16 Game*
self = malloc(
sizeof(*
self));
19 self->players_count = -1;
20 self->penguins_per_player = -1;
21 self->board_width = -1;
22 self->board_height = -1;
23 self->board_grid = NULL;
24 self->tile_attributes = NULL;
25 self->current_player_index = -1;
26 self->log_disabled =
false;
27 self->log_buffer = NULL;
28 self->log_capacity = 0;
30 self->log_current = 0;
41 Player *player = &
self->players[i], *other_player = &other->
players[i];
42 player->
name = other_player->name ? strdup(other_player->name) : NULL;
44 other_player->penguins,
sizeof(*other_player->penguins) * other_player->penguins_count
48 if (self->board_grid) {
53 if (self->tile_attributes) {
54 self->tile_attributes =
memdup(
59 if (self->log_buffer) {
69 if (
self == NULL)
return;
71 for (
int i = 0; i <
self->players_count; i++) {
89 #define fnv32_hash_value(value) state = fnv32_hash(state, &value, sizeof(value))
90 #define fnv32_hash_array(ptr, len) state = fnv32_hash(state, ptr, sizeof(*ptr) * len)
92 for (
int i = 0; i <
self->players_count; i++) {
93 const Player* player = &
self->players[i];
108 if (self->board_grid) {
112 #undef fnv32_hash_value
113 #undef fnv32_hash_array
122 self->log_capacity = capacity;
123 self->log_length =
my_min(self->log_length, capacity);
124 self->log_current =
my_min(self->log_current, capacity);
125 self->log_buffer = realloc(self->log_buffer,
sizeof(*self->log_buffer) * capacity);
138 if (self->log_disabled) {
141 if (self->log_current >= self->log_capacity) {
144 GameLogEntry* entry = &
self->log_buffer[
self->log_current];
146 self->log_current += 1;
149 self->log_length =
self->log_current;
157 assert(self->log_current > 0);
158 const GameLogEntry* entry = &
self->log_buffer[
self->log_current - 1];
159 assert(entry->
type == expected_type);
162 if (entry->
type != expected_type) {
165 self->log_current -= 1;
174 assert(idx < self->log_length);
175 return &
self->log_buffer[idx];
182 if (self->phase == phase)
return;
196 if (self->current_player_index == idx)
return;
203 self->current_player_index = idx;
226 assert(self->board_width > 0);
227 assert(self->board_height > 0);
228 assert(self->board_grid != NULL);
229 assert(self->tile_attributes != NULL);
230 assert(self->players_count >= 0);
231 if (self->players_count != 0) {
232 assert(self->players != NULL);
234 assert(self->penguins_per_player >= 0);
235 for (
int i = 0; i <
self->players_count; i++) {
236 assert(self->players[i].name != NULL);
237 if (self->penguins_per_player != 0) {
238 assert(self->players[i].penguins != NULL);
251 self->penguins_per_player = value;
252 for (
int i = 0; i <
self->players_count; i++) {
253 Player* player = &
self->players[i];
256 realloc(player->
penguins,
sizeof(*player->
penguins) * self->penguins_per_player);
267 assert(self->players == NULL);
268 self->players = malloc(
sizeof(*self->players) * count);
269 self->players_count = count;
270 for (
int i = 0; i < count; i++) {
271 Player* player = &
self->players[i];
272 player->
id = (short)(i + 1);
291 player->
name = name ? strdup(name) : NULL;
309 assert(penguin != NULL);
312 int penguin_idx = (int)(penguin - player->
penguins);
369 bool prev_log_disabled =
self->log_disabled;
371 self->log_disabled =
true;
374 while (self->log_current > target_entry) {
376 switch (entry->
type) {
380 assert(self->phase == entry_data->
new_phase);
402 for (;
self->log_current < target_entry;
self->log_current += 1) {
404 switch (entry->
type) {
407 assert(self->phase == entry_data->
old_phase);
431 self->log_disabled = prev_log_disabled;
#define fnv32_hash_array(ptr, len)
#define fnv32_hash_value(value)
The core of the unified game logic library, contains the Game struct.
GamePhase
The values of Game::phase.
@ GAME_PHASE_PLACEMENT
Set by placement_begin.
@ GAME_PHASE_MOVEMENT
Set by movement_begin.
@ GAME_PHASE_SETUP
Set by game_begin_setup.
@ GAME_PHASE_NONE
The default phase, set when a Game is initially constructed.
@ GAME_PHASE_SETUP_DONE
Set by game_end_setup, placement_end, movement_end.
@ GAME_PHASE_END
Set by game_end.
GameLogEntryType
The values of GameLogEntry::type.
@ GAME_LOG_ENTRY_PLAYER_CHANGE
See GameLogPlayerChange.
@ GAME_LOG_ENTRY_PHASE_CHANGE
See GameLogPhaseChange.
@ GAME_LOG_ENTRY_PLACEMENT
See GameLogPlacement.
@ GAME_LOG_ENTRY_MOVEMENT
See GameLogMovement.
Movement phase functions.
Placement phase functions.
A pair of 2D coordinates, used for addressing the Game::board_grid.
An entry in the Game::log_buffer, implemented as a tagged union.
union GameLogEntry::GameLogEntryData data
A GameLogEntry created by move_penguin.
A GameLogEntry created by game_set_phase.
A GameLogEntry created by place_penguin.
A GameLogEntry created by game_set_current_player.
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...
void undo_place_penguin(Game *game)
Removes a GameLogPlacement entry from the log and undoes it.
int movement_switch_player(Game *game)
Performs the player switching logic for the movement phase.
Player * game_get_current_player(const Game *self)
A shorthand for calling game_get_player with Game::current_player_index.
int game_find_player_by_id(const Game *self, short id)
Returns an index of the player or -1 if no such player was found.
void move_penguin(Game *game, Coords start, Coords target)
Creates a GameLogMovement entry. The requested move must be valid.
void game_set_log_capacity(Game *self, size_t capacity)
Sets Game::log_capacity and allocates that many elements in Game::log_buffer. If the new capacity is ...
const GameLogEntry * game_get_log_entry(const Game *self, size_t idx)
Returns a pointer to the entry at the given index. Note that the returned pointer is const because th...
void game_add_player_penguin(Game *self, int idx, Coords coords)
void game_set_current_player(Game *self, int idx)
Sets Game::current_player_index and creates a GameLogPlayerChange log entry.
Player * players
The list of players with length players_count. Initialized with game_set_players_count....
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...
void game_end(Game *self)
Switches to the GAME_PHASE_END phase.
void game_set_phase(Game *self, GamePhase phase)
Sets the current Game::phase and creates a GameLogPhaseChange log entry.
void game_remove_player_penguin(Game *self, int idx, Coords coords)
void game_advance_state(Game *self)
The all-in-one phase switcher that progresses of the game.
const GameLogEntry * game_pop_log_entry(Game *self, GameLogEntryType expected_type)
Pops the last entry off the top of the stack if its type matches the expected_type (this is used as a...
int board_width
Use setup_board for setting this.
uint32_t game_compute_state_hash(const Game *self)
Computes a hash of the game state part of the Game, i.e. the fields that change while playing the gam...
short * tile_attributes
Stores auxilary data of grid tiles for use in the UIs. Use setup_board for initializing,...
size_t log_capacity
The total number of elements log_buffer was allocated for (i.e. pushing more requires reallocating it...
short * board_grid
A 2D grid represented as a 1D array which stores the tiles of the board. Use setup_board for initiali...
GameLogEntry * log_buffer
The stack of log entries. Use game_push_log_entry, game_pop_log_entry and game_get_log_entry for modi...
void game_end_setup(Game *self)
Verifies that all fields have been initialized and configured and switches the phase from GAME_PHASE_...
Game * game_clone(const Game *other)
Creates a (deep) copy of another Game.
void placement_begin(Game *game)
Enters the GAME_PHASE_PLACEMENT phase, can only be called in GAME_PHASE_SETUP_DONE.
Coords * game_find_player_penguin(const Game *self, int idx, Coords coords)
Finds a penguin with the given coordinates in the Player::penguins list of a player at idx and return...
int board_height
Use setup_board for setting this.
void game_rewind_state_to_log_entry(Game *self, size_t target_entry)
Successively undoes or redoes log entries in order to reset the game state to the entry at the given ...
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.
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 undo_move_penguin(Game *game)
Removes a GameLogMovement entry from the log and undoes it.
bool game_check_player_index(const Game *self, int idx)
Checks if idx is within the bounds of Game::players.
void game_free(Game *self)
Destroys a Game, freeing the memory allocated for the struct itself and all associated internal lists...
GameLogEntry * game_push_log_entry(Game *self, GameLogEntryType type)
Creates a GameLogEntry, sets its GameLogEntry::type, pushes it on top of the stack (reallocating the ...
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 moves_count
The number of moves (penguin placements and movements) made by the player.
int color
The color of the penguins, currently used only in the TUI.
Coords * penguins
The list of the positions of all of the player's penguins.
int points
The score of the player, i.e. the number of collected fish.
int penguins_count
The length of the penguins array.
GameLogPlacement placement
GameLogPhaseChange phase_change
GameLogPlayerChange player_change
void * memdup(const void *src, size_t size)
A shorthand for malloc + memcpy (analogous to strdup).
#define free_and_clear(ptr)
Calls free on a pointer and then sets it to NULL.
#define my_min(x, y)
Compares two numbers and returns the smaller one.
#define FNV32_INITIAL_STATE
A constant for fnv32_hash.
#define my_max(x, y)
Compares two numbers and returns the larger one.