#include "jsmn.h" #include #include #include #include #include #include #include using std::vector; // Parsování JSONu static int jsoneq(const char *json, jsmntok_t *tok, const char *s) { if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start && strncmp(json + tok->start, s, tok->end - tok->start) == 0) { return 0; } return -1; } // Třídy reprezentující hru enum Direction { STAY = -1, UP = 0, LEFT = 1, DOWN = 2, RIGHT = 3, }; struct Team; struct Member; struct Field; struct Team { int id; bool is_me; Field* home; vector occupied; vector protected_fields; vector members; Team(int _id, bool _is_me) { id = id; is_me = _is_me; } }; struct Member { Field * field; Team * team; int id; Direction action = STAY; Member(Field *_field) { field = _field; } }; struct Field { int i,j; bool hill; Team* home_for_team = NULL; Team* occupied_by_team = NULL; Team* protected_for_team = NULL; vector members; Field(int _i, int _j) { i = _i; j = _j; } }; // Celý stav hry včetně parsování a vypisování struct State { // Dealokace paměti není implementována, protože předpokládáme, že program // poběží jen krátce a po ukončení všechna paměť automaticky zanikne. vector teams; vector> world; Team * my_team; int round_number; int time_to_response; int js_skip(jsmntok_t* t, int i) { int s = t[i].size; i++; for(int j=0; j current_row; for (int j = i+1, y=0; y < t[i].size;j = js_skip(t, j), y++) { Field *current_field = new Field(x,y); int members_tok; for (int k = j+1, c=0; c < t[j].size;k = js_skip(t, k), c++) { if (jsoneq(input_str, &t[k], "hill") == 0) current_field->hill = input_str[t[k+1].start] == 't'; if (jsoneq(input_str, &t[k], "home_for_team") == 0) if(input_str[t[k+1].start] != 'n') { current_field->home_for_team = teams[atoi(input_str+t[k+1].start)]; current_field->home_for_team->home = current_field; } if (jsoneq(input_str, &t[k], "occupied_by_team") == 0) if(input_str[t[k+1].start] != 'n') { current_field->occupied_by_team = teams[atoi(input_str+t[k+1].start)]; current_field->occupied_by_team->occupied.push_back(current_field); } if (jsoneq(input_str, &t[k], "protected_for_team") == 0) if(input_str[t[k+1].start] != 'n') { current_field->protected_for_team = teams[atoi(input_str+t[k+1].start)]; current_field->protected_for_team->protected_fields.push_back(current_field); } if (jsoneq(input_str, &t[k], "members") == 0) members_tok = k+1; } for (int k = members_tok+1, c=0; c < t[members_tok].size;k = js_skip(t, k), c++) { auto m = new Member(current_field); for (int l = k+1, d=0; d < t[k].size;l = js_skip(t, l), d++) { // printf("%d %d: %.*s %d\n", x,y, t[l].end - t[l].start, input_str + t[l].start, t[l].size); if (jsoneq(input_str, &t[l], "id") == 0) m->id = atoi(input_str + t[l+1].start); if (jsoneq(input_str, &t[l], "team") == 0) m->team = teams[atoi(input_str+t[l+1].start)]; } m->team->members.push_back(m); current_field->members.push_back(m); } current_row.push_back(current_field); } world.push_back(current_row); } } void print_turn() { for(Team *t: teams) if(!t->is_me) for(Member *m: t->members) if(m->action != STAY) { fprintf(stderr, "Voják cizího týmu má přiřazenou akci."); exit(1); } bool first = true; printf("{\"members\": ["); for(Member *m: my_team->members) { if(!first) printf(", "); const char * action = "stay"; if(m->action == UP) action = "up"; if(m->action == LEFT) action = "left"; if(m->action == DOWN) action = "down"; if(m->action == RIGHT) action = "right"; printf("{\"id\": %d, \"action\": \"%s\"}", m->id, action); first = false; } printf("]}"); } }; State* state; // Algoritmy // otoč směr podle jiného otočení Direction combine_directions(Direction a, Direction b) { if (a == STAY || b == STAY) { fprintf(stderr, "Nelze kombinovat se STAY."); exit(1); } return (Direction) ((a + b) % 4); } // získej opačný směr Direction invert_direction(Direction a) { if (a == STAY) return STAY; return combine_directions(a, DOWN); } // další políčko v daném směru Field* get_neighbour_field(Field* f, Direction direction) { int neighbour_i, neighbour_j; switch (direction) { case UP: neighbour_i = f->i - 1; neighbour_j = f->j; break; case DOWN: neighbour_i = f->i + 1; neighbour_j = f->j; break; case LEFT: neighbour_i = f->i; neighbour_j = f->j - 1; break; case RIGHT: neighbour_i = f->i; neighbour_j = f->j + 1; break; default: neighbour_i = f->i; neighbour_j = f->j; } // zajisti, aby souřadnice byly v rozsahu herní plochy neighbour_i %= state->world.size(); neighbour_j %= state->world[0].size(); return state->world[neighbour_i][neighbour_j]; } // jestli daný tým může vstoupit na políčko bool is_field_accessible(Field* f, Team* t) { if (f->hill) return false; if (f->protected_for_team != NULL && f->protected_for_team != t) return false; return true; } // Najdi nejkratší cestu od vojáka k cílovému políčku. // Vrátí první krok, který má voják udělat. // Pokud žádná cesta neexistuje, vrátí STAY. Direction pathfind(Member* m, Field* goal) { // speciální případ: voják už je v cíli if (m->field == goal) return STAY; std::set explored; std::queue queue; queue.push(goal); auto dirs = {UP, LEFT, DOWN, RIGHT}; while (!queue.empty()) { auto field = queue.front(); queue.pop(); for (auto direction : dirs) { auto neighbour = get_neighbour_field(field, direction); if (explored.find(neighbour) != explored.end()) continue; if (!is_field_accessible(neighbour, m->team)) continue; // pokud jsme našli vojáka, vrátíme první krok if (neighbour == m->field) return invert_direction(direction); queue.push(neighbour); explored.insert(neighbour); } } return STAY; } // Strategie int main() { char * input_str; scanf("%m[^\n]", &input_str); state = new State(input_str); // TODO: zde doplňte svou herní strategii for(Member *m: state->my_team->members) m->action = UP; state->print_turn(); return 0; }