3f54716cc0294d6a6743f373fdb058f8a03c69f3
[aversive.git] / strat.c
1 /*  
2  *  Copyright Droids, Microb Technology (2009)
3  * 
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  *  Revision : $Id: strat.c,v 1.6 2009-11-08 17:24:33 zer0 Exp $
19  *
20  *  Olivier MATZ <zer0@droids-corp.org> 
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <math.h>
27
28 #include <aversive/pgmspace.h>
29 #include <aversive/queue.h>
30 #include <aversive/wait.h>
31 #include <aversive/error.h>
32
33 #include <ax12.h>
34 #include <uart.h>
35 #include <pwm_ng.h>
36 #include <time.h>
37 #include <spi.h>
38
39 #include <pid.h>
40 #include <quadramp.h>
41 #include <control_system_manager.h>
42 #include <trajectory_manager.h>
43 #include <vect_base.h>
44 #include <lines.h>
45 #include <polygon.h>
46 #include <obstacle_avoidance.h>
47 #include <blocking_detection_manager.h>
48 #include <robot_system.h>
49 #include <position_manager.h>
50
51 #include <diagnostic.h>
52
53 #include <rdline.h>
54 #include <parse.h>
55
56 #include "../common/i2c_commands.h"
57 #include "i2c_protocol.h"
58 #include "main.h"
59 #include "strat.h"
60 #include "strat_base.h"
61 #include "strat_utils.h"
62 #include "sensor.h"
63 #include "actuator.h"
64
65 #define COL_DISP_MARGIN 400 /* stop 40 cm in front of dispenser */
66 #define COL_SCAN_PRE_MARGIN 250
67
68
69 #ifdef TEST_BEACON
70
71 #define BEACON_MAX_SAMPLES 100
72 struct beacon_sample {
73         int16_t posx;
74         int16_t posy;
75         int16_t posa;
76         int16_t oppx;
77         int16_t oppy;
78         uint8_t time;
79 };
80
81 static struct beacon_sample beacon_sample[BEACON_MAX_SAMPLES];
82 static uint8_t beacon_prev_time = 0;
83 static uint8_t beacon_cur_idx = 0;
84
85 static void beacon_update_samples(void)
86 {
87         int16_t opp_a, opp_d, opp_x, opp_y;
88         int8_t err;
89         uint8_t time;
90
91         time = time_get_s();
92
93         /* one sample per second max */
94         if (time <= beacon_prev_time)
95                 return;
96         /* limit max number of samples */
97         if (beacon_cur_idx >= BEACON_MAX_SAMPLES)
98                 return;
99
100         memset(&beacon_sample[beacon_cur_idx], 0, sizeof(beacon_sample[beacon_cur_idx]));
101         beacon_prev_time = time;
102         beacon_sample[beacon_cur_idx].time = time;
103         
104         /* get opponent pos; if not found, just set struct to 0 */
105         err = get_opponent_xyda(&opp_x, &opp_y, &opp_d, &opp_a);
106         if (err == -1)
107                 return;
108
109         beacon_sample[beacon_cur_idx].posx = position_get_x_s16(&mainboard.pos);
110         beacon_sample[beacon_cur_idx].posy = position_get_y_s16(&mainboard.pos);
111         beacon_sample[beacon_cur_idx].posa = position_get_a_deg_s16(&mainboard.pos);
112         beacon_sample[beacon_cur_idx].oppx = opp_x;
113         beacon_sample[beacon_cur_idx].oppy = opp_y;
114         beacon_cur_idx++;
115 }
116
117 void beacon_dump_samples(void)
118 {
119         uint16_t i;
120
121         for (i=0; i<BEACON_MAX_SAMPLES; i++) {
122                 printf_P(PSTR("%d: pos=(%d,%d,%d) opp=(%d,%d) time=%d\r\n"),
123                          i,
124                          beacon_sample[i].posx,
125                          beacon_sample[i].posy,
126                          beacon_sample[i].posa,
127                          beacon_sample[i].oppx,
128                          beacon_sample[i].oppy,
129                          beacon_sample[i].time);
130         }
131 }
132 #endif
133
134 struct strat_infos strat_infos = {
135         /* conf */
136         .conf = {
137                 .flags = 0,
138                 /* scanner disabled by default */
139                 .scan_opp_min_time = 90,
140                 .delay_between_opp_scan = 90,
141                 .scan_our_min_time = 90,
142                 .delay_between_our_scan = 90,
143                 .wait_opponent = 0,
144                 .lintel_min_time = 0,
145                 .scan_opp_angle = -1,
146         },
147
148         /* static columns */
149         .s_cols = { 
150                 .flags = 0, 
151                 .configuration = 0,
152         },
153
154         /* column dispensers ; be carreful, positions are
155          * color-dependent, so COLOR_Y() and COLOR_A() should be
156          * used. All angles here are _absolute_ */
157         .c1 = {
158                 .checkpoint_x = 2711 - COL_SCAN_PRE_MARGIN,
159                 .checkpoint_y = AREA_Y - COL_DISP_MARGIN,
160                 .scan_left = 0,
161                 .scan_a = 180,
162                 .eject_a = 180,
163                 .recalib_x = 2711,
164                 .recalib_y = AREA_Y - (ROBOT_LENGTH/2 + DIST_BACK_DISPENSER),
165                 .pickup_a = 90,
166                 .name = "col_disp1",
167         },
168         .c2 = {
169                 .checkpoint_x = AREA_X - COL_DISP_MARGIN,
170                 .checkpoint_y = 800 - COL_SCAN_PRE_MARGIN,
171                 .scan_left = 1,
172                 .scan_a = -90,
173                 .eject_a = -90,
174                 .recalib_x = AREA_X - (ROBOT_LENGTH/2 + DIST_BACK_DISPENSER),
175                 .recalib_y = 800,
176                 .pickup_a = 0,
177                 .name = "col_disp2",
178         },
179         .c3 = {
180                 .checkpoint_x = AREA_X-COL_DISP_MARGIN,
181                 .checkpoint_y = 1300 + COL_SCAN_PRE_MARGIN,
182                 .scan_a = 90,
183                 .scan_left = 0,
184                 .eject_a = -90,
185                 .recalib_x = AREA_X - (ROBOT_LENGTH/2 + DIST_BACK_DISPENSER),
186                 .recalib_y = 1300,
187                 .pickup_a = 0,
188                 .name = "col_disp3",
189         },
190         
191         /* lintel dispensers */
192         .l1 = {
193                 .x = 912, /* XXX for red only */
194                 .name = "lin_disp1",
195         },
196         .l2 = {
197                 .x = 1312,  /* XXX for red only */
198                 .name = "lin_disp2",
199         },
200
201         /* build zones */
202         .zone_list = {
203 #define ZONE_DISC_NUM 0
204                 {
205                         .flags = ZONE_F_VALID | ZONE_F_DISC,
206                         .level = 2,
207                         .checkpoint_x = 0,
208                         .checkpoint_x = 0,
209                         .name = "disc",
210                 },
211 #define ZONE_1A_NUM 1
212                 {
213                         .flags = ZONE_F_VALID,
214                         .level = 1,
215                         .checkpoint_x = 1385,
216                         .checkpoint_y = 1700,
217                         .name = "z1a",
218                 },
219 #define ZONE_1B_NUM 2
220                 {
221                         .flags = ZONE_F_VALID,
222                         .level = 1,
223                         .checkpoint_x = 1615,
224                         .checkpoint_y = 1700,
225                         .name = "z1b",
226                 },
227 #define ZONE_0B_NUM 3
228                 {
229                         .flags = ZONE_F_VALID,
230                         .level = 0,
231                         .checkpoint_x = 2100,
232                         .checkpoint_y = 1700,
233                         .name = "z0b",
234                 },
235 #define ZONE_0A_NUM 4
236                 {
237                         .flags = ZONE_F_VALID,
238                         .level = 0,
239                         .checkpoint_x = 900,
240                         .checkpoint_y = 1700,
241                         .name = "z0a",
242                 },
243         }
244 };
245
246 /*************************************************************/
247
248 /*                  INIT                                     */
249
250 /*************************************************************/
251
252 void strat_set_bounding_box(void)
253 {
254         if (get_color() == I2C_COLOR_RED) {
255                 strat_infos.area_bbox.x1 = 300;
256                 strat_infos.area_bbox.y1 = 200;
257                 strat_infos.area_bbox.x2 = 2720; /* needed for c1 */
258                 strat_infos.area_bbox.y2 = 1800;
259         }
260         else {
261                 strat_infos.area_bbox.x1 = 200;
262                 strat_infos.area_bbox.y1 = 300;
263                 strat_infos.area_bbox.x2 = 2720; /* needed for c1 */
264                 strat_infos.area_bbox.y2 = 1900;
265         }
266
267         polygon_set_boundingbox(strat_infos.area_bbox.x1,
268                                 strat_infos.area_bbox.y1,
269                                 strat_infos.area_bbox.x2,
270                                 strat_infos.area_bbox.y2);
271 }
272
273 /* called before each strat, and before the start switch */
274 void strat_preinit(void)
275 {
276         time_reset();
277         interrupt_traj_reset();
278         mainboard.flags =  DO_ENCODERS | DO_CS | DO_RS |
279                 DO_POS | DO_BD | DO_POWER;
280
281         i2c_mechboard_mode_init();
282         if (get_color() == I2C_COLOR_RED)
283                 i2c_mechboard_mode_prepare_pickup(I2C_LEFT_SIDE);
284         else
285                 i2c_mechboard_mode_prepare_pickup(I2C_RIGHT_SIDE);
286
287         strat_dump_conf();
288         strat_dump_infos(__FUNCTION__);
289 }
290
291 void strat_dump_conf(void)
292 {
293         if (!strat_infos.dump_enabled)
294                 return;
295
296         printf_P(PSTR("-- conf --\r\n"));
297
298         printf_P(PSTR("  one build on disc: "));
299         if (strat_infos.conf.flags & STRAT_CONF_ONLY_ONE_ON_DISC)
300                 printf_P(PSTR("on\r\n"));
301         else
302                 printf_P(PSTR("off\r\n"));
303
304         printf_P(PSTR("  bypass static2: "));
305         if (strat_infos.conf.flags & STRAT_CONF_BYPASS_STATIC2)
306                 printf_P(PSTR("on\r\n"));
307         else
308                 printf_P(PSTR("off\r\n"));
309
310         printf_P(PSTR("  take one lintel: "));
311         if (strat_infos.conf.flags & STRAT_CONF_TAKE_ONE_LINTEL)
312                 printf_P(PSTR("on\r\n"));
313         else
314                 printf_P(PSTR("off\r\n"));
315
316         printf_P(PSTR("  skip this temple when temple check fails: "));
317         if (strat_infos.conf.flags & STRAT_CONF_SKIP_WHEN_CHECK_FAILS)
318                 printf_P(PSTR("on\r\n"));
319         else
320                 printf_P(PSTR("off\r\n"));
321
322         printf_P(PSTR("  store static2: "));
323         if (strat_infos.conf.flags & STRAT_CONF_STORE_STATIC2)
324                 printf_P(PSTR("on\r\n"));
325         else
326                 printf_P(PSTR("off\r\n"));
327
328         printf_P(PSTR("  (big3) try to build a temple with 3 lintels: "));
329         if (strat_infos.conf.flags & STRAT_CONF_BIG_3_TEMPLE)
330                 printf_P(PSTR("on\r\n"));
331         else
332                 printf_P(PSTR("off\r\n"));
333
334         printf_P(PSTR("  early opponent scan: "));
335         if (strat_infos.conf.flags & STRAT_CONF_EARLY_SCAN)
336                 printf_P(PSTR("on\r\n"));
337         else
338                 printf_P(PSTR("off\r\n"));
339
340         printf_P(PSTR("  push opponent columns: "));
341         if (strat_infos.conf.flags & STRAT_CONF_PUSH_OPP_COLS)
342                 printf_P(PSTR("on\r\n"));
343         else
344                 printf_P(PSTR("off\r\n"));
345
346         printf_P(PSTR("  scan opponent min time: %d\r\n"),
347                  strat_infos.conf.scan_opp_min_time);
348         printf_P(PSTR("  delay between oppnent scan: %d\r\n"),
349                  strat_infos.conf.delay_between_opp_scan);
350         printf_P(PSTR("  scan our min time: %d\r\n"),
351                  strat_infos.conf.scan_our_min_time);
352         printf_P(PSTR("  delay between our scan: %d\r\n"),
353                  strat_infos.conf.delay_between_our_scan);
354         printf_P(PSTR("  wait opponent gone before scan: %d\r\n"),
355                  strat_infos.conf.wait_opponent);
356         printf_P(PSTR("  lintel min time: %d\r\n"),
357                  strat_infos.conf.lintel_min_time);
358         printf_P(PSTR("  scan_opp_angle: %d\r\n"),
359                  strat_infos.conf.scan_opp_angle);
360 }
361
362 void strat_dump_temple(struct temple *temple)
363 {
364         if (!strat_infos.dump_enabled)
365                 return;
366
367         printf_P(PSTR("  temple %p (%s): "), temple, temple->zone->name);
368
369         if (temple->flags & TEMPLE_F_MONOCOL)
370                 printf_P(PSTR("MONOCOL "));
371         else
372                 printf_P(PSTR("BICOL "));
373
374         if (temple->flags & TEMPLE_F_ON_DISC)
375                 printf_P(PSTR("ON_DISC "));
376         else
377                 printf_P(PSTR("ON_ZONE_0_1 "));
378         
379         if (temple->flags & TEMPLE_F_OPPONENT)
380                 printf_P(PSTR("OPPONENT "));
381         else
382                 printf_P(PSTR("OURS "));
383
384         if (temple->flags & TEMPLE_F_LINTEL)
385                 printf_P(PSTR("LIN_ON_TOP "));
386         else
387                 printf_P(PSTR("COL_ON_TOP "));
388
389         printf_P(PSTR("\r\n"));
390
391         printf_P(PSTR("   pos=(%d,%d,%d) ckpt=(%d,%d) ltime=%d\r\n"),
392                  temple->x, temple->y, temple->a,
393                  temple->checkpoint_x, temple->checkpoint_y,
394                  temple->last_try_time);
395         printf_P(PSTR("   L: lev=%d da=%d,%d\r\n"),
396                  temple->level_l, temple->dist_l, temple->angle_l);
397         printf_P(PSTR("   R: lev=%d da=%d,%d\r\n"),
398                  temple->level_l, temple->dist_l, temple->angle_l);
399 }
400
401 void strat_dump_zone(struct build_zone *zone)
402 {
403         if (!strat_infos.dump_enabled)
404                 return;
405
406         printf_P(PSTR("  zone %s: "), zone->name);
407
408         if (zone->flags & ZONE_F_DISC)
409                 printf_P(PSTR("DISC "));
410         else if (zone->flags & ZONE_F_ZONE1)
411                 printf_P(PSTR("ZONE1 "));
412         else if (zone->flags & ZONE_F_ZONE0)
413                 printf_P(PSTR("ZONE0 "));
414
415         if (zone->flags & ZONE_F_BUSY)
416                 printf_P(PSTR("BUSY "));
417         else
418                 printf_P(PSTR("FREE "));
419         
420         printf_P(PSTR("\r\n"));
421
422         printf_P(PSTR("    lev=%d ckpt=(%d,%d) ltime=%d\r\n"),
423                  zone->level,
424                  zone->checkpoint_x, zone->checkpoint_y,
425                  zone->last_try_time);
426 }
427
428 void strat_dump_static_cols(void)
429 {
430         if (!strat_infos.dump_enabled)
431                 return;
432
433         printf_P(PSTR("  static cols: l0=%d l1=%d l2=%d\r\n"),
434                  strat_infos.s_cols.flags & STATIC_COL_LINE0_DONE,
435                  strat_infos.s_cols.flags & STATIC_COL_LINE1_DONE,
436                  strat_infos.s_cols.flags & STATIC_COL_LINE2_DONE);
437 }
438
439 void strat_dump_col_disp(void)
440 {
441         if (!strat_infos.dump_enabled)
442                 return;
443
444         printf_P(PSTR("  c1 cnt=%d ltt=%d\r\n"),
445                  strat_infos.c1.count, strat_infos.c1.last_try_time);
446         printf_P(PSTR("  c2 cnt=%d ltt=%d\r\n"),
447                  strat_infos.c2.count, strat_infos.c2.last_try_time);
448         printf_P(PSTR("  c3 cnt=%d ltt=%d\r\n"),
449                  strat_infos.c3.count, strat_infos.c3.last_try_time);
450 }
451
452 void strat_dump_lin_disp(void)
453 {
454         if (!strat_infos.dump_enabled)
455                 return;
456         printf_P(PSTR("  l1 cnt=%d ltt=%d\r\n"),
457                  strat_infos.l1.count, strat_infos.l1.last_try_time);
458         printf_P(PSTR("  l2 cnt=%d ltt=%d\r\n"),
459                  strat_infos.l2.count, strat_infos.l2.last_try_time);
460
461 }
462
463 void strat_dump_all_temples(void)
464 {
465         struct temple *temple;
466         uint8_t i;
467
468         if (!strat_infos.dump_enabled)
469                 return;
470
471         for (i=0; i<MAX_TEMPLE; i++) {
472                 temple = &strat_infos.temple_list[i];
473                 if (!(temple->flags & TEMPLE_F_VALID))
474                         continue;
475                 strat_dump_temple(temple);
476         }
477 }
478
479 void strat_dump_all_zones(void)
480 {
481         struct build_zone *zone;
482         uint8_t i;
483
484         if (!strat_infos.dump_enabled)
485                 return;
486
487         for (i=0; i<MAX_ZONE; i++) {
488                 zone = &strat_infos.zone_list[i];
489                 if (!(zone->flags & ZONE_F_VALID))
490                         continue;
491                 strat_dump_zone(zone);
492         }
493 }
494
495 /* display current information about the state of the game */
496 void strat_dump_infos(const char *caller)
497 {
498         if (!strat_infos.dump_enabled)
499                 return;
500
501         printf_P(PSTR("%s() dump strat infos:\r\n"), caller);
502         strat_dump_static_cols();
503         strat_dump_col_disp();
504         strat_dump_lin_disp();
505         strat_dump_all_temples();
506         strat_dump_all_zones();
507 }
508
509 /* init current area state before a match. Dump update user conf
510  * here */
511 void strat_reset_infos(void)
512 {
513         uint8_t i;
514
515         /* /!\ don't do a big memset() as there is static data */
516         strat_infos.s_cols.flags = 0;
517         strat_infos.c1.count = 5;
518         strat_infos.c1.last_try_time = 0;
519         strat_infos.c2.count = 5;
520         strat_infos.c2.last_try_time = 0;
521         strat_infos.c3.count = 5;
522         strat_infos.c3.last_try_time = 0;
523         strat_infos.l1.count = 1;
524         strat_infos.l1.last_try_time = 0;
525         strat_infos.l2.count = 1;
526         strat_infos.l2.last_try_time = 0;
527
528         strat_infos.taken_lintel = 0;
529         strat_infos.col_in_boobs = 0;
530         strat_infos.lazy_pickup_done = 0;
531         strat_infos.i2c_loaded_skipped = 0;
532         
533         memset(strat_infos.temple_list, 0, sizeof(strat_infos.temple_list));
534
535         for (i=0; i<MAX_ZONE; i++)
536                 strat_infos.zone_list[i].flags = ZONE_F_VALID;
537         strat_infos.zone_list[ZONE_DISC_NUM].flags |= ZONE_F_DISC;
538         strat_infos.zone_list[ZONE_1A_NUM].flags |= ZONE_F_ZONE1;
539         strat_infos.zone_list[ZONE_1B_NUM].flags |= ZONE_F_ZONE1;
540         strat_infos.zone_list[ZONE_0A_NUM].flags |= ZONE_F_ZONE0;
541         strat_infos.zone_list[ZONE_0B_NUM].flags |= ZONE_F_ZONE0;
542
543         strat_set_bounding_box();
544
545         /* set lintel position, depending on color */
546         if (mainboard.our_color == I2C_COLOR_RED) {
547                 strat_infos.l1.x = 912;
548                 strat_infos.l2.x = 1312;
549         }
550         else {
551                 strat_infos.l1.x = 888;
552                 strat_infos.l2.x = 1288;
553         }
554 }
555
556 /* call it just before launching the strat */
557 void strat_init(void)
558 {
559         pickup_wheels_on();
560         strat_reset_infos();
561
562         /* we consider that the color is correctly set */
563
564         strat_set_speed(SPEED_DIST_FAST, SPEED_ANGLE_FAST);
565         time_reset();
566         interrupt_traj_reset();
567
568         /* used in strat_base for END_TIMER */
569         mainboard.flags = DO_ENCODERS | DO_CS | DO_RS | 
570                 DO_POS | DO_BD | DO_TIMER | DO_POWER;
571
572 #ifdef TEST_BEACON
573         beacon_prev_time = 0;
574         beacon_cur_idx = 0;
575 #endif
576 }
577
578
579 /* call it after each strat */
580 void strat_exit(void)
581 {
582         uint8_t flags;
583
584         pickup_wheels_off();
585         mainboard.flags &= ~(DO_TIMER);
586         strat_hardstop();
587         time_reset();
588         wait_ms(1000);
589         IRQ_LOCK(flags);
590         mainboard.flags &= ~(DO_CS);
591         pwm_ng_set(LEFT_PWM, 0);
592         pwm_ng_set(RIGHT_PWM, 0);
593         IRQ_UNLOCK(flags);
594 }
595
596 /* called periodically */
597 void strat_event(void *dummy)
598 {
599         /* limit speed when opponent is close */
600         strat_limit_speed();
601
602 #ifdef TEST_BEACON
603         beacon_update_samples();
604 #endif
605 }
606
607 /* do static cols + first temples */
608 static uint8_t strat_beginning(void)
609 {
610         uint8_t err;
611
612         /* don't limit the speed when opponent is near: it can change
613          * the radius of the curves */
614         strat_limit_speed_disable();
615
616         err = strat_static_columns(0);
617
618         strat_limit_speed_enable();
619
620         if (!TRAJ_SUCCESS(err))
621                 return err;
622
623         /* go to disc to build the first temple */
624
625         /* XXX if opponent is near disc, go to zone1 */
626         err = strat_goto_disc(2);
627         if (!TRAJ_SUCCESS(err))
628                 return err;
629         DEBUG(E_USER_STRAT, "disc reached");
630
631         /* can return END_ERROR or END_TIMER, should not happen
632          * here */
633         err = strat_build_new_temple(&strat_infos.zone_list[0]);
634         if (!TRAJ_SUCCESS(err))
635                 return err;
636
637         /* bypass static2 if specified */
638         if (strat_infos.conf.flags & STRAT_CONF_BYPASS_STATIC2) {
639                 err = strat_escape(&strat_infos.zone_list[0], TRAJ_FLAGS_STD);
640                 return err;
641         }
642
643         /* get the last 2 columns, and build them on previous temple */
644         err = strat_static_columns_pass2();
645         if (!TRAJ_SUCCESS(err))
646                 return err;
647
648         /* early opponent scan, for offensive strategy */
649         if (strat_infos.conf.flags & STRAT_CONF_EARLY_SCAN) {
650                 err = strat_pickup_lintels();
651                 /* ignore code */
652
653                 /* try to build on opponent (scan must be enabled) */
654                 err = strat_build_on_opponent_temple();
655                 /* ignore code */
656         }
657
658         return err;
659 }
660
661 /* return true if we need to grab some more elements (lintel/cols) */
662 uint8_t need_more_elements(void)
663 {
664         if (time_get_s() <= 75) {
665                 /* we have at least one col on each arm, build now */
666                 if ((get_column_count_left() >= 1) && 
667                     (get_column_count_right() >= 1))
668                         return 0;
669         }
670         else {
671                 if (get_column_count())
672                         return 0;
673         }
674         return 1;
675 }
676
677 /* dump state (every 5 s max) */
678 #define DUMP_RATE_LIMIT(dump, last_print)               \
679         do {                                            \
680                 if (time_get_s() - last_print > 5) {    \
681                         dump();                         \
682                         last_print = time_get_s();      \
683                 }                                       \
684         } while (0)
685
686
687 uint8_t strat_main(void)
688 {
689         uint8_t err;
690         struct temple *temple = NULL;
691         struct build_zone *zone = NULL;
692
693         uint8_t last_print_cols = 0;
694         uint8_t last_print_lin = 0;
695         uint8_t last_print_temple = 0;
696         uint8_t last_print_zone = 0;
697
698         /* do static cols + first temple */
699         err = strat_beginning();
700
701         /* skip error code */
702
703         while (1) {
704                 
705                 if (err == END_TIMER) {
706                         DEBUG(E_USER_STRAT, "End of time");
707                         strat_exit();
708                         break;
709                 }
710
711                 /* we have at least one col on each arm, build now */
712                 if (need_more_elements() == 0) {
713                         
714                         /* try to build on opponent, will return
715                          * END_TRAJ without doing anything if
716                          * disabled */
717                         err = strat_build_on_opponent_temple();
718                         if (!TRAJ_SUCCESS(err))
719                                 continue;
720                         if (need_more_elements())
721                                 continue;
722
723                         /* try to scan and build on our temple, will
724                          * return END_TRAJ without doing anything if
725                          * disabled */
726                         err = strat_check_temple_and_build();
727                         if (!TRAJ_SUCCESS(err))
728                                 continue;
729                         if (need_more_elements())
730                                 continue;
731
732                         /* Else, do a simple build, as before */
733
734                         temple = strat_get_best_temple();
735
736                         /* one valid temple found */
737                         if (temple) {
738                                 DUMP_RATE_LIMIT(strat_dump_all_temples, last_print_temple);
739
740                                 err = strat_goto_temple(temple);
741                                 if (!TRAJ_SUCCESS(err))
742                                         continue;
743
744                                 /* can return END_ERROR or END_TIMER,
745                                  * should not happen here */
746                                 err = strat_grow_temple(temple);
747                                 if (!TRAJ_SUCCESS(err))
748                                         continue;
749                                 
750                                 err = strat_escape(temple->zone, TRAJ_FLAGS_STD);
751                                 if (!TRAJ_SUCCESS(err))
752                                         continue;
753
754                                 continue;
755                         }
756
757                         zone = strat_get_best_zone();
758                         if (zone) {
759                                 DUMP_RATE_LIMIT(strat_dump_all_zones, last_print_zone);
760
761                                 DEBUG(E_USER_STRAT, "goto zone %s", zone->name);
762                                 err = strat_goto_build_zone(zone, zone->level);
763                                 if (!TRAJ_SUCCESS(err))
764                                         continue;
765                                 DEBUG(E_USER_STRAT, "zone reached");
766                                 
767                                 /* no error code except END_ERROR, should not happen */
768                                 err = strat_build_new_temple(zone);
769
770                                 err = strat_escape(zone, TRAJ_FLAGS_STD);
771                                 if (!TRAJ_SUCCESS(err))
772                                         continue;
773
774                                 continue;
775                         }
776
777                         /* XXX hey what can we do here... :'( */
778                         DEBUG(E_USER_STRAT, "panic :)");
779                         time_wait_ms(1000);
780                         continue;
781                 }
782
783                 /* else we need some elements (lintels, then columns) */
784                 else {
785                         if (strat_infos.l1.count != 0 && strat_infos.l2.count != 0)
786                                 DUMP_RATE_LIMIT(strat_dump_lin_disp, last_print_lin);
787
788                         err = strat_pickup_lintels();
789                          /* can return an error code, but we have
790                           * nothing to do because pickup_column()
791                           * starts with a goto_and_avoid() */
792                         if (!TRAJ_SUCCESS(err))
793                                 nop();
794                         
795                         DUMP_RATE_LIMIT(strat_dump_col_disp, last_print_cols);
796
797                         err = strat_pickup_columns();
798                         if (!TRAJ_SUCCESS(err))
799                                 nop(); /* nothing to do */
800
801                         /* XXX check here that we have elements, or do
802                          * something else */
803                         /* if we cannot take elements, try to build */
804                 }
805         }
806         return END_TRAJ;
807 }