21 #define MIN_PLAYER_ID 1 
   22 #define MAX_PLAYER_ID 9 
   27     printf(
"%s\n", my_player_name);
 
   33   FILE *input_file, *output_file;
 
   48       perror(
"Failed to open the input board file");
 
   53       fprintf(stderr, 
"Failed to parse the input file\n");
 
   61 #ifdef INTERACTIVE_MODE 
   64     printf(
"The app must be compiled with the interactive mode for viewing the board files!\n");
 
   68     int my_player_index = -1;
 
   75     assert(my_player_index >= 0);
 
  107       perror(
"Failed to open the output board file");
 
  122 static size_t read_line(FILE* file, 
char** buf, 
size_t* line_len) {
 
  124   size_t buf_size = 64;
 
  125   *buf = realloc(*buf, buf_size);
 
  127   while ((c = fgetc(file)) != EOF) {
 
  128     if (*line_len + 1 >= buf_size) {
 
  130       *buf = realloc(*buf, buf_size);
 
  132     (*buf)[*line_len] = (char)c;
 
  138   (*buf)[*line_len] = 
'\0';
 
  143   char* line_buf = NULL;
 
  147   int board_width, board_height;
 
  148   if (sscanf(line_buf, 
"%d %d", &board_height, &board_width) != 2) {
 
  149     fprintf(stderr, 
"Failed to parse the board size line: '%s'\n", line_buf);
 
  152   if (!(board_width > 0 && board_height > 0)) {
 
  153     fprintf(stderr, 
"Invalid board size: %d %d\n", board_width, board_height);
 
  169   for (
int y = 0; y < board_height; y++) {
 
  171     char* str = line_buf;
 
  173     while (isspace(*str)) str++;
 
  174     for (
int x = 0; x < board_width; x++) {
 
  177       if (str[0] == 
'\0' || str[1] == 
'\0') {
 
  182       char c1 = str[0], c2 = str[1];
 
  185       if (
'0' <= c1 && c1 <= 
'9' && c2 == 
'0') {
 
  186         short fish = c1 - 
'0';
 
  188       } 
else if (
'1' <= c2 && c2 <= 
'9' && c1 == 
'0') {
 
  189         short player_id = c2 - 
'0';
 
  193         fprintf(stderr, 
"Invalid tile at x=%d y=%d: '%c%c'\n", x, y, c1, c2);
 
  198       while (isspace(*str)) str++;
 
  202   int players_count = 0;
 
  203   for (
int linenr = 0; linenr < 
MAX_PLAYERS; linenr++) {
 
  204     if (!
read_line(file, &line_buf, &line_len)) {
 
  210     if (sscanf(line_buf, 
"%255s %d %d", name, &
id, &points) != 3) {
 
  211       fprintf(stderr, 
"Failed to parse the player on line %d: '%s'\n", linenr, line_buf);
 
  215       fprintf(stderr, 
"Player ID on line %d falls out of the acceptable range: %d\n", linenr, 
id);
 
  218     if (taken_player_ids[
id]) {
 
  219       fprintf(stderr, 
"Player ID on line %d is a duplicate: %d\n", linenr, 
id);
 
  223       fprintf(stderr, 
"Player name on line %d is empty\n", linenr);
 
  226     taken_player_ids[id] = 
true;
 
  227     int i = players_count;
 
  228     player_ids[i] = (short)
id;
 
  229     player_names[i] = strdup(name);
 
  230     player_scores[i] = points;
 
  234   bool my_player_found = 
false;
 
  235   for (
int i = 0; i < players_count; i++) {
 
  236     if (strcmp(player_names[i], my_player_name) == 0) {
 
  237       my_player_found = 
true;
 
  241   if (!my_player_found) {
 
  244       if (!taken_player_ids[
id]) {
 
  249     if (free_id <= 0 || players_count >= 
MAX_PLAYERS) {
 
  250       fprintf(stderr, 
"No IDs left in the input file to assign to our own player\n");
 
  253     int i = players_count;
 
  254     player_ids[i] = free_id;
 
  255     player_names[i] = strdup(my_player_name);
 
  256     player_scores[i] = 0;
 
  260   int penguins_per_player = 
my_max(penguins_arg, 1);
 
  261   for (
int i = 0; i < players_count; i++) {
 
  262     penguins_per_player =
 
  268   for (
int i = 0; i < players_count; i++) {
 
  271     player->
id = player_ids[i];
 
  272     player->
points = player_scores[i];
 
  276         short tile = 
get_tile(game, coords);
 
  286   for (
int i = 0; i < players_count; i++) {
 
  287     free(player_names[i]);
 
  298       short tile = 
get_tile(game, coords);
 
  302       if (0 <= tile && tile <= 9) {
 
  304         fprintf(file, 
"%c0", 
'0' + fish);
 
  305       } 
else if (-9 <= tile && tile <= -1) {
 
  307         fprintf(file, 
"0%c", 
'0' + player_id);
 
  315     fprintf(file, 
"%s %d %d\n", player->
name, player->
id, player->
points);
 
The command-line argument parser.
 
const char * MY_AUTONOMOUS_PLAYER_NAME
 
bool load_game_state(Game *game, FILE *file, int penguins_arg, const char *my_player_name)
 
static size_t read_line(FILE *file, char **buf, size_t *line_len)
 
int run_autonomous_mode(const Arguments *args)
 
bool save_game_state(const Game *game, FILE *file)
 
The autonomous-mode machine interface.
 
void generate_board_random(Game *game, Rng *rng)
Generates the board by setting every tile purely randomly. The resulting board will look sort of like...
 
void generate_board_island(Game *game, Rng *rng)
Generates the board which looks sort of like a big icy island.
 
Functions for working with the game board (and the specifics of its encoding)
 
#define PENGUIN_TILE(player_id)
 
#define get_tile_player_id(tile)
 
#define get_tile_fish(tile)
 
The core of the unified game logic library, contains the Game struct.
 
void print_game_state(const Game *game)
 
The interactive-mode text user interface.
 
Movement phase functions.
 
Placement phase functions.
 
const char * input_board_file
 
const char * output_board_file
 
GenerateArg board_gen_type
 
Contains temporary data created during the evaluation of bot's moves.
 
bool bot_compute_placement(BotState *self, Coords *out_target)
Computes the best placement for the current player given the current game state.
 
void bot_state_free(BotState *self)
Recursively destroys a BotState and its substates (similarly to game_free).
 
BotState * bot_state_new(const BotParameters *params, Game *game, Rng *rng)
Constructs a BotState (similarly game_new).
 
bool bot_compute_move(BotState *self, Coords *out_penguin, Coords *out_target)
Computes the best move for the current player given the current game state.
 
A pair of 2D coordinates, used for addressing the Game::board_grid.
 
The central struct of the application, holds the game data and settings.
 
void game_set_penguins_per_player(Game *self, int value)
Sets Game::penguins_per_player (the value mustn't be negative) and allocates Player::penguins lists o...
 
int movement_switch_player(Game *game)
Performs the player switching logic for the movement phase.
 
ALWAYS_INLINE void set_tile(Game *game, Coords coords, short value)
Sets the value of the tile at coords (and also sets the attribute TILE_DIRTY). Fails if coords are ou...
 
void move_penguin(Game *game, Coords start, Coords target)
Creates a GameLogMovement entry. The requested move must be valid.
 
ALWAYS_INLINE short get_tile(const Game *game, Coords coords)
Returns the value of the tile at coords. Fails if coords are outside the bounds.
 
void game_add_player_penguin(Game *self, int idx, Coords coords)
 
void game_begin_setup(Game *self)
Switches to the GAME_PHASE_SETUP phase, can only be called in GAME_PHASE_NONE. Should be called right...
 
int board_width
Use setup_board for setting this.
 
void setup_board(Game *game, int width, int height)
Sets Game::board_width and Game::board_height and allocates Game::board_grid and Game::tile_attribute...
 
void game_end_setup(Game *self)
Verifies that all fields have been initialized and configured and switches the phase from GAME_PHASE_...
 
void placement_begin(Game *game)
Enters the GAME_PHASE_PLACEMENT phase, can only be called in GAME_PHASE_SETUP_DONE.
 
int board_height
Use setup_board for setting this.
 
int placement_switch_player(Game *game)
Performs the player switching logic for the placement phase.
 
void movement_begin(Game *game)
Enters the GAME_PHASE_MOVEMENT phase, can only be called in GAME_PHASE_SETUP_DONE.
 
int current_player_index
A negative value means that there is no current player selected. Use game_set_current_player for sett...
 
void game_set_player_name(Game *self, int idx, const char *name)
Sets the Player::name of a player at the given index. Only available in the GAME_PHASE_SETUP phase.
 
int players_count
Use game_set_players_count for setting this.
 
void place_penguin(Game *game, Coords target)
Creates a GameLogPlacement entry. The requested placement must be valid.
 
void movement_end(Game *game)
Exits the GAME_PHASE_MOVEMENT phase and switches to GAME_PHASE_SETUP_DONE.
 
Player * game_get_player(const Game *self, int idx)
Returns a pointer to the player at the given index. Fails if the index isn't within the bounds of the...
 
void placement_end(Game *game)
Exits the GAME_PHASE_PLACEMENT phase and switches to GAME_PHASE_SETUP_DONE.
 
Game * game_new(void)
Constructs a Game. Allocates memory for storing the struct itself, setting all fields to default valu...
 
void game_free(Game *self)
Destroys a Game, freeing the memory allocated for the struct itself and all associated internal lists...
 
void game_set_players_count(Game *self, int count)
Sets Game::players_count (the value mustn't be negative) and allocates the Game::players list....
 
Holds the data of the players of the Game.
 
short id
The unique ID, usually (but not necessarily) is just index + 1.
 
char * name
Use game_set_player_name to set this.
 
int points
The score of the player, i.e. the number of collected fish.
 
int penguins_count
The length of the penguins array.
 
A wrapper around random number generators.
 
Rng init_stdlib_rng(void)
Returns an RNG implementation based on the rand function from <stdlib.h> (and seeds it with srand).
 
#define my_max(x, y)
Compares two numbers and returns the larger one.