5211c4f162c0d6421b01b861ed5572b7c1877bbb
[aversive.git] / projects / microb2010 / mainboard / strat_avoid.c
1 /*
2  *  Copyright Droids, Microb Technology (2010)
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
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdint.h>
27 #include <math.h>
28
29 #include <aversive.h>
30 #include <aversive/pgmspace.h>
31 #include <aversive/error.h>
32
33 #include <ax12.h>
34 #include <uart.h>
35 #include <pwm_ng.h>
36 #include <clock_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 <trajectory_manager_utils.h>
44 #include <trajectory_manager_core.h>
45 #include <vect_base.h>
46 #include <lines.h>
47 #include <polygon.h>
48 #include <obstacle_avoidance.h>
49 #include <blocking_detection_manager.h>
50 #include <robot_system.h>
51 #include <position_manager.h>
52
53 #include <diagnostic.h>
54
55 #include <rdline.h>
56 #include <parse.h>
57
58 #include "../common/i2c_commands.h"
59 #include "i2c_protocol.h"
60 #include "main.h"
61 #include "strat.h"
62 #include "strat_db.h"
63 #include "strat_base.h"
64 #include "strat_corn.h"
65 #include "strat_avoid.h"
66 #include "strat_utils.h"
67 #include "sensor.h"
68 #include "actuator.h"
69
70 //#define VERBOSE
71
72 #ifdef VERBOSE
73 #define DPR(fmt, ...) printf_P(PSTR(fmt), ##__VA_ARGS__)
74 #else
75 #define DPR(args...) do {} while (0)
76 #endif
77
78 struct circuit {
79         const char *name;
80         uint8_t len;
81         const struct wp_coord *path;
82 };
83
84 const struct wp_coord butterfly_tab[] = {
85         { .i = 11, .j = 6, },
86         { .i = 10, .j = 6, },
87         { .i = 9, .j = 5, },
88         { .i = 8, .j = 5, },
89         { .i = 7, .j = 4, },
90         { .i = 6, .j = 4, },
91         { .i = 5, .j = 3, },
92         { .i = 4, .j = 3, },
93         { .i = 3, .j = 2, },
94         { .i = 2, .j = 2, },
95         { .i = 1, .j = 1, },
96         { .i = 1, .j = 2, },
97         { .i = 1, .j = 3, },
98         { .i = 1, .j = 4, },
99         { .i = 1, .j = 5, },
100         { .i = 1, .j = 6, },
101         { .i = 2, .j = 6, },
102         { .i = 3, .j = 5, },
103         { .i = 4, .j = 5, },
104         { .i = 5, .j = 4, },
105         { .i = 6, .j = 4, },
106         { .i = 7, .j = 3, },
107         { .i = 8, .j = 3, },
108         { .i = 9, .j = 2, },
109         { .i = 10, .j = 2, },
110         { .i = 11, .j = 1, },
111         { .i = 11, .j = 2, },
112         { .i = 11, .j = 3, },
113         { .i = 11, .j = 4, },
114         { .i = 11, .j = 5, },
115         { .i = 11, .j = 6, },
116 };
117
118 const struct circuit butterfly_circuit = {
119         .name = "butterfly",
120         .len = sizeof(butterfly_tab)/sizeof(struct wp_coord),
121         .path = butterfly_tab,
122 };
123
124 const struct wp_coord losange_tab[] = {
125         { .i = 11, .j = 6, },
126         { .i = 10, .j = 6, },
127         { .i = 9, .j = 5, },
128         { .i = 9, .j = 4, },
129         { .i = 9, .j = 3, },
130         { .i = 10, .j = 4, },
131         { .i = 11, .j = 4, },
132         { .i = 11, .j = 5, },
133         { .i = 11, .j = 6, },
134 };
135
136 const struct circuit losange_circuit = {
137         .name = "losange",
138         .len = sizeof(losange_tab)/sizeof(struct wp_coord),
139         .path = losange_tab,
140 };
141
142 const struct wp_coord triangle_tab[] = {
143         { .i = 11, .j = 6, },
144         { .i = 10, .j = 6, },
145         { .i = 9, .j = 5, },
146         { .i = 8, .j = 5, },
147         { .i = 7, .j = 4, },
148         { .i = 6, .j = 4, },
149         { .i = 7, .j = 3, },
150         { .i = 8, .j = 3, },
151         { .i = 9, .j = 2, },
152         { .i = 10, .j = 2, },
153         { .i = 11, .j = 1, },
154         { .i = 11, .j = 2, },
155         { .i = 11, .j = 3, },
156         { .i = 11, .j = 4, },
157         { .i = 11, .j = 5, },
158         { .i = 11, .j = 6, },
159 };
160
161 const struct circuit triangle_circuit = {
162         .name = "triangle",
163         .len = sizeof(triangle_tab)/sizeof(struct wp_coord),
164         .path = triangle_tab,
165 };
166
167 const struct wp_coord answer_d_tab[] = {
168         { .i = 11, .j = 6, },
169         { .i = 11, .j = 5, },
170         { .i = 11, .j = 4, },
171         { .i = 11, .j = 3, },
172         { .i = 11, .j = 2, },
173         { .i = 11, .j = 1, },
174         { .i = 10, .j = 2, },
175         { .i = 9, .j = 2, },
176         { .i = 8, .j = 3, },
177         { .i = 9, .j = 3, },
178         { .i = 10, .j = 4, },
179         { .i = 11, .j = 4, },
180         { .i = 11, .j = 5, },
181         { .i = 11, .j = 6, },
182 };
183
184 const struct circuit answer_d_circuit = {
185         .name = "answer_d",
186         .len = sizeof(answer_d_tab)/sizeof(struct wp_coord),
187         .path = answer_d_tab,
188 };
189
190 const struct wp_coord h_lambda_tab[] = {
191         { .i = 11, .j = 6, },
192         { .i = 10, .j = 6, },
193         { .i = 9, .j = 5, },
194         { .i = 8, .j = 5, },
195         { .i = 7, .j = 4, },
196         { .i = 6, .j = 4, },
197         { .i = 5, .j = 3, },
198         { .i = 5, .j = 4, },
199         { .i = 5, .j = 5, },
200         { .i = 5, .j = 6, },
201         { .i = 6, .j = 6, },
202         { .i = 7, .j = 5, },
203         { .i = 8, .j = 5, },
204         { .i = 9, .j = 5, },
205         { .i = 10, .j = 6, },
206         { .i = 11, .j = 6, },
207 };
208
209 const struct circuit h_lambda_circuit = {
210         .name = "h_lambda",
211         .len = sizeof(h_lambda_tab)/sizeof(struct wp_coord),
212         .path = h_lambda_tab,
213 };
214
215 const struct wp_coord asym_butterfly_tab[] = {
216         { .i = 11, .j = 6, },
217         { .i = 10, .j = 6, },
218         { .i = 9, .j = 5, },
219         { .i = 8, .j = 5, },
220         { .i = 7, .j = 4, },
221         { .i = 6, .j = 4, },
222         { .i = 5, .j = 3, },
223         { .i = 4, .j = 3, },
224         { .i = 3, .j = 2, },
225         { .i = 3, .j = 3, },
226         { .i = 3, .j = 4, },
227         { .i = 3, .j = 5, },
228         { .i = 4, .j = 5, },
229         { .i = 5, .j = 4, },
230         { .i = 6, .j = 4, },
231         { .i = 7, .j = 3, },
232         { .i = 8, .j = 3, },
233         { .i = 9, .j = 2, },
234         { .i = 10, .j = 2, },
235         { .i = 11, .j = 1, },
236         { .i = 11, .j = 2, },
237         { .i = 11, .j = 3, },
238         { .i = 11, .j = 4, },
239         { .i = 11, .j = 5, },
240         { .i = 11, .j = 6, },
241 };
242
243 const struct circuit asym_butterfly_circuit = {
244         .name = "asym_butterfly",
245         .len = sizeof(asym_butterfly_tab)/sizeof(struct wp_coord),
246         .path = asym_butterfly_tab,
247 };
248
249 const struct wp_coord big_h_lambda_tab[] = {
250         { .i = 11, .j = 6, },
251         { .i = 10, .j = 6, },
252         { .i = 9, .j = 5, },
253         { .i = 8, .j = 5, },
254         { .i = 7, .j = 4, },
255         { .i = 6, .j = 4, },
256         { .i = 5, .j = 4, },
257         { .i = 4, .j = 5, },
258         { .i = 3, .j = 5, },
259         { .i = 2, .j = 6, },
260         { .i = 1, .j = 6, },
261         { .i = 1, .j = 5, },
262         { .i = 1, .j = 4, },
263         { .i = 1, .j = 3, },
264         { .i = 1, .j = 2, },
265         { .i = 1, .j = 1, },
266         { .i = 2, .j = 2, },
267         { .i = 3, .j = 2, },
268         { .i = 4, .j = 3, },
269         { .i = 5, .j = 3, },
270         { .i = 6, .j = 4, },
271         { .i = 7, .j = 4, },
272         { .i = 8, .j = 5, },
273         { .i = 9, .j = 5, },
274         { .i = 10, .j = 6, },
275         { .i = 11, .j = 6, },
276 };
277
278 const struct circuit big_h_lambda_circuit = {
279         .name = "big_h_lambda",
280         .len = sizeof(big_h_lambda_tab)/sizeof(struct wp_coord),
281         .path = big_h_lambda_tab,
282 };
283
284 const struct wp_coord letter_v_tab[] = {
285         { .i = 11, .j = 6, },
286         { .i = 10, .j = 6, },
287         { .i = 9, .j = 5, },
288         { .i = 8, .j = 5, },
289         { .i = 7, .j = 4, },
290         { .i = 6, .j = 4, },
291         { .i = 5, .j = 4, },
292         { .i = 4, .j = 5, },
293         { .i = 3, .j = 5, },
294         { .i = 2, .j = 6, },
295         { .i = 1, .j = 6, },
296         { .i = 1, .j = 5, },
297         { .i = 1, .j = 4, },
298         { .i = 2, .j = 4, },
299         { .i = 3, .j = 3, },
300         { .i = 4, .j = 3, },
301         { .i = 5, .j = 2, },
302         { .i = 6, .j = 2, },
303         { .i = 7, .j = 2, },
304         { .i = 8, .j = 3, },
305         { .i = 9, .j = 3, },
306         { .i = 10, .j = 4, },
307         { .i = 11, .j = 4, },
308         { .i = 11, .j = 5, },
309         { .i = 11, .j = 6, },
310 };
311
312 const struct circuit letter_v_circuit = {
313         .name = "letter_v",
314         .len = sizeof(letter_v_tab)/sizeof(struct wp_coord),
315         .path = letter_v_tab,
316 };
317
318 /* list of all possible circuits */
319 const struct circuit *circuits[] = {
320         &butterfly_circuit,
321         &losange_circuit,
322         &triangle_circuit,
323         &answer_d_circuit,
324         &h_lambda_circuit,
325         &asym_butterfly_circuit,
326         &big_h_lambda_circuit,
327         &letter_v_circuit,
328         NULL,
329 };
330
331 /* symetric neighbor position */
332 static inline uint8_t opposite_position(uint8_t pos)
333 {
334         pos += 3;
335         if (pos > LINE_L_UP)
336                 pos -= 6;
337         return pos;
338 }
339
340 #ifdef HOST_VERSION
341 //#define TEST_STRAT_AVOID
342 #endif
343
344 #ifdef TEST_STRAT_AVOID
345 static uint8_t cc;
346 uint8_t xget_cob_count(void)
347 {
348         return cc;
349 }
350
351 static uint8_t bc;
352 uint8_t xget_ball_count(void)
353 {
354         return bc;
355 }
356
357 static uint32_t ts;
358 uint8_t xtime_get_s(void)
359 {
360         return ts;
361 }
362 #else
363 #define xget_cob_count() get_cob_count()
364 #define xget_ball_count() get_ball_count()
365 #define xtime_get_s() time_get_s()
366 #endif
367
368 /* return true if turn is at 60 deg */
369 uint8_t is_60deg(uint8_t dir1, uint8_t dir2)
370 {
371         int8_t turn;
372
373         turn = dir2-dir1;
374         if (turn < 0)
375                 turn += 6;
376         if (turn == 1)
377                 return 1;
378         if (turn == 5)
379                 return 1;
380         return 0;
381 }
382
383 /* return true if turn is at 60 deg */
384 uint8_t is_120deg(uint8_t dir1, uint8_t dir2)
385 {
386         int8_t turn;
387
388         turn = dir2-dir1;
389         if (turn < 0)
390                 turn += 6;
391         if (turn == 2)
392                 return 1;
393         if (turn == 4)
394                 return 1;
395         return 0;
396 }
397
398 /* get the neighbour of the point at specified dir, return -1 if
399  * there is no neighbor */
400 int8_t wp_get_neigh(uint8_t i, uint8_t j, uint8_t *ni, uint8_t *nj,
401                  uint8_t dir)
402 {
403         switch (dir) {
404         case LINE_UP:
405                 j++;
406                 break;
407         case LINE_R_UP:
408                 if ((i & 1)) j++;
409                 i++;
410                 break;
411         case LINE_R_DOWN:
412                 if (!(i & 1)) j--;
413                 i++;
414                 break;
415         case LINE_DOWN:
416                 j--;
417                 break;
418         case LINE_L_DOWN:
419                 if (!(i & 1)) j--;
420                 i--;
421                 break;
422         case LINE_L_UP:
423                 if ((i & 1)) j++;
424                 i--;
425                 break;
426         default:
427                 return -1;
428         }
429         if (i >= WAYPOINTS_NBX || j >= WAYPOINTS_NBY)
430                 return -1;
431
432         *ni = i;
433         *nj = j;
434         return 0;
435 }
436
437 static uint8_t get_line_num(int8_t i, int8_t j, uint8_t dir)
438 {
439         switch (dir) {
440         case LINE_UP:
441         case LINE_DOWN:
442                 return i/2;
443         case LINE_R_UP:
444         case LINE_L_DOWN:
445                 i &= 0xfe;
446                 j -= i/2;
447                 return (5-j)/2;
448         case LINE_R_DOWN:
449         case LINE_L_UP:
450                 i &= 0xfe;
451                 j += i/2;
452                 return (11-j)/2;
453         default:
454                 return -1;
455         }
456 }
457
458 static uint8_t get_dir(uint8_t prev_i, uint8_t prev_j,
459                        uint8_t i, uint8_t j)
460 {
461         int8_t diff_i, diff_j;
462
463         diff_i = i - prev_i;
464         diff_j = j - prev_j;
465
466         if (diff_i == 0 && diff_j == 1)
467                 return LINE_UP;
468         if (diff_i == 0 && diff_j == -1)
469                 return LINE_DOWN;
470
471         if ((prev_i & 1) == 0) {
472                 if (diff_i == 1 && diff_j == 0)
473                         return LINE_R_UP;
474                 if (diff_i == 1 && diff_j == -1)
475                         return LINE_R_DOWN;
476                 if (diff_i == -1 && diff_j == 0)
477                         return LINE_L_UP;
478                 if (diff_i == -1 && diff_j == -1)
479                         return LINE_L_DOWN;
480         }
481         else {
482                 if (diff_i == 1 && diff_j == 1)
483                         return LINE_R_UP;
484                 if (diff_i == 1 && diff_j == 0)
485                         return LINE_R_DOWN;
486                 if (diff_i == -1 && diff_j == 1)
487                         return LINE_L_UP;
488                 if (diff_i == -1 && diff_j == 0)
489                         return LINE_L_DOWN;
490         }
491
492         /* invalid value */
493         return 0xFF;
494 }
495
496 /* return true if a waypoint belongs to a line */
497 uint8_t wp_belongs_to_line(uint8_t i, uint8_t j, uint8_t linenum, uint8_t dir)
498 {
499         uint8_t ln;
500         ln = get_line_num(i, j, dir);
501         if (ln == linenum)
502                 return 1;
503         return 0;
504 }
505
506 /* count the number of non-black corns which are neighbors of
507  * specified cob */
508 uint8_t corn_count_neigh(uint8_t i, uint8_t j)
509 {
510         uint8_t dir, n = 0;
511         uint8_t ni, nj;
512
513         for (dir = LINE_UP; dir <= LINE_R_UP; dir++) {
514                 if (wp_get_neigh(i, j, &ni, &nj, dir) < 0)
515                         continue;
516
517                 /* is there a corn cob ? */
518                 if (strat_db.wp_table[ni][nj].type == WP_TYPE_CORN &&
519                     strat_db.wp_table[ni][nj].present &&
520                     strat_db.wp_table[ni][nj].corn.color != I2C_COB_BLACK)
521                         n ++;
522         }
523
524         return n;
525 }
526
527
528 /* fill circuit_wpline table with waypoints from circuit starting at
529  * i,j and using selected face */
530 static int8_t get_path(const struct circuit *circuit,
531                        uint8_t starti, uint8_t startj, uint8_t faceA,
532                        struct wp_line *circuit_wpline)
533 {
534         const struct wp_coord *curcircuit;
535         const struct wp_coord *start;
536         const struct wp_coord *end;
537         uint8_t prev_i, prev_j;
538         uint8_t dir, prev_dir = 0xFF;
539         uint8_t found = 0, i = 0, j = 0;
540         uint8_t linenum;
541         int8_t step = faceA ? 1 : -1;
542         int8_t path_len = 0;
543
544         /* start and end of circuit */
545         if (faceA) {
546                 start = &circuit->path[0];
547                 end = start + circuit->len - 1;
548         }
549         else {
550                 end = &circuit->path[0];
551                 start = end + circuit->len - 1;
552         }
553
554         DPR("%s(): %s face=%d\r\n", __FUNCTION__, circuit->name, faceA);
555
556         /* check that the point is present in the circuit */
557         for (curcircuit = start; curcircuit != end; curcircuit += step) {
558                 if (curcircuit->i == starti && curcircuit->j == startj) {
559                         found = 1;
560                         break;
561                 }
562         }
563         if (found == 0)
564                 return -1;
565
566
567         /* browse the circuit from starti, startj in the specified
568          * direction, and fill the table when direction changes */
569         prev_i = starti;
570         prev_j = startj;
571         for ( ; curcircuit != end;
572               curcircuit += step, prev_dir = dir, prev_i = i, prev_j = j) {
573
574                 i = curcircuit->i;
575                 j = curcircuit->j;
576
577                 dir = get_dir(prev_i, prev_j, i, j);
578
579                 if (prev_dir != dir) {
580                         linenum = get_line_num(prev_i, prev_j, dir);
581                         circuit_wpline[path_len].line_num = linenum;
582                         circuit_wpline[path_len].dir = dir;
583                         DPR("%s(): %d %d -> %d %d / len=%d num=%d dir=%d\r\n",
584                             __FUNCTION__, prev_i, prev_j, i, j, path_len, linenum, dir);
585                         path_len++;
586                 }
587         }
588
589         return path_len;
590 }
591
592 /* process score from retrieved objects number, and circuit len */
593 static int16_t get_score(uint32_t wcorn_retrieved,
594                          uint32_t ucorn_retrieved,
595                          uint16_t tomato_retrieved,
596                          uint8_t len, uint8_t opp_on_path)
597 {
598         int16_t score = 0;
599         uint8_t i;
600         uint32_t mask = 1;
601         uint8_t n;
602
603         /* score with corn */
604         n = xget_cob_count() * 2;
605         for (i = 0; i<CORN_NB; i++) {
606                 if (n >= 10)
607                         break;
608                 if (wcorn_retrieved & mask) {
609                         score += 250;
610                         n += 2;
611                 }
612                 if (n >= 10)
613                         break;
614                 if (ucorn_retrieved & mask) {
615                         score += 125;
616                         n += 1;
617                 }
618                 mask <<= 1UL;
619         }
620
621         DPR("get score: cob %d (->%d)\r\n", n, n/2);
622
623         /* score with tomato */
624         n = xget_ball_count();
625         mask = 1;
626         for (i = 0; i<TOMATO_NB; i++) {
627                 if (n >= 4)
628                         break;
629                 if (tomato_retrieved & mask) {
630                         score += 150;
631                         n += 1;
632                 }
633                 mask <<= 1UL;
634         }
635
636         DPR("get score: ball %d\r\n", n);
637
638         /* malus for long circuits */
639         score -= (len * 20);
640         DPR("malus for length: %d\r\n", len * 20);
641
642         /* double malus for long circuits if we don't have much
643          * time */
644 #define WP_SPEED 1
645         if (len * WP_SPEED > (MATCH_TIME - xtime_get_s())) {
646                 int32_t extra;
647                 extra = (len * WP_SPEED) - (MATCH_TIME - xtime_get_s());
648                 extra = (200 * extra);
649                 if (extra < 0) /* should not happen */
650                         extra = 0;
651                 if (extra > 10000)
652                         extra = 10000;
653                 score -= extra;
654                 DPR("malus for length + time: %d\r\n", extra);
655         }
656
657         /* malus if there is opponent on the path */
658         if (opp_on_path) {
659                 DPR("malus for opponent: 1000\r\n");
660                 score -= 2000;
661         }
662
663         return score;
664 }
665
666 /* return the corn type of specified coords: I2C_COB_WHITE,
667  * I2C_COB_UNKNOWN, or I2C_COB_NONE if it is black or not present */
668 static uint8_t get_corn_type(uint8_t i, uint8_t j)
669 {
670         uint8_t color;
671         /* is there a corn cob ? */
672         if (strat_db.wp_table[i][j].type == WP_TYPE_CORN &&
673             strat_db.wp_table[i][j].present) {
674                 color = strat_db.wp_table[i][j].corn.color;
675                 if (color == I2C_COB_WHITE)
676                         return I2C_COB_WHITE;
677                 else if (color == I2C_COB_UNKNOWN)
678                         return I2C_COB_UNKNOWN;
679         }
680         return I2C_COB_NONE;
681 }
682
683 /* i,j: starting position */
684 static int8_t evaluate_one_face(const struct circuit *circuit,
685                                 uint8_t starti, uint8_t startj,
686                                 uint8_t faceA, int16_t *score)
687 {
688         const struct wp_coord *curcircuit;
689         const struct wp_coord *start;
690         const struct wp_coord *end;
691         uint32_t wcorn_retrieved = 0; /* bit mask */
692         uint32_t ucorn_retrieved = 0; /* bit mask */
693         uint16_t tomato_retrieved = 0; /* bit mask */
694         uint8_t opponent_on_path = 0;
695         uint8_t len = 0, found = 0;
696         uint8_t i, j, prev_i, prev_j;
697         uint8_t ni = 0, nj = 0;
698         uint8_t dir, color, idx;
699         int8_t step = faceA ? 1 : -1;
700         int16_t x, y, d, prev_d = 0;
701         int16_t oppx, oppy;
702
703         *score = 0x8000; /* -int_max */
704
705         /* start and end of circuit */
706         if (faceA) {
707                 start = &circuit->path[0];
708                 end = start + circuit->len - 1;
709         }
710         else {
711                 end = &circuit->path[0];
712                 start = end + circuit->len - 1;
713         }
714
715         DPR("%s() face: %s %d\r\n", __FUNCTION__, circuit->name, faceA);
716
717         /* check that the point is present in the circuit */
718         for (curcircuit = start; curcircuit != end; curcircuit += step) {
719                 if (curcircuit->i == starti && curcircuit->j == startj) {
720                         found = 1;
721                         break;
722                 }
723         }
724         if (found == 0)
725                 return -1;
726
727         /* get opponent coords */
728         if (get_opponent_xy(&oppx, &oppy) < 0)
729                 oppx = I2C_OPPONENT_NOT_THERE;
730         else
731                 DPR("%s() opponent: %d, %d\r\n", __FUNCTION__, oppx, oppy);
732
733         /* silent the compiler */
734         prev_i = 0xff;
735         prev_j = 0xff;
736
737         /* browse all points and calculate the score */
738         for (; /* start at starti,startj */
739              curcircuit != end;
740              curcircuit += step, len ++, prev_i = i, prev_j = j) {
741                 i = curcircuit->i;
742                 j = curcircuit->j;
743
744                 /* is opponent near the point ? */
745                 ijcoord_to_xycoord(i, j, &x, &y);
746                 if (oppx != I2C_OPPONENT_NOT_THERE) {
747                         d = distance_between(oppx, oppy, x, y);
748                         DPR("%s(): opp at %d mm (ij=%d,%d opp=%d,%d pos=%d,%d)\r\n",
749                             __FUNCTION__, d, i, j, oppx, oppy, x, y);
750                         if (d < 600 && d < prev_d)
751                                 opponent_on_path = 1;
752                         prev_d = d;
753                 }
754
755                 /* don't try to look cobs/tomato for first point */
756                 if (curcircuit == start)
757                         continue;
758
759                 /* get current direction, we wil check cobs behind us
760                  * on left and right */
761                 dir = get_dir(prev_i, prev_j, i, j);
762
763                 DPR("%d %d -> %d %d  (%d)\n", prev_i, prev_j, i, j, dir);
764
765                 /* is there a tomato ? */
766                 if (strat_db.wp_table[i][j].type == WP_TYPE_TOMATO &&
767                     strat_db.wp_table[i][j].present) {
768                         DPR("  TOMATO\n");
769                         tomato_retrieved |= (1UL << strat_db.wp_table[i][j].tomato.idx);
770                 }
771
772                 /* behind left */
773                 if (wp_get_neigh(i, j, &ni, &nj, (dir + 2) % 6) == 0) {
774                         color = get_corn_type(ni, nj);
775                         idx = strat_db.wp_table[ni][nj].corn.idx;
776                         if (color == I2C_COB_WHITE) {
777                                 DPR("  LEFT WCORN (%d)\n", idx);
778                                 wcorn_retrieved |= (1UL << idx);
779                         }
780                         else if (color == I2C_COB_UNKNOWN) {
781                                 DPR("  LEFT UCORN (%d)\n", idx);
782                                 ucorn_retrieved |= (1UL << idx);
783                         }
784                 }
785
786                 /* behind right */
787                 if (wp_get_neigh(i, j, &ni, &nj, (dir + 4) % 6) == 0) {
788                         color = get_corn_type(ni, nj);
789                         idx = strat_db.wp_table[ni][nj].corn.idx;
790                         if (color == I2C_COB_WHITE) {
791                                 DPR("  RIGHT WCORN (%d)\n", idx);
792                                 wcorn_retrieved |= (1UL << idx);
793                         }
794                         else if (color == I2C_COB_UNKNOWN) {
795                                 DPR("  RIGHT UCORN (%d)\n", idx);
796                                 ucorn_retrieved |= (1UL << idx);
797                         }
798                 }
799
800                 /* prev_i, prev_j, len and curcircuit are updated in
801                  * for (;;) */
802         }
803
804         /* write score and exit */
805         *score = get_score(wcorn_retrieved, ucorn_retrieved,
806                            tomato_retrieved, len, opponent_on_path);
807         return 0;
808 }
809
810 /* i,j: starting position */
811 static int8_t evaluate_one_circuit(const struct circuit *circuit,
812                                    uint8_t starti, uint8_t startj,
813                                    int16_t *scoreA, int16_t *scoreB)
814 {
815         if (evaluate_one_face(circuit, starti, startj, 1, scoreA) < 0)
816                 return -1;
817
818         /* we are on eject point, scoreB is the same */
819         if (starti == 11 && startj == 6) {
820                 *scoreB = *scoreA;
821                 return 0;
822         }
823
824         if (evaluate_one_face(circuit, starti, startj, 0, scoreB) < 0)
825                 return -1;
826         return 0;
827 }
828
829 /* i,j starting position */
830 static int8_t find_best_circuit(uint8_t i, uint8_t j,
831                                 const struct circuit **selected_circuit,
832                                 int8_t *selected_face)
833 {
834         const struct circuit **circuit;
835         int16_t scoreA, scoreB;
836         int16_t selected_score = 0x8000; /* ~-int_max */
837         int8_t found = -1;
838
839         *selected_face = 0;
840         *selected_circuit = circuits[0] ;
841         for (circuit = &circuits[0]; *circuit; circuit++) {
842                 if (evaluate_one_circuit(*circuit, i, j, &scoreA, &scoreB) < 0)
843                         continue;
844                 found = 0;
845                 DEBUG(E_USER_STRAT, "Scores for %s are: faceA=%d, faceB=%d",
846                       (*circuit)->name, scoreA, scoreB);
847                 if (scoreA > selected_score) {
848                         *selected_circuit = *circuit;
849                         selected_score = scoreA;
850                         *selected_face = 1;
851                 }
852                 if (scoreB > selected_score) {
853                         *selected_circuit = *circuit;
854                         selected_score = scoreB;
855                         *selected_face = 0;
856                 }
857         }
858
859         if (found == -1)
860                 DEBUG(E_USER_STRAT, "no circuit found");
861         else
862                 DEBUG(E_USER_STRAT, "circuit found: %s, %s",
863                       (*selected_circuit)->name,
864                       (*selected_face) ? "faceA":"faceB");
865         return found;
866 }
867
868 static void test_all_circuits(void)
869 {
870         const struct circuit **circuit;
871         const struct wp_coord *cur;
872         const struct wp_coord *start;
873         const struct wp_coord *end;
874         uint8_t prev_i, prev_j, i, j, dir;
875
876         for (circuit = &circuits[0]; *circuit; circuit++) {
877                 start = &(*circuit)->path[0];
878                 end = start + (*circuit)->len - 1;
879
880                 prev_i = start->i;
881                 prev_j = start->j;
882                 start ++;
883
884                 for (cur = start; cur != end;
885                      cur ++, prev_i = i, prev_j = j) {
886
887                         i = cur->i;
888                         j = cur->j;
889
890                         dir = get_dir(prev_i, prev_j, i, j);
891                         if (dir == 0xFF)
892                                 printf_P("Bad circuit %s %d %d\r\n", (*circuit)->name, i, j);
893                 }
894         }
895 }
896
897
898 static void dump_circuit_wp(struct wp_line *circuit_wpline, int8_t len)
899 {
900         int8_t i;
901         if (len <= 0)
902                 return;
903         for (i = 0; i < len; i ++) {
904                 DEBUG(E_USER_STRAT, "linenum %d dir %d",
905                       circuit_wpline[i].line_num,
906                        circuit_wpline[i].dir);
907         }
908
909 }
910
911 /* choose a circuit, then harvest on this circuit */
912 uint8_t strat_harvest_circuit(void)
913 {
914         const struct circuit *selected_circuit;
915         int8_t selected_face;
916         struct wp_line circuit_wpline[MAX_CIRCUIT_WPLINE];
917         int8_t len;
918         uint8_t i, j, idx;
919         int16_t x, y;
920         uint8_t linenum, prev_linenum;
921         uint8_t dir, prev_dir;
922         uint8_t err;
923
924         strat_set_speed(SPEED_CLITOID_SLOW, SPEED_ANGLE_SLOW);
925
926         x = position_get_x_s16(&mainboard.pos);
927         y = position_get_y_s16(&mainboard.pos);
928
929         if (xycoord_to_ijcoord(&x, &y, &i, &j) < 0) {
930                 DEBUG(E_USER_STRAT, "%s(): cannot find waypoint at %d,%d",
931                       __FUNCTION__, x, y);
932                 return END_ERROR;
933         }
934
935         if (find_best_circuit(i, j, &selected_circuit, &selected_face) < 0) {
936                 DEBUG(E_USER_STRAT, "%s(): cannot find a good circuit",
937                       __FUNCTION__);
938                 return END_ERROR;
939         }
940
941         len = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
942         if (len < 0) {
943                 DEBUG(E_USER_STRAT, "%s(): cannot find a path",
944                       __FUNCTION__);
945                 return END_ERROR;
946         }
947
948         dump_circuit_wp(circuit_wpline, len);
949
950         prev_linenum = circuit_wpline[0].line_num;
951         prev_dir = circuit_wpline[0].dir;
952
953         /* do all lines of circuit */
954         for (idx = 1; idx < len; idx ++) {
955                 linenum = circuit_wpline[idx].line_num;
956                 dir = circuit_wpline[idx].dir;
957
958                 DEBUG(E_USER_STRAT, "%s(): line %d dir %d -> line %d dir %d",
959                       __FUNCTION__, prev_linenum, prev_dir, linenum, dir);
960                 err = line2line(prev_linenum, prev_dir, linenum, dir,
961                                 TRAJ_FLAGS_NO_NEAR);
962                 if (!TRAJ_SUCCESS(err))
963                         return err;
964
965                 prev_linenum = linenum;
966                 prev_dir = dir;
967         }
968
969         return END_TRAJ;
970 }
971
972 /* try to unblock in any situation */
973 uint8_t strat_unblock(void)
974 {
975         int16_t x, y;
976         uint8_t i, j;
977         uint16_t old_dspeed, old_aspeed;
978         uint8_t err;
979
980         DEBUG(E_USER_STRAT, "%s()", __FUNCTION__);
981
982         strat_want_pack = 1;
983         strat_get_speed(&old_dspeed, &old_aspeed);
984
985         strat_hardstop();
986         strat_set_speed(SPEED_DIST_SLOW, SPEED_ANGLE_SLOW);
987         x = position_get_x_s16(&mainboard.pos);
988         y = position_get_y_s16(&mainboard.pos);
989         if (xycoord_to_ijcoord(&x, &y, &i, &j) < 0) {
990                 /* aie... go to center... but it's really a bad
991                  * idea */
992                 x = CENTER_X;
993                 y = CENTER_Y;
994         }
995
996         /* XXX if opponent is too close, go back, or wait ? */
997
998         /* go to nearest waypoint */
999         trajectory_goto_xy_abs(&mainboard.traj, x, y);
1000         err = wait_traj_end(TRAJ_FLAGS_NO_NEAR);
1001         if (err == END_TIMER)
1002                 return err;
1003
1004         if (!TRAJ_SUCCESS(err))
1005                 return err;
1006
1007         strat_set_speed(old_dspeed, old_aspeed);
1008         strat_want_pack = 0;
1009         return END_TRAJ;
1010 }
1011
1012 void test_strat_avoid(void)
1013 {
1014         test_all_circuits();
1015
1016 #ifdef TEST_STRAT_AVOID
1017         uint8_t i, j;
1018         const struct circuit *selected_circuit;
1019         int8_t selected_face;
1020         struct wp_line circuit_wpline[MAX_CIRCUIT_WPLINE];
1021         int8_t ret;
1022
1023         i = 1; j = 1;
1024         printf_P(PSTR("========= i=%d, j=%d\r\n"), i, j);
1025
1026         ts = 0; bc = 0; cc = 0;
1027         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1028         find_best_circuit(i, j, &selected_circuit, &selected_face);
1029         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1030         dump_circuit_wp(circuit_wpline, ret);
1031
1032         ts = 0; bc = 3; cc = 0;
1033         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1034         find_best_circuit(i, j, &selected_circuit, &selected_face);
1035         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1036         dump_circuit_wp(circuit_wpline, ret);
1037
1038         ts = 0; bc = 4; cc = 0;
1039         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1040         find_best_circuit(i, j, &selected_circuit, &selected_face);
1041         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1042         dump_circuit_wp(circuit_wpline, ret);
1043
1044         ts = 0; bc = 3; cc = 5;
1045         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1046         find_best_circuit(i, j, &selected_circuit, &selected_face);
1047         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1048         dump_circuit_wp(circuit_wpline, ret);
1049
1050         ts = 0; bc = 4; cc = 5;
1051         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1052         find_best_circuit(i, j, &selected_circuit, &selected_face);
1053         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1054         dump_circuit_wp(circuit_wpline, ret);
1055
1056         ts = 80; bc = 0; cc = 0;
1057         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1058         find_best_circuit(i, j, &selected_circuit, &selected_face);
1059         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1060         dump_circuit_wp(circuit_wpline, ret);
1061
1062         i = 4; j = 3;
1063         printf_P(PSTR("========= i=%d, j=%d\r\n"), i, j);
1064
1065         ts = 0; bc = 0; cc = 0;
1066         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1067         find_best_circuit(i, j, &selected_circuit, &selected_face);
1068         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1069         dump_circuit_wp(circuit_wpline, ret);
1070
1071         ts = 0; bc = 3; cc = 0;
1072         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1073         find_best_circuit(i, j, &selected_circuit, &selected_face);
1074         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1075         dump_circuit_wp(circuit_wpline, ret);
1076
1077         ts = 80; bc = 0; cc = 0;
1078         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1079         find_best_circuit(i, j, &selected_circuit, &selected_face);
1080         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1081         dump_circuit_wp(circuit_wpline, ret);
1082
1083         i = 11; j = 6;
1084         printf_P(PSTR("========= i=%d, j=%d\r\n"), i, j);
1085
1086         ts = 0; bc = 0; cc = 0;
1087         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1088         find_best_circuit(i, j, &selected_circuit, &selected_face);
1089         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1090         dump_circuit_wp(circuit_wpline, ret);
1091
1092         ts = 0; bc = 3; cc = 0;
1093         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1094         find_best_circuit(i, j, &selected_circuit, &selected_face);
1095         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1096         dump_circuit_wp(circuit_wpline, ret);
1097
1098         ts = 80; bc = 0; cc = 0;
1099         printf_P(PSTR("=== time=%"PRIu32", ball=%d, corn=%d\r\n"), ts, bc, cc);
1100         find_best_circuit(i, j, &selected_circuit, &selected_face);
1101         ret = get_path(selected_circuit, i, j, selected_face, circuit_wpline);
1102         dump_circuit_wp(circuit_wpline, ret);
1103 #endif
1104 }