Created
April 7, 2015 10:52
-
-
Save raek/2241a7104718f7ed1ea1 to your computer and use it in GitHub Desktop.
"BombAi" programming contest example client in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdbool.h> | |
#define ERROR(msg) error(msg, __FILE__, __LINE__) | |
#define FAIL() error(__FUNCTION__, __FILE__, __LINE__) | |
#define ASSERT(expr) do { if (!(expr)) { error(#expr, __FILE__, __LINE__); } } while (0) | |
void error(const char *msg, const char *file, int line) | |
{ | |
fprintf(stderr, "%s:%d: %s\n", file, line, msg); | |
exit(1); | |
} | |
enum keyword_ { | |
kw_up, | |
kw_down, | |
kw_left, | |
kw_right, | |
kw_pass, | |
kw_out | |
}; | |
typedef enum keyword_ keyword; | |
struct action_ { | |
bool place_bomb; | |
keyword non_bomb_action; | |
int bomb_delay; | |
}; | |
typedef struct action_ action; | |
const action action_up = {false, kw_up, -1}; | |
const action action_down = {false, kw_down, -1}; | |
const action action_left = {false, kw_left, -1}; | |
const action action_right = {false, kw_right, -1}; | |
const action action_pass = {false, kw_pass, -1}; | |
const action action_out = {false, kw_out, -1}; | |
struct parameters_ { | |
int player_id; | |
int number_of_players; | |
int max_number_of_turns; | |
}; | |
typedef struct parameters_ parameters; | |
struct map_ { | |
int width; | |
int height; | |
char *data; | |
}; | |
typedef struct map_ map; | |
struct bomb_ { | |
int pos_x; | |
int pos_y; | |
int ticks_left; | |
}; | |
typedef struct bomb_ bomb; | |
struct player_ { | |
int pos_x; | |
int pos_y; | |
int bomb_count; | |
bomb *bombs; | |
action last_action; | |
}; | |
typedef struct player_ player; | |
struct state_ { | |
parameters parameters; | |
map map; | |
player *players; | |
}; | |
typedef struct state_ state; | |
const int max_bombs_per_players = 5; | |
bool is_whitespace(char c) | |
{ | |
return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'); | |
} | |
bool is_digit(char c) | |
{ | |
return (c >= '0') && (c <= '9'); | |
} | |
char *map_pos(map *m, int row, int col) | |
{ | |
return &m->data[m->width * row + col]; | |
} | |
int read_integer_token(void) | |
{ | |
int i; | |
int res = scanf("%d", &i); | |
if (res != 1) { | |
FAIL(); | |
} | |
return i; | |
} | |
void read_character_tokens(int n, char *buffer) | |
{ | |
int i; | |
for (i = 0; i < n; i++) { | |
int c; | |
do { | |
c = getchar(); | |
if (c == EOF) { | |
FAIL(); | |
} | |
} while (is_whitespace((char) c)); | |
buffer[i] = (char) c; | |
} | |
} | |
keyword read_keyword_token(void) | |
{ | |
char buffer[6]; | |
int res = scanf("%5s", buffer); | |
if (res != 1) { | |
FAIL(); | |
} | |
if (strcmp(buffer, "up") == 0) { | |
return kw_up; | |
} else if (strcmp(buffer, "down") == 0) { | |
return kw_down; | |
} else if (strcmp(buffer, "left") == 0) { | |
return kw_left; | |
} else if (strcmp(buffer, "right") == 0) { | |
return kw_right; | |
} else if (strcmp(buffer, "pass") == 0) { | |
return kw_pass; | |
} else if (strcmp(buffer, "out") == 0) { | |
return kw_out; | |
} else { | |
ERROR("invalid keyword"); | |
} | |
} | |
action read_action_token(void) | |
{ | |
action a; | |
int c; | |
do { | |
c = getchar(); | |
if (c == EOF) { | |
FAIL(); | |
} | |
} while (is_whitespace((char) c)); | |
a.place_bomb = is_digit((char) c); | |
int res = ungetc(c, stdin); | |
if (res == EOF) { | |
FAIL(); | |
} | |
if (a.place_bomb) { | |
a.bomb_delay = read_integer_token(); | |
} else { | |
a.non_bomb_action = read_keyword_token(); | |
} | |
return a; | |
} | |
void read_parameters(parameters *p) | |
{ | |
p->player_id = read_integer_token(); | |
p->number_of_players = read_integer_token(); | |
p->max_number_of_turns = read_integer_token(); | |
} | |
void read_map(map *m) | |
{ | |
read_character_tokens(m->width * m->height, m->data); | |
} | |
void read_bomb(bomb *b) | |
{ | |
b->pos_x = read_integer_token(); | |
b->pos_y = read_integer_token(); | |
b->ticks_left = read_integer_token(); | |
} | |
void read_round(state *state) | |
{ | |
int player_count = state->parameters.number_of_players; | |
for (int i = 0; i < player_count; i++) { | |
state->players[i].bomb_count = 0; | |
} | |
read_map(&state->map); | |
int live_player_count = read_integer_token(); | |
for (int i = 0; i < live_player_count; i++) { | |
int player_id = read_integer_token(); | |
ASSERT(player_id < player_count); | |
player *player = &state->players[player_id]; | |
player->pos_x = read_integer_token(); | |
player->pos_y = read_integer_token(); | |
} | |
int bomb_count = read_integer_token(); | |
for (int i = 0; i < bomb_count; i++) { | |
int player_id = read_integer_token(); | |
ASSERT(player_id < player_count); | |
player *player = &state->players[player_id]; | |
ASSERT(player->bomb_count < max_bombs_per_players); | |
bomb *bomb = &player->bombs[player->bomb_count]; | |
read_bomb(bomb); | |
player->bomb_count++; | |
} | |
for (int i = 0; i < player_count; i++) | |
{ | |
int player_id = read_integer_token(); | |
ASSERT(player_id < player_count); | |
player *player = &state->players[player_id]; | |
player->last_action = read_action_token(); | |
} | |
} | |
bool no_more_tokens(void) | |
{ | |
int c; | |
do { | |
c = getchar(); | |
if (c == EOF) { | |
return true; | |
} | |
} while (is_whitespace((char) c)); | |
ungetc(c, stdin); | |
return false; | |
} | |
void setup(state *state) | |
{ | |
read_parameters(&state->parameters); | |
state->map.width = read_integer_token(); | |
state->map.height = read_integer_token(); | |
state->map.data = malloc(sizeof(char) * state->map.width * state->map.height); | |
state->players = malloc(sizeof(player) * state->parameters.number_of_players); | |
for (int i = 0; i < state->parameters.number_of_players; i++) | |
{ | |
state->players[i].bombs = malloc(sizeof(bomb) * max_bombs_per_players); | |
} | |
} | |
void write_action(action a) | |
{ | |
if (a.place_bomb) { | |
printf("%d\n", a.bomb_delay); | |
} else { | |
const char *s; | |
switch (a.non_bomb_action) { | |
case kw_up: | |
s = "up"; | |
break; | |
case kw_down: | |
s = "down"; | |
break; | |
case kw_left: | |
s = "left"; | |
break; | |
case kw_right: | |
s = "right"; | |
break; | |
case kw_pass: | |
s = "pass"; | |
break; | |
default: | |
FAIL(); | |
break; | |
} | |
puts(s); | |
} | |
} | |
void make_move(state *state) | |
{ | |
write_action(action_pass); | |
} | |
int main(int argc, char **argv) | |
{ | |
state state; | |
setup(&state); | |
while (!no_more_tokens()) { | |
read_round(&state); | |
make_move(&state); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment