penguins  1.0.0
controllers.cc
Go to the documentation of this file.
1 #include "gui/controllers.hh"
2 #include "board.h"
3 #include "game.h"
4 #include "gui/bot_thread.hh"
5 #include "gui/canvas.hh"
6 #include "gui/game.hh"
7 #include "gui/game_state.hh"
8 #include "movement.h"
9 #include "placement.h"
10 #include "utils.h"
11 #include <memory>
12 #include <wx/button.h>
13 #include <wx/debug.h>
14 #include <wx/defs.h>
15 #include <wx/sizer.h>
16 #include <wx/string.h>
17 #include <wx/utils.h>
18 
20 : panel(panel), canvas(panel->canvas), game(panel->game.get()), bot_params(panel->bot_params) {}
21 
23  this->panel->update_game_state();
24 }
25 
27  this->configure_bot_turn_ui();
29  this->update_status_bar();
31  this->canvas->Refresh();
32 }
33 
35  this->panel->stop_bot_progress();
36 }
37 
40 }
41 
42 void GameController::on_deactivated(GameController* WXUNUSED(next_controller)) {}
43 void GameController::paint_overlay(wxDC& WXUNUSED(dc)) {}
46 void GameController::on_mouse_up(wxMouseEvent& WXUNUSED(event)) {}
47 
49  this->panel->frame->clear_status_bar();
50 }
51 
53  this->update_status_bar();
54  this->canvas->Refresh();
55 }
56 
59  if (!this->panel->game_ended) {
60  this->panel->game_ended = true;
62  }
64  this->panel->exit_game_btn->Show();
65  this->panel->game_controls_box->Layout();
66 }
67 
69  this->panel->start_bot_progress();
70 }
71 
73  return new BotPlacementThread(this);
74 }
75 
77  return new BotMovementThread(this);
78 }
79 
82  this->start_bot_thread();
83 }
84 
85 void BotTurnController::on_deactivated(GameController* WXUNUSED(next_controller)) {
86  this->stop_bot_thread();
87 }
88 
90  this->stop_bot_thread();
91 }
92 
94  this->executing_bot_turn = false;
95  if (!cancelled) {
97  } else {
98  this->panel->stop_bot_progress();
99  }
100 }
101 
104  this->executing_bot_turn = true;
105  BotThread* thread = this->create_bot_thread();
106  {
108  wxASSERT(this->bot_thread == nullptr);
109  this->bot_thread = thread;
110  }
111  wxThreadError code WX_ATTRIBUTE_UNUSED = thread->Run();
112  wxASSERT(code == wxTHREAD_NO_ERROR);
113 }
114 
117  // Well, this ain't the best way of doing thread synchronization, but it sure
118  // does work.
119  std::shared_ptr<BotThreadShared> shared = nullptr;
120  {
122  if (this->bot_thread) {
123  this->bot_thread->cancel();
124  shared = this->bot_thread->shared;
125  this->bot_thread = nullptr;
126  }
127  }
128  if (shared) {
129  shared->wait_for_exit();
130  }
131  this->executing_bot_turn = false;
132 }
133 
135  wxASSERT(wxThread::GetCurrentId() == thread->GetId());
137  // Another bot thread might have just been spun up after cancelling this one,
138  // so check that we are unregistering the correct one to be sure.
139  if (this->bot_thread == thread) {
140  this->bot_thread = nullptr;
141  }
142 }
143 
145  const GameLogEntry* entry = game_get_log_entry(game, this->entry_index);
146  size_t adjusted_index = this->entry_index;
147  if (entry->type == GAME_LOG_ENTRY_PHASE_CHANGE) {
148  if (entry->data.phase_change.new_phase == GAME_PHASE_END) {
149  adjusted_index = game->log_length;
150  }
151  } else if (entry->type == GAME_LOG_ENTRY_PLACEMENT) {
152  adjusted_index += 1;
153  }
154  game_rewind_state_to_log_entry(game, adjusted_index);
156 }
157 
160 }
161 
165 }
166 
168  Coords curr_coords = this->canvas->tile_coords_at_point(this->canvas->mouse_pos);
169  bool is_a_tile_selected =
170  this->canvas->mouse_within_window && is_tile_in_bounds(game, curr_coords);
171  for (int y = 0; y < game->board_height; y++) {
172  for (int x = 0; x < game->board_width; x++) {
173  Coords coords = { x, y };
174  bool blocked = !validate_placement_simple(game, coords);
175  set_tile_attr(game, coords, TILE_BLOCKED_FOR_CURSOR, blocked);
176  set_tile_attr(game, coords, TILE_BLOCKED, blocked && is_a_tile_selected);
177  }
178  }
179 }
180 
182  Coords selected_penguin = this->canvas->get_selected_penguin_coords();
183  if (!is_tile_in_bounds(game, selected_penguin)) {
184  int current_player_id = game_get_current_player(game)->id;
185  for (int y = 0; y < game->board_height; y++) {
186  for (int x = 0; x < game->board_width; x++) {
187  Coords coords = { x, y };
188  short tile = get_tile(game, coords);
189  bool blocked = get_tile_player_id(tile) != current_player_id;
190  set_tile_attr(game, coords, TILE_BLOCKED_FOR_CURSOR, blocked);
191  set_tile_attr(game, coords, TILE_BLOCKED, false);
192  }
193  }
194  return;
195  }
196  // A penguin is selected
199  PossibleSteps moves = calculate_penguin_possible_moves(game, selected_penguin);
200  bool any_steps = false;
201  for (int dir = 0; dir < DIRECTION_MAX; dir++) {
202  Coords coords = selected_penguin;
203  Coords d = DIRECTION_TO_COORDS[dir];
204  any_steps = any_steps || moves.steps[dir] != 0;
205  for (int steps = moves.steps[dir]; steps > 0; steps--) {
206  coords.x += d.x, coords.y += d.y;
207  set_tile_attr(game, coords, TILE_BLOCKED, false);
208  set_tile_attr(game, coords, TILE_BLOCKED_FOR_CURSOR, false);
209  }
210  }
211  set_tile_attr(game, selected_penguin, TILE_BLOCKED, false);
212  if (any_steps && !this->canvas->mouse_is_down) {
213  set_tile_attr(game, selected_penguin, TILE_BLOCKED_FOR_CURSOR, false);
214  }
215 }
216 
220 }
221 
223  Coords current_coords = this->canvas->tile_coords_at_point(this->canvas->mouse_pos);
224  if (is_tile_in_bounds(game, current_coords) && this->canvas->mouse_within_window) {
225  bool blocked = get_tile_attr(game, current_coords, TILE_BLOCKED_FOR_CURSOR);
226  this->canvas->paint_selected_tile_outline(dc, current_coords, blocked);
227  }
228 }
229 
232 
233  if (!this->canvas->mouse_is_down) return;
234  Coords penguin = this->canvas->get_selected_penguin_coords();
235  Coords target = this->canvas->tile_coords_at_point(this->canvas->mouse_pos);
236  if (!(is_tile_in_bounds(game, penguin) && is_tile_in_bounds(game, target))) return;
237  if (coords_same(penguin, target)) return;
238 
239  Coords move_fail = penguin;
240  MovementError result = validate_movement(game, penguin, target, &move_fail);
241  this->canvas->paint_move_arrow(dc, penguin, target, move_fail, result == MOVEMENT_VALID);
242 }
243 
245  const GameLogEntry* entry = game_get_log_entry(game, this->entry_index);
246  if (entry->type == GAME_LOG_ENTRY_PLACEMENT) {
248  } else if (entry->type == GAME_LOG_ENTRY_MOVEMENT) {
250  this->canvas->paint_move_arrow(dc, entry->data.movement.penguin, entry->data.movement.target);
251  }
252 }
253 
255  switch (result) {
256  case PLACEMENT_VALID: return "You can place your penguin here!";
257  case PLACEMENT_OUT_OF_BOUNDS: return "A tile outside the board has been selected.";
258  case PLACEMENT_EMPTY_TILE: return "Penguins can only be placed on ice tiles with one fish.";
259  case PLACEMENT_ENEMY_PENGUIN: return "This tile is already occupied by a penguin.";
260  case PLACEMENT_OWN_PENGUIN: return "This tile is already occupied by your own penguin.";
261  case PLACEMENT_MULTIPLE_FISH: return "Penguins may only be placed on tiles with one fish.";
262  }
263  return "";
264 }
265 
267  GameFrame* frame = this->panel->frame;
268  Coords curr_coords = this->canvas->tile_coords_at_point(this->canvas->mouse_pos);
269  if (!(this->canvas->mouse_within_window && is_tile_in_bounds(game, curr_coords))) {
270  frame->clear_status_bar();
271  return;
272  }
273  frame->SetStatusText(wxString::Format("(%d, %d)", curr_coords.x + 1, curr_coords.y + 1), 1);
274  PlacementError result = validate_placement(game, curr_coords);
275  frame->SetStatusText(describe_placement_result(result), 0);
276 }
277 
279  switch (result) {
280  case MOVEMENT_VALID: return "This is a valid move!";
281  case MOVEMENT_OUT_OF_BOUNDS: return "A tile outside the board has been selected.";
282  case MOVEMENT_CURRENT_LOCATION: return "Drag the mouse to a desired tile to make a move.";
283  case MOVEMENT_DIAGONAL:
284  return "Penguins cannot move diagonally, only horizontally or vertically.";
285  case MOVEMENT_NOT_A_PENGUIN: return "You must select a penguin to make a move.";
286  case MOVEMENT_NOT_YOUR_PENGUIN: return "You must select your own penguin to make a move.";
287  case MOVEMENT_ONTO_EMPTY_TILE: return "You can't move onto a water tile.";
288  case MOVEMENT_ONTO_PENGUIN: return "You can't move onto another penguin.";
289  case MOVEMENT_OVER_EMPTY_TILE: return "You can't jump over a water tile.";
290  case MOVEMENT_OVER_PENGUIN: return "You can't jump over another penguin.";
292  return "There are no possible moves for this penguin, it is blocked on all sides.";
293  }
294  return "";
295 }
296 
298  GameFrame* frame = this->panel->frame;
299  Coords prev_coords = this->canvas->tile_coords_at_point(this->canvas->mouse_drag_pos);
300  Coords curr_coords = this->canvas->tile_coords_at_point(this->canvas->mouse_pos);
301  if (!(this->canvas->mouse_within_window && is_tile_in_bounds(game, curr_coords))) {
302  frame->clear_status_bar();
303  return;
304  }
305  if (this->canvas->mouse_is_down && is_tile_in_bounds(game, prev_coords)) {
306  MovementError result = validate_movement(game, prev_coords, curr_coords, nullptr);
307  if (result != MOVEMENT_VALID) {
308  frame->SetStatusText(describe_movement_result(result), 0);
309  } else if (this->canvas->mouse_is_down_real) {
310  frame->SetStatusText("This is a valid move! Release the mouse to confirm it.", 0);
311  } else {
312  frame->SetStatusText("This is a valid move! Click on the tile to confirm it.", 0);
313  }
314  frame->SetStatusText(
316  "(%d, %d) -> (%d, %d)",
317  prev_coords.x + 1,
318  prev_coords.y + 1,
319  curr_coords.x + 1,
320  curr_coords.y + 1
321  ),
322  1
323  );
324  } else {
325  MovementError result = MOVEMENT_VALID;
326  if (is_tile_in_bounds(game, curr_coords) && is_penguin_tile(get_tile(game, curr_coords))) {
327  result = validate_movement_start(game, curr_coords);
328  }
329  if (result != MOVEMENT_VALID) {
330  frame->SetStatusText(describe_movement_result(result), 0);
331  } else {
332  frame->SetStatusText("Either drag or click on a penguin to make a move.", 0);
333  }
334  frame->SetStatusText(wxString::Format("(%d, %d)", curr_coords.x + 1, curr_coords.y + 1), 1);
335  }
336 }
337 
339  this->panel->frame->SetStatusText("The bot is thinking...", 0);
340  this->panel->frame->SetStatusText("", 1);
341 }
342 
344  this->panel->frame->SetStatusText("The game has ended!", 0);
345  this->panel->frame->SetStatusText("", 1);
346 }
347 
349  this->panel->frame->SetStatusText(
350  wxString::Format("Viewing a previous turn (entry #%zd)", this->entry_index + 1), 0
351  );
352  this->panel->frame->SetStatusText("", 1);
353 }
354 
356  this->update_status_bar();
357  this->canvas->Refresh();
358 }
359 
361  Coords prev_coords = this->canvas->tile_coords_at_point(this->canvas->prev_mouse_pos);
362  Coords curr_coords = this->canvas->tile_coords_at_point(this->canvas->mouse_pos);
363  if (coords_same(curr_coords, prev_coords)) return;
364  this->update_status_bar();
365  this->canvas->Refresh();
366 }
367 
369  Coords prev_coords = this->canvas->tile_coords_at_point(this->canvas->prev_mouse_pos);
370  Coords curr_coords = this->canvas->tile_coords_at_point(this->canvas->mouse_pos);
371  if (coords_same(curr_coords, prev_coords)) return;
372  Coords selected_penguin = this->canvas->get_selected_penguin_coords();
373  if (is_tile_in_bounds(game, selected_penguin)) {
374  set_tile_attr(game, selected_penguin, TILE_NEEDS_REDRAW, true);
375  }
376  this->update_status_bar();
377  this->canvas->Refresh();
378 }
379 
381  Coords prev_coords = this->canvas->tile_coords_at_point(this->canvas->mouse_drag_pos);
382  Coords curr_coords = this->canvas->tile_coords_at_point(this->canvas->mouse_pos);
383  if (is_tile_in_bounds(game, curr_coords) && coords_same(prev_coords, curr_coords)) {
384  if (validate_placement(game, curr_coords) == PLACEMENT_VALID) {
385  place_penguin(game, curr_coords);
387  return;
388  } else {
389  wxBell();
390  }
391  }
392  this->update_status_bar();
393 }
394 
396  Coords prev_coords = this->canvas->tile_coords_at_point(this->canvas->mouse_drag_pos);
397  Coords curr_coords = this->canvas->tile_coords_at_point(this->canvas->mouse_pos);
398  if (is_tile_in_bounds(game, curr_coords) && is_tile_in_bounds(game, prev_coords)) {
399  if (coords_same(prev_coords, curr_coords)) {
400  if (validate_movement_start(game, curr_coords) == MOVEMENT_VALID) {
401  // This is a hacky way of doing what I want: when the user has simply
402  // clicked on a penguin, let them then move it without dragging the
403  // mouse all the way.
404  this->canvas->mouse_is_down = true;
405  } else {
406  wxBell();
407  }
408  } else {
409  if (validate_movement(game, prev_coords, curr_coords, nullptr) == MOVEMENT_VALID) {
410  move_penguin(game, prev_coords, curr_coords);
412  return;
413  } else {
414  wxBell();
415  }
416  }
417  }
418  this->update_status_bar();
419  this->canvas->Refresh();
420 }
421 
423  if (!this->executing_bot_turn) {
424  this->on_activated();
425  }
426 }
void set_all_tiles_attr(Game *game, short attr, bool value)
Sets the attribute attr on all tiles.
Definition: board.h:95
bool is_tile_in_bounds(const Game *game, Coords coords)
Checks if the given coords are within the bounds of the board.
Definition: board.h:70
short get_tile(const Game *game, Coords coords)
Returns the value of the tile at coords. Fails if coords are outside the bounds.
Definition: board.h:108
bool get_tile_attr(const Game *game, Coords coords, short attr)
Checks whether the attribute attr of the tile at coords is set.
Definition: board.h:78
void set_tile_attr(Game *game, Coords coords, short attr, bool value)
Sets (or resets) the attribute attr of the tile at coords.
Definition: board.h:86
Functions for working with the game board (and the specifics of its encoding)
#define is_penguin_tile(tile)
Definition: board.h:26
#define get_tile_player_id(tile)
Definition: board.h:28
GameFrame * frame
Definition: game.hh:42
virtual BotThread * create_bot_thread() override
Definition: controllers.cc:76
virtual BotThread * create_bot_thread() override
Definition: controllers.cc:72
void cancel()
Definition: bot_thread.cc:36
std::shared_ptr< BotThreadShared > shared
Definition: bot_thread.hh:37
virtual BotThread * create_bot_thread()=0
virtual ~BotTurnController()
Definition: controllers.cc:89
virtual void on_mouse_up(wxMouseEvent &event) override
Definition: controllers.cc:422
BotThread * bot_thread
Definition: controllers.hh:85
void unregister_bot_thread(BotThread *thread)
Definition: controllers.cc:134
wxCriticalSection bot_thread_cs
Definition: controllers.hh:84
virtual void update_status_bar() override
Definition: controllers.cc:338
void on_bot_thread_done_work(bool cancelled)
Definition: controllers.cc:93
virtual void on_activated() override
Definition: controllers.cc:80
virtual void update_tile_attributes() override
Definition: controllers.cc:217
virtual void configure_bot_turn_ui() override
Definition: controllers.cc:68
virtual void on_deactivated(GameController *next_controller) override
Definition: controllers.cc:85
wxPoint mouse_pos
Definition: canvas.hh:37
void paint_selected_tile_outline(wxDC &dc, Coords coords, bool blocked=false)
Definition: canvas.cc:263
bool mouse_is_down
Definition: canvas.hh:35
void paint_move_arrow(wxDC &dc, Coords start, Coords end)
Definition: canvas.cc:269
Coords tile_coords_at_point(wxPoint point) const
Definition: canvas.cc:46
bool mouse_is_down_real
Definition: canvas.hh:36
Coords get_selected_penguin_coords() const
Definition: canvas.cc:59
bool mouse_within_window
Definition: canvas.hh:34
wxPoint prev_mouse_pos
Definition: canvas.hh:38
wxPoint mouse_drag_pos
Definition: canvas.hh:39
virtual void on_mouse_move(wxMouseEvent &event)
Definition: controllers.cc:45
GameController(GamePanel *panel)
Definition: controllers.cc:19
virtual void on_mouse_up(wxMouseEvent &event)
Definition: controllers.cc:46
virtual void on_deactivated(GameController *next_controller)
Definition: controllers.cc:42
void update_game_state_and_indirectly_delete_this()
Definition: controllers.cc:22
virtual void update_status_bar()
Definition: controllers.cc:48
virtual void configure_log_viewer_ui()
Definition: controllers.cc:38
virtual void on_activated()
Definition: controllers.cc:26
CanvasPanel * canvas
Definition: controllers.hh:35
virtual void on_mouse_down(wxMouseEvent &event)
Definition: controllers.cc:44
virtual void on_mouse_enter_leave(wxMouseEvent &event)
Definition: controllers.cc:52
virtual void paint_overlay(wxDC &dc)
Definition: controllers.cc:43
virtual void configure_bot_turn_ui()
Definition: controllers.cc:34
GamePanel * panel
Definition: controllers.hh:34
virtual void update_tile_attributes()
Definition: controllers.cc:162
virtual void update_status_bar() override
Definition: controllers.cc:343
virtual void on_activated() override
Definition: controllers.cc:57
void clear_status_bar()
Definition: game.cc:132
wxSizer * game_controls_box
Definition: game.hh:81
bool game_ended
Definition: game.hh:68
void update_game_state()
Definition: game.cc:324
void show_game_results()
Definition: game.cc:444
wxButton * show_current_turn_btn
Definition: game.hh:82
void start_bot_progress()
Definition: game.cc:364
wxButton * exit_game_btn
Definition: game.hh:83
void update_player_info_boxes()
Definition: game.cc:451
void stop_bot_progress()
Definition: game.cc:376
virtual void paint_overlay(wxDC &dc) override
Definition: controllers.cc:244
virtual void configure_log_viewer_ui() override
Definition: controllers.cc:158
virtual void update_status_bar() override
Definition: controllers.cc:348
virtual void on_activated() override
Definition: controllers.cc:144
virtual void update_status_bar() override
Definition: controllers.cc:297
virtual void on_mouse_move(wxMouseEvent &event) override
Definition: controllers.cc:368
virtual void on_mouse_down(wxMouseEvent &event) override
Definition: controllers.cc:355
virtual void update_tile_attributes() override
Definition: controllers.cc:181
virtual void paint_overlay(wxDC &dc) override
Definition: controllers.cc:230
virtual void on_mouse_up(wxMouseEvent &event) override
Definition: controllers.cc:395
virtual void on_mouse_up(wxMouseEvent &event) override
Definition: controllers.cc:380
virtual void update_status_bar() override
Definition: controllers.cc:266
virtual void update_tile_attributes() override
Definition: controllers.cc:167
virtual void on_mouse_move(wxMouseEvent &event) override
Definition: controllers.cc:360
virtual void paint_overlay(wxDC &dc) override
Definition: controllers.cc:222
void CallAfter(void(T::*method)(T1,...), T1 x1,...)
virtual void SetStatusText(const wxString &text, int number=0)
virtual void Layout()
static wxString Format(const wxString &format,...)
static bool IsMain()
static wxThreadIdType GetCurrentId()
wxThreadIdType GetId() const
wxThreadError Run()
bool Disable()
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL)
virtual bool Enable(bool enable=true)
bool Hide()
virtual bool Show(bool show=true)
static wxString describe_placement_result(PlacementError result)
Definition: controllers.cc:254
static wxString describe_movement_result(MovementError result)
Definition: controllers.cc:278
Player * game_get_current_player(const Game *self)
A shorthand for calling game_get_player with Game::current_player_index.
Definition: game.h:401
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...
Definition: game.c:173
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 ...
Definition: game.c:368
The core of the unified game logic library, contains the Game struct.
@ GAME_PHASE_END
Set by game_end.
Definition: game.h:61
@ GAME_LOG_ENTRY_PHASE_CHANGE
See GameLogPhaseChange.
Definition: game.h:88
@ GAME_LOG_ENTRY_PLACEMENT
See GameLogPlacement.
Definition: game.h:90
@ GAME_LOG_ENTRY_MOVEMENT
See GameLogMovement.
Definition: game.h:91
@ TILE_NEEDS_REDRAW
Definition: game_state.hh:22
@ TILE_BLOCKED_FOR_CURSOR
Definition: game_state.hh:21
@ TILE_BLOCKED
Definition: game_state.hh:19
#define wxASSERT(condition)
void wxBell()
wxThreadError
wxTHREAD_NO_ERROR
void move_penguin(Game *game, Coords start, Coords target)
Creates a GameLogMovement entry. The requested move must be valid.
Definition: movement.c:118
PossibleSteps calculate_penguin_possible_moves(const Game *game, Coords start)
Definition: movement.h:64
MovementError validate_movement(const Game *game, Coords start, Coords target, Coords *fail)
Definition: movement.c:76
MovementError validate_movement_start(const Game *game, Coords start)
Definition: movement.c:58
Movement phase functions.
MovementError
Definition: movement.h:16
@ MOVEMENT_OVER_EMPTY_TILE
Definition: movement.h:25
@ MOVEMENT_PENGUIN_BLOCKED
Definition: movement.h:27
@ MOVEMENT_NOT_YOUR_PENGUIN
Definition: movement.h:22
@ MOVEMENT_NOT_A_PENGUIN
Definition: movement.h:21
@ MOVEMENT_ONTO_PENGUIN
Definition: movement.h:24
@ MOVEMENT_OUT_OF_BOUNDS
Definition: movement.h:18
@ MOVEMENT_CURRENT_LOCATION
Definition: movement.h:19
@ MOVEMENT_DIAGONAL
Definition: movement.h:20
@ MOVEMENT_VALID
Definition: movement.h:17
@ MOVEMENT_OVER_PENGUIN
Definition: movement.h:26
@ MOVEMENT_ONTO_EMPTY_TILE
Definition: movement.h:23
bool validate_placement_simple(const Game *game, Coords target)
Definition: placement.c:64
PlacementError validate_placement(const Game *game, Coords target)
Definition: placement.c:70
void place_penguin(Game *game, Coords target)
Creates a GameLogPlacement entry. The requested placement must be valid.
Definition: placement.c:93
Placement phase functions.
PlacementError
Definition: placement.h:14
@ PLACEMENT_VALID
Definition: placement.h:15
@ PLACEMENT_OWN_PENGUIN
Definition: placement.h:19
@ PLACEMENT_MULTIPLE_FISH
Definition: placement.h:20
@ PLACEMENT_ENEMY_PENGUIN
Definition: placement.h:18
@ PLACEMENT_EMPTY_TILE
Definition: placement.h:17
@ PLACEMENT_OUT_OF_BOUNDS
Definition: placement.h:16
A pair of 2D coordinates, used for addressing the Game::board_grid.
Definition: utils.h:15
int x
Definition: utils.h:16
int y
Definition: utils.h:17
An entry in the Game::log_buffer, implemented as a tagged union.
Definition: game.h:156
union GameLogEntry::GameLogEntryData data
GameLogEntryType type
Definition: game.h:157
Coords penguin
Definition: game.h:114
Coords target
Definition: game.h:115
GamePhase new_phase
Definition: game.h:97
Coords target
Definition: game.h:108
int board_width
Use setup_board for setting this.
Definition: game.h:264
size_t log_length
The actual number of entries in log_buffer. game_push_log_entry and game_pop_log_entry affects this.
Definition: game.h:351
int board_height
Use setup_board for setting this.
Definition: game.h:266
short id
The unique ID, usually (but not necessarily) is just index + 1.
Definition: game.h:70
Exists purely to wrap an array of the numbers of steps in every possible Direction.
Definition: movement.h:35
int steps[DIRECTION_MAX]
Definition: movement.h:36
GameLogMovement movement
Definition: game.h:162
GameLogPlacement placement
Definition: game.h:161
GameLogPhaseChange phase_change
Definition: game.h:159
bool coords_same(Coords a, Coords b)
Checks if two Coords pairs are equal.
Definition: utils.h:46
const Coords DIRECTION_TO_COORDS[DIRECTION_MAX]
A table that maps Direction variants to relative Coords.
Definition: utils.c:19
@ DIRECTION_MAX
Definition: utils.h:25