From d2e4e1f473154775de48d19a31a97e9604e30905 Mon Sep 17 00:00:00 2001 From: Jérôme Jutteau Date: Sat, 28 May 2011 14:27:14 +0200 Subject: digital/io-hub: add element score computation --- digital/io-hub/src/robospierre/element.c | 685 +++++++++++++++++++++++++++++++ 1 file changed, 685 insertions(+) create mode 100644 digital/io-hub/src/robospierre/element.c (limited to 'digital/io-hub/src/robospierre/element.c') diff --git a/digital/io-hub/src/robospierre/element.c b/digital/io-hub/src/robospierre/element.c new file mode 100644 index 00000000..341206b0 --- /dev/null +++ b/digital/io-hub/src/robospierre/element.c @@ -0,0 +1,685 @@ +/* element.c */ +/* io - Input & Output with Artificial Intelligence (ai) support on AVR. {{{ + * + * Copyright (C) 2011 Jérôme Jutteau + * + * APBTeam: + * Web: http://apbteam.org/ + * Email: team AT apbteam DOT org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * }}} */ +#include "common.h" +#include "element.h" + +#include "modules/utils/utils.h" +#include "modules/math/geometry/distance.h" +#include "modules/math/geometry/geometry.h" + +#include "chrono.h" +#include "logistic.h" + +/** Elements on table. */ +struct element_t element_table[] = +{ + /* + 20 elements on intersections. + To be symmetric, alternate % 2. + See ELEMENT_INTERSEC_START and ELEMENT_INTERSEC_END + ELEMENT_INTERSEC_END don't takes central pawn. + */ + {ELEMENT_NONE | ELEMENT_PAWN, {1500 - 2 * 350, 5 * 350}, ELEMENT_INTERSEC | ELEMENT_LEFT}, /* top left */ + {ELEMENT_NONE | ELEMENT_PAWN, {1500 + 2 * 350, 5 * 350}, ELEMENT_INTERSEC | ELEMENT_RIGHT}, /* top right */ + {ELEMENT_NONE | ELEMENT_PAWN, {1500 - 1 * 350, 5 * 350}, ELEMENT_INTERSEC | ELEMENT_LEFT}, /* middle left */ + {ELEMENT_NONE | ELEMENT_PAWN, {1500 + 1 * 350, 5 * 350}, ELEMENT_INTERSEC | ELEMENT_RIGHT}, /* middle right */ + {ELEMENT_NONE | ELEMENT_PAWN, {1500 - 2 * 350, 4 * 350}, ELEMENT_INTERSEC | ELEMENT_LEFT}, /* 2nd line left */ + {ELEMENT_NONE | ELEMENT_PAWN, {1500 + 2 * 350, 4 * 350}, ELEMENT_INTERSEC | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_PAWN, {1500 - 1 * 350, 4 * 350}, ELEMENT_INTERSEC | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_PAWN, {1500 + 1 * 350, 4 * 350}, ELEMENT_INTERSEC | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_PAWN, {1500 - 2 * 350, 3 * 350}, ELEMENT_INTERSEC | ELEMENT_LEFT}, /* 3th line left */ + {ELEMENT_NONE | ELEMENT_PAWN, {1500 + 2 * 350, 3 * 350}, ELEMENT_INTERSEC | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_PAWN, {1500 - 1 * 350, 3 * 350}, ELEMENT_INTERSEC | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_PAWN, {1500 + 1 * 350, 3 * 350}, ELEMENT_INTERSEC | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_PAWN, {1500 - 2 * 350, 2 * 350}, ELEMENT_INTERSEC | ELEMENT_LEFT}, /* 4th line left */ + {ELEMENT_NONE | ELEMENT_PAWN, {1500 + 2 * 350, 2 * 350}, ELEMENT_INTERSEC | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_PAWN, {1500 - 1 * 350, 2 * 350}, ELEMENT_INTERSEC | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_PAWN, {1500 + 1 * 350, 2 * 350}, ELEMENT_INTERSEC | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_PAWN, {1500 - 2 * 350, 1 * 350}, ELEMENT_INTERSEC | ELEMENT_LEFT}, /* 5th line left */ + {ELEMENT_NONE | ELEMENT_PAWN, {1500 + 2 * 350, 1 * 350}, ELEMENT_INTERSEC | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_PAWN, {1500 - 1 * 350, 1 * 350}, ELEMENT_INTERSEC | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_PAWN, {1500 + 1 * 350, 1 * 350}, ELEMENT_INTERSEC | ELEMENT_RIGHT}, + + /* Central pawn. (see ELEMENT_CENTRAL_PAWN) */ + {ELEMENT_PAWN, {1500, 3 * 350}, ELEMENT_INTERSEC | ELEMENT_CENTER}, + + /* + 10 elements on green zones. + To be symmetric, alternate % 2. + See ELEMENT_GREEN_START and ELEMENT_GREEN_END + */ + {ELEMENT_ANY, {200, 10 + 280 * 5}, ELEMENT_GREEN |ELEMENT_LEFT}, /* top left */ + {ELEMENT_ANY, {3000 - 200, 10 + 280 * 5}, ELEMENT_GREEN | ELEMENT_RIGHT}, /* top right */ + {ELEMENT_ANY, {200, 10 + 280 * 4}, ELEMENT_GREEN |ELEMENT_LEFT}, /* 2nd line left */ + {ELEMENT_ANY, {3000 - 200, 10 + 280 * 4}, ELEMENT_GREEN | ELEMENT_RIGHT}, /* 2nd line right */ + {ELEMENT_ANY, {200, 10 + 280 * 3}, ELEMENT_GREEN |ELEMENT_LEFT}, /* ... */ + {ELEMENT_ANY, {3000 - 200, 10 + 280 * 3}, ELEMENT_GREEN | ELEMENT_RIGHT}, + {ELEMENT_ANY, {200, 10 + 280 * 2}, ELEMENT_GREEN |ELEMENT_LEFT}, + {ELEMENT_ANY, {3000 - 200, 10 + 280 * 2}, ELEMENT_GREEN | ELEMENT_RIGHT}, + {ELEMENT_ANY, {200, 10 + 280 * 1}, ELEMENT_GREEN |ELEMENT_LEFT}, + {ELEMENT_ANY, {3000 - 200, 10 + 280 * 1}, ELEMENT_GREEN | ELEMENT_RIGHT}, + + /* + 32 elements in the middle of a square. + Altern colors in order to retrieve position % 2. + See ELEMENT_UNLOAD_START and ELEMENT_UNLOAD_END + */ + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 2 * 350 - 175, 5 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, /* Top left blue */ + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 1 * 350 - 175, 5 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 0 * 350 - 175, 5 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 0 * 350 + 175, 5 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 1 * 350 + 175, 5 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 2 * 350 + 175, 5 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 2 * 350 - 175, 4 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, /* 2nd line left red */ + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 1 * 350 - 175, 4 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, /* bonus */ + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 0 * 350 - 175, 4 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 0 * 350 + 175, 4 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 1 * 350 + 175, 4 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT | ELEMENT_BONUS}, /* bonus */ + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 2 * 350 + 175, 4 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 2 * 350 - 175, 3 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, /* 3th line left blue */ + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 1 * 350 - 175, 3 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 0 * 350 - 175, 3 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 0 * 350 + 175, 3 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 1 * 350 + 175, 3 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 2 * 350 + 175, 3 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 2 * 350 - 175, 2 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, /* 4th line left red */ + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 1 * 350 - 175, 2 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT | ELEMENT_BONUS}, /* bonus */ + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 0 * 350 - 175, 2 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 0 * 350 + 175, 2 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 1 * 350 + 175, 2 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT | ELEMENT_BONUS}, /* bonus */ + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 2 * 350 + 175, 2 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 2 * 350 - 175, 1 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, /* 5th line left blue */ + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 1 * 350 - 175, 1 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 0 * 350 - 175, 1 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 0 * 350 + 175, 1 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 1 * 350 + 175, 1 * 350 + 175}, ELEMENT_CENTER | ELEMENT_RIGHT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 2 * 350 + 175, 1 * 350 + 175}, ELEMENT_CENTER | ELEMENT_LEFT}, + {ELEMENT_NONE | ELEMENT_ANY, {1500 - 175, 175}, ELEMENT_CENTER | ELEMENT_LEFT | ELEMENT_BONUS}, /* middle bonus left, red. */ + {ELEMENT_NONE | ELEMENT_ANY, {1500 + 175, 175}, ELEMENT_CENTER | ELEMENT_RIGHT | ELEMENT_BONUS}, /* middle bonus right, blue. */ + + /* + 4 elements in safe zones. + see ELEMENT_UNLOAD_SAFE_START and ELEMENT_UNLOAD_SAFE_END + */ + {ELEMENT_NONE, {1500 - 2 * 350 - 175, 175}, ELEMENT_CENTER | ELEMENT_SAFE | ELEMENT_LEFT}, /* left red */ + {ELEMENT_NONE, {1500 - 1 * 350 - 175, 175}, ELEMENT_CENTER | ELEMENT_SAFE | ELEMENT_RIGHT}, /* left blue */ + {ELEMENT_NONE, {1500 + 1 * 350 + 175, 175}, ELEMENT_CENTER | ELEMENT_SAFE | ELEMENT_LEFT}, /* right red */ + {ELEMENT_NONE, {1500 + 2 * 350 + 175, 175}, ELEMENT_CENTER | ELEMENT_SAFE | ELEMENT_RIGHT} /* right blue */ +}; + +inline element_t +element_get (uint8_t element_id) +{ + assert (element_id < UTILS_COUNT (element_table)); + return element_table[element_id]; +} + +inline void +element_set (uint8_t element_id, element_t element) +{ + assert (element_id < UTILS_COUNT (element_table)); + element_table[element_id] = element; +} + +void +element_init () +{ + /* Set NONE in middle of our squares and keep ELEMENT_NONE | ELEMENT_ANY + in others square middle. */ + uint8_t i; + element_t e; + for (i = ELEMENT_UNLOAD_START; i <= ELEMENT_UNLOAD_END; i++) + { + e = element_get (i); + if ((team_color == TEAM_COLOR_LEFT && + (e.attr & ELEMENT_LEFT)) || + (team_color == TEAM_COLOR_RIGHT && + (e.attr & ELEMENT_RIGHT))) + { + e.type = ELEMENT_NONE; + element_set (i, e); + } + } +} + +int32_t +element_unload_score (position_t robot_pos, uint8_t element_id) +{ + int32_t score = 0; + assert (element_id < UTILS_COUNT (element_table)); + element_t e = element_get (element_id); + + /* If it is not an unload zone, quit. */ + if (!((e.attr & ELEMENT_CENTER) || (e.attr & ELEMENT_INTERSEC))) + return -1; + + /* Unload color. */ + if (!( + (e.attr & ELEMENT_CENTER) && + ((team_color == TEAM_COLOR_LEFT && (e.attr & ELEMENT_LEFT)) + ||(team_color == TEAM_COLOR_RIGHT && (e.attr & ELEMENT_RIGHT))) + )) + return -1; + + /* If there is already something here, do not score. */ + if (e.type != ELEMENT_NONE) + return -1; + + /* Bonus score. */ + if ((e.attr & ELEMENT_BONUS) && + (chrono_remaining_time () * 100 / CHRONO_MATCH_DURATION_MS > 40)) + score += 1000; + + /* Unload distance. */ + /* TODO: minimal distance may not be the best choice. */ + vect_t v = e.pos; + int32_t dr = distance_point_point (&v, &robot_pos.v); + score += 4242 - dr; + + /* Alignment with the robot. */ + if (dr > 100) + { + vect_t vr = v; + vect_sub (&vr, &robot_pos.v); + vect_t u; + uint16_t a; + if (logistic_global.collect_direction == DIRECTION_FORWARD) + a = robot_pos.a; + else + a = robot_pos.a + G_ANGLE_UF016_DEG (180); + vect_from_polar_uf016 (&u, 100, a); + int32_t dp = vect_dot_product (&u, &vr); + int32_t align = dp / dr; + score += align; + } + + return score; +} + +uint8_t +element_unload_best (position_t robot_pos) +{ + uint8_t i; + uint8_t best = 0xff; + int32_t score, best_score = 0; + for (i = ELEMENT_UNLOAD_START; + i <= ELEMENT_UNLOAD_END; + i++) + { + score = element_score (robot_pos , i); + if (best == 0xff || best_score < score) + { + best = i; + best_score = score; + } + } + return best; +} + +int32_t +element_score (position_t robot_pos, uint8_t element_id) +{ + int32_t score = 0; + assert (element_id < UTILS_COUNT (element_table)); + element_t e = element_get (element_id); + + if (e.attr & ELEMENT_SAFE) + return -1; + + if ((e.attr & ELEMENT_CENTER) && + ((team_color == TEAM_COLOR_LEFT && (e.attr & ELEMENT_LEFT)) || + (team_color == TEAM_COLOR_RIGHT && (e.attr & ELEMENT_RIGHT)))) + return -1; + + if (e.type == ELEMENT_NONE && + ((e.attr & ELEMENT_INTERSEC) ||(e.attr & ELEMENT_GREEN))) + return -1; + + if (e.type & ELEMENT_PAWN) + score += ELEMENT_PAWN_SCORE; + if (e.type & ELEMENT_QUEEN) + score += ELEMENT_QUEEN_SCORE; + if (e.type & ELEMENT_KING) + score += ELEMENT_KING_SCORE; + if (e.type & ELEMENT_ANY) + score += ELEMENT_ANY_SCORE; + else if (e.type & ELEMENT_NONE) + score /= 2; + + /* Big score for our green zone. */ + if (e.type != ELEMENT_NONE && (e.attr & ELEMENT_GREEN)) + { + /* In our zone. */ + if ((team_color == TEAM_COLOR_LEFT && (e.attr & ELEMENT_LEFT)) || + (team_color == TEAM_COLOR_RIGHT && (e.attr & ELEMENT_RIGHT))) + score *= 10; + /* In the other zone, boost score if our green zone is empty. */ + else + { + element_t el; + int cpt = 0; + u8 i; + /* Is our green zone empty ? */ + for (i = ELEMENT_GREEN_START; i <= ELEMENT_GREEN_END; i++) + { + el = element_get (i); + if (((team_color == TEAM_COLOR_LEFT && (el.attr & ELEMENT_LEFT)) || + (team_color == TEAM_COLOR_RIGHT && (el.attr & ELEMENT_RIGHT))) + && el.type == ELEMENT_NONE) + cpt++; + } + if (cpt == 5) + score *= 10; + } + } + + //TODO Set right modifier at this time + score *= 100; + + /* Central pawn. */ + if (element_id == ELEMENT_CENTRAL_PAWN) + score += 1000; + + /* We are sure of this element. */ + if (!(e.type & ELEMENT_NONE) && + (e.attr == ELEMENT_INTERSEC || e.attr == ELEMENT_CENTER) && + element_id != ELEMENT_CENTRAL_PAWN) + score += score / 4; + + /* Distance from the robot. */ + vect_t v = e.pos; + int32_t dr = distance_point_point (&v, &robot_pos.v); + score += (4242 - dr); + + /* Alignment with the robot. */ + if (dr > 100) + { + vect_t vr = v; + vect_sub (&vr, &robot_pos.v); + vect_t u; + uint16_t a; + if (logistic_global.collect_direction == DIRECTION_FORWARD) + a = robot_pos.a; + else + a = robot_pos.a + G_ANGLE_UF016_DEG (180); + vect_from_polar_uf016 (&u, 100, a); + int32_t dp = vect_dot_product (&u, &vr); + int32_t align = dp / dr; + score += align; + } + + /* Adjust score with time probability. */ + score += element_proba (element_id); + return score; +} + +uint32_t +element_proba (uint8_t element_id) +{ + assert (element_id < UTILS_COUNT (element_table)); + element_t e = element_get (element_id); + uint32_t p_t = chrono_remaining_time () * 500 / CHRONO_MATCH_DURATION_MS; + uint8_t p_pos; + int32_t out = 0; + + /* Intersections. */ + if (e.attr & ELEMENT_INTERSEC) + { + /* Element on our side ? */ + if ((team_color == TEAM_COLOR_LEFT && (e.attr & ELEMENT_LEFT)) || + (team_color == TEAM_COLOR_RIGHT && (e.attr & ELEMENT_RIGHT))) + { + p_pos = 20 - element_id / 2; + out = p_pos * p_t; + } + /* Element on the other side ? */ + else + { + p_pos = element_id / 2 + 1; + out = p_pos * p_t; + } + } + /* Green zone. */ + else if (e.attr & ELEMENT_GREEN) + { + /* In our side. */ + if ((team_color == TEAM_COLOR_LEFT && (e.attr & ELEMENT_LEFT)) || + (team_color == TEAM_COLOR_RIGHT && (e.attr & ELEMENT_RIGHT))) + { + p_pos = 5 - ((element_id - ELEMENT_GREEN_START) / 2); + out = p_t * p_pos; + + } + /* Other side. */ + else + { + p_pos = (element_id - ELEMENT_GREEN_START) / 2 + 1; + out = p_t * p_pos; + } + + } + /* Central pawn */ + else if (e.type == ELEMENT_CENTRAL_PAWN) + out = p_t; + /* Centre of squares. */ + else if (e.attr & ELEMENT_CENTER) + { + /* In our side. */ + if ((team_color == TEAM_COLOR_LEFT && (e.attr & ELEMENT_LEFT)) || + (team_color == TEAM_COLOR_RIGHT && (e.attr & ELEMENT_RIGHT))) + out = 0; + /* Other side. */ + else + { + p_pos = (element_id - ELEMENT_UNLOAD_START) / 2 + 1; + out = (1000 - p_t) * p_pos; + if (e.attr & ELEMENT_BONUS) + out += 1000; + } + + } + else + out = 0; + return out; +} + +uint8_t +element_best (position_t robot_pos) +{ + uint8_t i; + uint8_t best = 0xff; + int32_t score = 0, best_score = 0; + for (i = 0; i < UTILS_COUNT (element_table); i++) + { + score = element_score (robot_pos ,i); + if (best == 0xff || best_score < score) + { + best = i; + best_score = score; + } + } + return best; +} + +void +element_not_here (uint8_t element_id) +{ + assert (element_id < UTILS_COUNT (element_table)); + element_t e = element_get (element_id); + e.type = ELEMENT_NONE; + element_set (element_id, e); + + /* Invalidate the same element to the other side. */ + if (e.attr & ELEMENT_INTERSEC) + { + uint8_t other_side_id = element_opposed (element_id); + element_t other_side = element_get (other_side_id); + other_side.type = ELEMENT_NONE; + element_set (other_side_id, other_side); + } + + /* If the element is on an intersection, try to guess last elements. */ + element_intersec_symetric (element_id, ELEMENT_NONE); +} + +inline void +element_intersec_symetric (uint8_t element_id, uint8_t element_type) +{ + static uint8_t element_columns[2][5] = + { + { + ELEMENT_NONE | ELEMENT_PAWN, + ELEMENT_NONE | ELEMENT_PAWN, + ELEMENT_NONE | ELEMENT_PAWN, + ELEMENT_NONE | ELEMENT_PAWN, + ELEMENT_NONE | ELEMENT_PAWN + }, + { + ELEMENT_NONE | ELEMENT_PAWN, + ELEMENT_NONE | ELEMENT_PAWN, + ELEMENT_NONE | ELEMENT_PAWN, + ELEMENT_NONE | ELEMENT_PAWN, + ELEMENT_NONE | ELEMENT_PAWN + } + }; + element_t e = element_get (element_id); + + /* if the element is on an intersection, try to guess last elements. */ + if ((e.attr & ELEMENT_INTERSEC) && !(e.attr & ELEMENT_CENTER)) + { + uint8_t cpt_none = 0; + uint8_t cpt_pawn = 0; + uint8_t col; + uint8_t i; + uint8_t type = 0; + + if (element_id % 4 == 0 || element_id % 4 == 1) + col = 0; + else + col = 1; + + /* Nothing to see. */ + if (element_columns[col][4] != (ELEMENT_NONE | ELEMENT_PAWN)) + return; + + /* Count. */ + for (i = 0; i < 5; i++) + { + if (element_columns[col][i] == ELEMENT_PAWN ||element_type == ELEMENT_PAWN) + cpt_pawn++; + if (element_columns[col][i] == ELEMENT_NONE ||element_type == ELEMENT_NONE) + cpt_none++; + if (element_columns[col][i] == (ELEMENT_NONE | ELEMENT_PAWN)) + { + element_columns[col][i] = element_type; + break; + } + } + + /* With which element are we going to fill the rest ? */ + if (cpt_pawn == 2) + type = ELEMENT_NONE; + if (cpt_none == 3) + type = ELEMENT_PAWN; + + if (type) + for (i = 0; i < 5; i++) + if (element_columns[col][i] == (ELEMENT_NONE | ELEMENT_PAWN)) + element_columns[col][i] = type; + + /* Complete if possible. */ + if (type != 0) + for (i = ELEMENT_INTERSEC_START; i < ELEMENT_INTERSEC_END; i++) + if (i % 4 == element_id % 4) + { + element_t el = element_get (i); + element_t sym = element_get (element_opposed (i)); + if (el.type == (ELEMENT_NONE | ELEMENT_PAWN)) + { + el.type = type; + element_set (i, el); + /* Set opposed. */ + if (sym.type == (ELEMENT_NONE | ELEMENT_PAWN)) + { + sym.type = type; + element_set (element_opposed (i), sym); + } + } + } + } +} + +void +element_taken (uint8_t element_id, uint8_t element_type) +{ + assert (element_id < UTILS_COUNT (element_table)); + static uint8_t pawn_c = 3, queen_c = 1, king_c = 1, any_nb = 5; + uint8_t other_side_id, other_side_id_element; + + if (element_type != ELEMENT_PAWN && element_type != ELEMENT_QUEEN && element_type != ELEMENT_KING) + return; + + /* Set element. */ + element_t e = element_get (element_id); + e.type = ELEMENT_NONE; + element_set (element_id, e); + + /* Deduce symmetric position. */ + if ((e.attr & ELEMENT_INTERSEC) || (e.attr & ELEMENT_GREEN)) + { + other_side_id_element = element_opposed (element_id); + element_t other_side = element_get (other_side_id_element); + if (other_side.type != ELEMENT_NONE) + { + other_side.type = element_type; + element_set (other_side_id_element, other_side); + } + } + + /* If the element is on an intersection, try to guess last elements. */ + element_intersec_symetric (element_id, element_type); + + /* If the element is in the green zone, try to guess last elements. */ + if ((e.attr & ELEMENT_GREEN) && any_nb > 0) + { + uint8_t i; + if (element_type == ELEMENT_PAWN) + pawn_c--; + else if (element_type == ELEMENT_QUEEN) + queen_c--; + else if (element_type == ELEMENT_KING) + king_c--; + any_nb--; + + /* If there is something to guess. */ + if (any_nb <= 3) + { + /* All others are pawns. */ + if (!queen_c && !king_c) + { + for (i = ELEMENT_GREEN_START; i <= ELEMENT_GREEN_END; i++) + { + element_t el = element_get (i); + if (el.type == ELEMENT_ANY) + { + el.type = ELEMENT_PAWN; + element_set (i, el); + any_nb--; + /* Set opposed side. */ + other_side_id = element_opposed (element_id); + element_t other_side = element_get (other_side_id); + if (other_side.type != ELEMENT_NONE && + other_side_id != other_side_id_element) + { + other_side.type = ELEMENT_PAWN; + element_set (other_side_id, other_side); + } + } + } + } + /* All others are unidentified heads */ + else if (pawn_c == 0 && any_nb == 2) + { + for (i = ELEMENT_GREEN_START; i <= ELEMENT_GREEN_END; i++) + { + element_t el = element_get (i); + if (el.type == ELEMENT_ANY) + { + el.type = ELEMENT_HEAD; + element_set (i, el); + /* Set opposed side. */ + other_side_id = element_opposed (element_id); + element_t other_side = element_get (other_side_id); + if (other_side.type != ELEMENT_NONE && + other_side_id != other_side_id_element) + { + other_side.type = ELEMENT_HEAD; + element_set (other_side_id, other_side); + } + } + } + } + /* Last element. */ + if (any_nb == 1) + { + uint8_t last_type; + if (pawn_c == 1) last_type = ELEMENT_PAWN; + else if (queen_c == 1) last_type = ELEMENT_QUEEN; + else last_type = ELEMENT_KING; + for (i = ELEMENT_GREEN_START; i <= ELEMENT_GREEN_END; i++) + { + element_t el = element_get (i); + if (el.type == ELEMENT_ANY || el.type == ELEMENT_HEAD) + { + el.type = last_type; + element_set (i, el); + any_nb--; + /* Set opposed side. */ + other_side_id = element_opposed (i); + element_t other_side = element_get (other_side_id); + if (other_side.type != ELEMENT_NONE && + other_side_id != other_side_id_element) + { + other_side.type = last_type; + element_set (other_side_id, other_side); + } + break; + } + } + } + } + } +} + +void +element_down (uint8_t element_id, uint8_t element_type) +{ + element_t e = element_get (element_id); + e.type = element_type; + element_set (element_id, e); +} + +uint8_t +element_give_position (position_t pos) +{ + uint8_t e = 0xff; + + return e; +} + +uint8_t +element_opposed (uint8_t element_id) +{ + uint8_t op = 0xff; + element_t e = element_get (element_id); + if ((e.attr & ELEMENT_GREEN) ||(e.attr & ELEMENT_INTERSEC)) + { + if (e.attr & ELEMENT_LEFT) + op = element_id + 1; + else + op = element_id - 1; + } + return op; +} -- cgit v1.2.3