]> git.cworth.org Git - dvonn/commitdiff
Implement automatic pass (when there is no legal move) and end-of-game master
authorCarl Worth <cworth@cworth.org>
Thu, 5 Dec 2013 01:35:07 +0000 (17:35 -0800)
committerCarl Worth <cworth@cworth.org>
Fri, 24 Apr 2020 21:30:19 +0000 (14:30 -0700)
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
dvonn-board.h
dvonn.c

index eeab83076294649ebe0ccdaa846ca59307eef1e0..c78905ee3910b521ae851dd49a9fa265ce9970e9 100644 (file)
@@ -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
index 71923011e0ce07611de88a10454009e4d6f0137a..a150b2541f7fdc5fe9566fded72662d6bec196d0 100644 (file)
@@ -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 fccbfbc5b6ee5d1fff71dc161cf0c005453167df..c1762ed19be159f67832ce71fe032e85e0331ee0 100644 (file)
--- 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);