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.