From dd85972d53ba5f88eb9b4eb3cb229e1d0e8b8f1a Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Wed, 4 Dec 2013 17:35:07 -0800 Subject: [PATCH] Implement automatic pass (when there is no legal move) and end-of-game Along with a simple report of the score and the winning player. This is obviously much better than the hidden UI of requiring a right-click to pass (and the bogus option of allowing a pass when a player has a legal move). --- dvonn-board.c | 82 ++++++++++++++++++++++++++++++++++++++++++++------- dvonn-board.h | 10 ++----- dvonn.c | 46 +++++++++++++++++++++-------- 3 files changed, 108 insertions(+), 30 deletions(-) diff --git a/dvonn-board.c b/dvonn-board.c index eeab830..c78905e 100644 --- a/dvonn-board.c +++ b/dvonn-board.c @@ -80,6 +80,8 @@ dvonn_board_init (dvonn_board_t *board) board->phase = DVONN_PHASE_PLACEMENT; board->player = DVONN_PLAYER_WHITE; board->moves = 0; + board->score[DVONN_PLAYER_BLACK] = 0; + board->score[DVONN_PLAYER_WHITE] = 0; } dvonn_bool_t @@ -196,24 +198,84 @@ dvonn_board_move_legal (dvonn_board_t *board, return TRUE; } -static void +static dvonn_bool_t +dvonn_board_player_has_legal_move (dvonn_board_t *board) +{ + int x, y, height; + char *error; + + for (x = 0; x < DVONN_BOARD_X_SIZE; x++) { + for (y = 0; y < DVONN_BOARD_X_SIZE; y++) { + if (! dvonn_board_cell_occupied (board, x, y)) + continue; + if (! (board->cells[x][y].type == (dvonn_cell_type_t) board->player)) + continue; + height = board->cells[x][y].height; + if (dvonn_board_move_legal (board, x, y, + x + height, y, &error)) + return TRUE; + if (dvonn_board_move_legal (board, x, y, + x - height, y, &error)) + return TRUE; + if (dvonn_board_move_legal (board, x, y, + x, y + height, &error)) + return TRUE; + if (dvonn_board_move_legal (board, x, y, + x, y - height, &error)) + return TRUE; + if (dvonn_board_move_legal (board, x, y, + x + height, y - height, &error)) + return TRUE; + if (dvonn_board_move_legal (board, x, y, + x - height, y + height, &error)) + return TRUE; + } + } + return FALSE; +} + + +static dvonn_phase_t dvonn_board_next_player (dvonn_board_t *board) { if (board->player == DVONN_PLAYER_BLACK) board->player = DVONN_PLAYER_WHITE; else board->player = DVONN_PLAYER_BLACK; -} -int -dvonn_board_pass (dvonn_board_t *board) -{ - /* XXX: Should check here and only allow a pass if there are - * no legal moves. */ - - dvonn_board_next_player (board); + /* Only look for legal moves during the movement phase. */ + if (board->phase != DVONN_PHASE_MOVEMENT) + return board->phase; + + if (! dvonn_board_player_has_legal_move (board)) { + if (board->player == DVONN_PLAYER_BLACK) + board->player = DVONN_PLAYER_WHITE; + else + board->player = DVONN_PLAYER_BLACK; + + if (! dvonn_board_player_has_legal_move (board)) + { + int x, y; + dvonn_cell_t *cell; + + board->phase = DVONN_PHASE_GAME_OVER; + + /* Compute final score. */ + for (x = 0; x < DVONN_BOARD_X_SIZE; x++) { + for (y = 0; y < DVONN_BOARD_Y_SIZE; y++) { + if (dvonn_board_cell_occupied (board, x, y)) + { + cell = &board->cells[x][y]; + if (cell->type == DVONN_CELL_RED) + continue; + board->score[cell->type] += cell->height; + } + } + } + } + } - return TRUE; + return board->phase; } int diff --git a/dvonn-board.h b/dvonn-board.h index 7192301..a150b25 100644 --- a/dvonn-board.h +++ b/dvonn-board.h @@ -53,7 +53,8 @@ typedef struct { typedef enum { DVONN_PHASE_PLACEMENT, - DVONN_PHASE_MOVEMENT + DVONN_PHASE_MOVEMENT, + DVONN_PHASE_GAME_OVER } dvonn_phase_t; typedef struct { @@ -61,6 +62,7 @@ typedef struct { dvonn_phase_t phase; dvonn_player_t player; int moves; + int score[2]; /* index by dvonn_player_t */ } dvonn_board_t; /* Initialize a board for a new game of DVONN. */ @@ -88,12 +90,6 @@ dvonn_board_move (dvonn_board_t *board, int x2, int y2, char **error); -/* Pass rather than moving, allowing the turn to pass to the - * opponent. This should only be allowed if there are no legal moves, - * but that is not yet enforced. Returns TRUE if the pass succeeds. */ -int -dvonn_board_pass (dvonn_board_t *board); - /* Is the cell at (x,y) occupied by a piece. Returns FALSE for all * out-of-bounds coordinates. */ dvonn_bool_t diff --git a/dvonn.c b/dvonn.c index fccbfbc..c1762ed 100644 --- a/dvonn.c +++ b/dvonn.c @@ -177,13 +177,6 @@ on_button_press_event (GtkWidget *widget, if (event->type >= GDK_2BUTTON_PRESS) return TRUE; - /* Right-click means pass, (yes, it would be better to add some - * actual UI elements... */ - if (event->button == 3) { - dvonn_board_pass (&game->board); - return TRUE; - } - x = event->x; y = event->y; layout_device_to_board (layout, &x, &y); @@ -373,12 +366,39 @@ on_expose_event_draw (GtkWidget *widget, pango_font_description_set_family (game->font, DVONN_FONT); pango_font_description_set_absolute_size (game->font, DVONN_FONT_SIZE * PANGO_SCALE); } - to_move = _create_layout_printf (cr, game->font, - "%s to %s.", - game->board.player == DVONN_PLAYER_WHITE ? - "White" : "Black", - game->board.phase == DVONN_PHASE_PLACEMENT ? - "place" : "move"); + if (game->board.phase == DVONN_PHASE_GAME_OVER) { + if (game->board.score[DVONN_PLAYER_WHITE] > + game->board.score[DVONN_PLAYER_BLACK]) + { + to_move = _create_layout_printf (cr, game->font, + "White wins (%d to %d)\n", + game->board.score[DVONN_PLAYER_WHITE], + game->board.score[DVONN_PLAYER_BLACK]); + } + else if (game->board.score[DVONN_PLAYER_BLACK] > + game->board.score[DVONN_PLAYER_WHITE]) + { + to_move = _create_layout_printf (cr, game->font, + "Black wins (%d to %d)\n", + game->board.score[DVONN_PLAYER_BLACK], + game->board.score[DVONN_PLAYER_WHITE]); + } + else + { + to_move = _create_layout_printf (cr, game->font, + "Tie game (%d to %d)\n", + game->board.score[DVONN_PLAYER_WHITE], + game->board.score[DVONN_PLAYER_BLACK]); + + } + } else { + to_move = _create_layout_printf (cr, game->font, + "%s to %s.", + game->board.player == DVONN_PLAYER_WHITE ? + "White" : "Black", + game->board.phase == DVONN_PHASE_PLACEMENT ? + "place" : "move"); + } cairo_move_to (cr, 2, 2); if (game->board.player == DVONN_PLAYER_WHITE) cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); -- 2.43.0