+/* mark corn as not present and give correct commands to the cobboard
+ * for spickles */
+static void check_corn(void)
+{
+ uint8_t flags;
+ int8_t lcob_near, rcob_near;
+ uint8_t lcob, rcob;
+ uint8_t lidx, ridx;
+ static uint8_t prev_check_time;
+ uint8_t cur_time;
+ uint8_t need_lpack, need_rpack;
+ int16_t l_xspickle, l_yspickle;
+ int16_t r_xspickle, r_yspickle;
+ uint8_t l_y_too_high_pack = 0, r_y_too_high_pack = 0;
+
+ /* read sensors from ballboard */
+ IRQ_LOCK(flags);
+ lcob = ballboard.lcob;
+ ballboard.lcob = I2C_COB_NONE;
+ rcob = ballboard.rcob;
+ ballboard.rcob = I2C_COB_NONE;
+ IRQ_UNLOCK(flags);
+
+ /* check present cobs once per second */
+ cur_time = time_get_s();
+ if (cur_time != prev_check_time) {
+ uint8_t i;
+
+ /* only useful for simu */
+ for (i = 0; i < CORN_NB; i++) {
+ if (strat_db.corn_table[i]->present == 1 &&
+ strat_db.corn_table[i]->time_removed != -1 &&
+ strat_db.corn_table[i]->time_removed + 2 <= time_get_s()) {
+#ifdef HOST_VERSION
+ printf("remove cob %d\n", i);
+#endif
+ strat_db.corn_table[i]->present = 0;
+ }
+ }
+ prev_check_time = cur_time;
+ }
+
+ /* detect cob on left side */
+ lcob_near = corn_is_near(&lidx, I2C_LEFT_SIDE,
+ &l_xspickle, &l_yspickle);
+ if (lcob_near && lcob != I2C_COB_NONE) {
+ if (strat_db.corn_table[lidx]->corn.color == I2C_COB_UNKNOWN)
+ DEBUG(E_USER_STRAT, "lcob %s %d",
+ lcob == I2C_COB_WHITE ? "white" : "black", lidx);
+ corn_set_color(strat_db.corn_table[lidx], lcob);
+ }
+ if (cur_time > 5 && !__y_is_more_than(l_yspickle, 600))
+ l_y_too_high_pack = 1;
+
+ /* detect cob on right side */
+ rcob_near = corn_is_near(&ridx, I2C_RIGHT_SIDE,
+ &r_xspickle, &r_yspickle);
+ if (rcob_near && rcob != I2C_COB_NONE) {
+ if (strat_db.corn_table[ridx]->corn.color == I2C_COB_UNKNOWN)
+ DEBUG(E_USER_STRAT, "rcob %s %d",
+ rcob == I2C_COB_WHITE ? "white" : "black", ridx);
+ corn_set_color(strat_db.corn_table[ridx], rcob);
+ }
+ if (cur_time > 5 && !__y_is_more_than(r_yspickle, 600))
+ r_y_too_high_pack = 1;
+
+ /* re-enable white cob */
+ if (lcob == I2C_COB_WHITE && lcob_near &&
+ strat_db.corn_table[lidx]->present == 0) {
+ strat_db.corn_table[lidx]->present = 1;
+ strat_db.corn_table[lidx]->time_removed = -1;
+ }
+ if (rcob == I2C_COB_WHITE && rcob_near &&
+ strat_db.corn_table[ridx]->present == 0) {
+ strat_db.corn_table[ridx]->present = 1;
+ strat_db.corn_table[ridx]->time_removed = -1;
+ }
+
+ /* control the cobboard mode for left spickle */
+ need_lpack = get_cob_count() >= 5 || strat_want_pack ||
+ strat_lpack60 || strat_opponent_lpack || l_y_too_high_pack;
+
+ if (lcob_near &&
+ (strat_db.corn_table[lidx]->present ||
+ strat_db.corn_table[lidx]->time_removed == -1)) {
+ if (need_lpack) {
+ /* nothing */
+ }
+ else {
+ /* deploy spickle and harvest white ones */
+ if (strat_db.corn_table[lidx]->corn.color == I2C_COB_WHITE)
+ i2c_cobboard_autoharvest_nomove(I2C_LEFT_SIDE);
+ else
+ i2c_cobboard_deploy_nomove(I2C_LEFT_SIDE);
+ remove_cob(lidx);
+ }
+ }
+ else {
+ /* no cob near us, we can pack or deploy freely */
+ if (need_lpack)
+ i2c_cobboard_pack_weak(I2C_LEFT_SIDE);
+ else
+ i2c_cobboard_deploy(I2C_LEFT_SIDE);
+ }
+
+ /* control the cobboard mode for right spickle */
+ need_rpack = get_cob_count() >= 5 || strat_want_pack ||
+ strat_rpack60 || strat_opponent_rpack || r_y_too_high_pack;
+ if (rcob_near &&
+ (strat_db.corn_table[ridx]->present ||
+ strat_db.corn_table[ridx]->time_removed == -1)) {
+ if (need_rpack) {
+ /* nothing */
+ }
+ else {
+ /* deploy spickle and harvest white ones */
+ if (strat_db.corn_table[ridx]->corn.color == I2C_COB_WHITE)
+ i2c_cobboard_autoharvest_nomove(I2C_RIGHT_SIDE);
+ else
+ i2c_cobboard_deploy_nomove(I2C_RIGHT_SIDE);
+ remove_cob(ridx);
+ }
+ }
+ else {
+ /* no cob near us, we can pack or deploy freely */
+ if (need_rpack)
+ i2c_cobboard_pack_weak(I2C_RIGHT_SIDE);
+ else
+ i2c_cobboard_deploy(I2C_RIGHT_SIDE);
+ }
+}
+
+/* check opponent position */
+void check_opponent(void)
+{
+ int16_t opp_x, opp_y;
+ int16_t opp_d, opp_a;
+ uint8_t i, j;
+
+ strat_opponent_lpack = 0;
+ strat_opponent_rpack = 0;
+
+ if (get_opponent_xyda(&opp_x, &opp_y, &opp_d, &opp_a) < 0)
+ return;
+
+ /* pack spickles if opponent too close */
+ if (opp_d < 600) {
+ if (opp_a > 45 && opp_a < 135)
+ strat_opponent_lpack = 1;
+ if (opp_a > 225 && opp_a < 315)
+ strat_opponent_rpack = 1;
+ }
+
+ /* check for oranges after 5 seconds */
+ if (time_get_s() > 5) {
+ if (mainboard.our_color == I2C_COLOR_YELLOW) {
+ if (opp_y < 500 && opp_x < 500)
+ strat_db.our_oranges_count = 0;
+ if (opp_y < 500 && opp_x > AREA_X - 500)
+ strat_db.opp_oranges_count = 0;
+ }
+ else {
+ if (opp_y > AREA_Y - 500 && opp_x < 500)
+ strat_db.our_oranges_count = 0;
+ if (opp_y > AREA_Y - 500 && opp_x > AREA_X - 500)
+ strat_db.opp_oranges_count = 0;
+ }
+ }
+
+ /* malus for some tomatoes and cobs, visited by opponent */
+ if (xycoord_to_ijcoord(&opp_x, &opp_y, &i, &j) < 0)
+ return;
+
+ strat_db.wp_table[i][j].opp_visited = 1;
+}
+
+/* called periodically (10ms) */
+void strat_event(void *dummy)
+{
+ /* ignore when strat is not running */
+ if (strat_running == 0)
+ return;
+
+ check_opponent();
+ check_tomato();
+ check_corn();
+
+ /* limit speed when opponent is near */
+ /* disabled for 2010, we are already slow :) */
+ //strat_limit_speed();
+}
+
+/* check that we are on an eject line */
+static uint8_t robot_is_on_eject_line(void)
+{
+ int16_t x, y;
+ uint8_t i, j;
+
+ x = position_get_x_s16(&mainboard.pos);
+ y = position_get_y_s16(&mainboard.pos);
+
+ if (xycoord_to_ijcoord_not_corn(&x, &y, &i, &j) < 0)
+ return 0;
+
+ if (!wp_belongs_to_line(i, j, 5, LINE_UP) &&
+ !wp_belongs_to_line(i, j, 2, LINE_R_UP))
+ return 0;
+
+ return 1;
+}
+
+/* 0 = fast, 1 = slow */
+static uint8_t eject_select_speed(void)
+{
+ int16_t x, y;
+ uint8_t i, j;
+
+ x = position_get_x_s16(&mainboard.pos);
+ y = position_get_y_s16(&mainboard.pos);
+
+ if (get_cob_count() >= 5) {
+ strat_want_pack = 1;
+ return 0; /* fast */
+ }
+
+ if (xycoord_to_ijcoord_not_corn(&x, &y, &i, &j) < 0) {
+ DEBUG(E_USER_STRAT, "%s(): cannot find waypoint at %d,%d",
+ __FUNCTION__, x, y);
+ return 1; /* slow */
+ }
+
+ if (corn_count_neigh(i, j) == 2)
+ return 1; /* slow */
+
+ return 0; /* fast */
+}
+
+/* called multiple times while we are waiting to reach the ejection
+ * point */
+static uint8_t speedify_eject(void)
+{
+ if (eject_select_speed())
+ strat_set_speed(SPEED_CLITOID_SLOW, SPEED_ANGLE_SLOW);
+ else
+ strat_set_speed(SPEED_CLITOID_FAST, SPEED_ANGLE_SLOW);
+ return 0;
+}
+
+/* must be called from a terminal line */
+static uint8_t strat_eject(void)