From 74df2492e8c32df37d886dec4baf9344dc6b8cff Mon Sep 17 00:00:00 2001
From: Carl Worth <cworth@cworth.org>
Date: Thu, 5 Mar 2009 08:50:59 -0800
Subject: [PATCH] Enforce legal moves

All the checks for legal moves are now enforced, (including not
even selecting a piece if it is surrounded). Basically all that's
missing now is elimination of disconnected pieces, (and the
ability to pass when there is no available move).
---
 dvonn-board.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++---
 dvonn-board.h | 13 +++++++++
 dvonn.c       | 18 ++++++++-----
 3 files changed, 95 insertions(+), 10 deletions(-)

diff --git a/dvonn-board.c b/dvonn-board.c
index 4d09e13..b6b36e5 100644
--- a/dvonn-board.c
+++ b/dvonn-board.c
@@ -82,12 +82,50 @@ dvonn_board_init (dvonn_board_t *board)
     board->moves = 0;
 }
 
+dvonn_bool_t
+dvonn_board_cell_occupied (dvonn_board_t *board,
+			   int x, int y)
+{
+    if (x < 0 || x >= DVONN_BOARD_X_SIZE ||
+	y < 0 || y >= DVONN_BOARD_Y_SIZE)
+    {
+	return FALSE;
+    }
+
+    if (board->cells[x][y].type == DVONN_CELL_INVALID ||
+	board->cells[x][y].type == DVONN_CELL_EMPTY)
+    {
+	return FALSE;
+    }
+
+    return TRUE;
+}
+
+dvonn_bool_t
+dvonn_board_cell_surrounded (dvonn_board_t *board,
+			     int x, int y)
+{
+    int surround_count;
+
+    surround_count =
+	dvonn_board_cell_occupied (board, x - 1, y) +
+	dvonn_board_cell_occupied (board, x + 1, y) +
+	dvonn_board_cell_occupied (board, x, y - 1) +
+	dvonn_board_cell_occupied (board, x, y + 1) +
+	dvonn_board_cell_occupied (board, x + 1, y - 1) +
+	dvonn_board_cell_occupied (board, x - 1, y + 1);
+
+    return (surround_count == 6);
+}
+
 static dvonn_bool_t
 dvonn_board_move_legal (dvonn_board_t *board,
 			int x1, int y1,
 			int x2, int y2,
 			char **error)
 {
+    int distance;
+
     if (x1 < 0 || x1 >= DVONN_BOARD_X_SIZE ||
 	y1 < 0 || y1 >= DVONN_BOARD_Y_SIZE ||
 	x2 < 0 || x2 >= DVONN_BOARD_X_SIZE ||
@@ -97,22 +135,50 @@ dvonn_board_move_legal (dvonn_board_t *board,
 	return FALSE;
     }
 
-    if (board->cells[x1][y1].type == DVONN_CELL_INVALID) {
+    if (board->cells[x1][y1].type == DVONN_CELL_INVALID ||
+	board->cells[x2][y2].type == DVONN_CELL_INVALID)
+    {
 	*error = "Not a valid board space";
 	return FALSE;
     }
 
     if (board->cells[x1][y1].type == DVONN_CELL_EMPTY) {
-	*error = "There is no piece there to move";
+	*error = "There are no pieces there to move";
+	return FALSE;
+    }
+
+    if (dvonn_board_cell_surrounded (board, x1, y1)) {
+	*error = "You cannot move a piece that is surrounded";
 	return FALSE;
     }
 
     if (board->cells[x1][y1].type != board->player) {
-	*error = "You cannot move your opponent's piece";
+	*error = "You cannot move your opponent's stack";
 	return FALSE;
     }
 
-    /* XXX: Need to code up DVONN-legal move calculation here. */
+    if (board->cells[x2][y2].type == DVONN_CELL_EMPTY) {
+	*error = "You cannot move to an empty space";
+	return FALSE;
+    }
+
+    /* Move must be in a straight line, which in our array is
+     * horizontal, vertical, or one of the diagonals. */
+    if (x2 == x1)
+	distance = abs (y2 - y1);
+    else if (y2 == y1)
+	distance = abs (x2 - x1);
+    else if ((x2 - x1) == - (y2 - y1))
+	distance = abs (x2 - x1);
+    else {
+	*error = "Move is not in a straight line";
+	return FALSE;
+    }
+
+    if (distance != board->cells[x1][y1].height) {
+	*error = "Move distance is not the same as stack height";
+	return FALSE;
+    }
 
     return TRUE;
 }
diff --git a/dvonn-board.h b/dvonn-board.h
index 2971a27..66464d8 100644
--- a/dvonn-board.h
+++ b/dvonn-board.h
@@ -88,4 +88,17 @@ dvonn_board_move (dvonn_board_t *board,
 		int x2, int y2,
 		char **error);
 
+/* Is the cell at (x,y) occupied by a piece. Returns FALSE for all
+ * out-of-bounds coordinates. */
+dvonn_bool_t
+dvonn_board_cell_occupied (dvonn_board_t *board,
+			   int x, int y);
+
+/* Is the cell at (x,y) surrounded by other pieces, (such that it is
+ * not legal for a piece at (x,y) to move. */
+dvonn_bool_t
+dvonn_board_cell_surrounded (dvonn_board_t *board,
+			     int x, int y);
+
+
 #endif
diff --git a/dvonn.c b/dvonn.c
index 806a8e6..8ac72b1 100644
--- a/dvonn.c
+++ b/dvonn.c
@@ -157,6 +157,10 @@ on_button_press_event (GtkWidget	*widget,
     int x, y;
     char *error;
 
+    /* Ignore double and triple clicks. */
+    if (event->type >= GDK_2BUTTON_PRESS)
+	return TRUE;
+
     x = event->x;
     y = event->y;
     layout_device_to_board (layout, &x, &y);
@@ -185,12 +189,14 @@ on_button_press_event (GtkWidget	*widget,
     }
 
     if (! game->has_selected) {
-	if (game->board.cells[x][y].type == game->board.player) {
-	    game->has_selected = TRUE;
-	    game->selected_x = x;
-	    game->selected_y = y;
-	    dvonn_game_update_windows (game);
-	}
+	if (game->board.cells[x][y].type == game->board.player &&
+	    ! dvonn_board_cell_surrounded (&game->board, x, y))
+	    {
+		    game->has_selected = TRUE;
+		    game->selected_x = x;
+		    game->selected_y = y;
+		    dvonn_game_update_windows (game);
+	    }
 	return TRUE;
     }
 
-- 
2.45.2