]> git.cworth.org Git - dvonn/blob - dvonn-board.c
Add visual indication for non-red stacks containing a red piece
[dvonn] / dvonn-board.c
1 /*
2  * Copyright (C) 2009 Carl Worth
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see http://www.gnu.org/licenses/ .
16  *
17  * Author: Carl Worth <cworth@cworth.org>
18  */
19
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <assert.h>
23
24 #include <glib.h>
25
26 #include "dvonn-board.h"
27
28 /* Just a diagram to help start thinking about data structures:
29  *
30  * Played/drawn as:
31  *
32  *   1 ○ ○ ○ ○ ○ ○ ○ ○ ○
33  *  2 ○ ● ● ○ ○ ○ ○ ○ ○ ○
34  * 3 ○ ● ○ ● ○ ○ ○ ○ ○ ○ ○
35  *  4 ○ ● ● ○ ○ ○ ○ ○ ○ ○ K
36  *   5 ○ ○ ○ ○ ○ ○ ○ ○ ○ J
37  *      A B C D E F G H I
38  *
39  * Stored as:
40  *
41  * 1 x x ○ ○ ○ ○ ○ ○ ○ ○ ○
42  * 2 x ○ ● ● ○ ○ ○ ○ ○ ○ ○
43  * 3 ○ ● ○ ● ○ ○ ○ ○ ○ ○ ○
44  * 4 ○ ● ● ○ ○ ○ ○ ○ ○ ○ x
45  * 5 ○ ○ ○ ○ ○ ○ ○ ○ ○ x x
46  *   A B C D E F G H I J K
47  *
48  * With connections as:
49  *
50  *         C2  D2
51  *          | /
52  *  B3 <-> C3 <-> D3
53  *        / |
54  *      B2 C4
55  */
56
57 void
58 dvonn_board_init (dvonn_board_t *board)
59 {
60     int x, y;
61
62     for (x = 0; x < DVONN_BOARD_X_SIZE; x++) {
63         for (y = 0; y < DVONN_BOARD_Y_SIZE; y++) {
64             board->cells[x][y].type = DVONN_CELL_EMPTY;
65             board->cells[x][y].height = 0;
66             board->cells[x][y].contains_red = FALSE;
67         }
68     }
69
70     /* Cut out the unplayable "corners" of the board. */
71     for (x = 0; x < DVONN_BOARD_Y_SIZE / 2; x++) {
72         for (y = 0; y < (DVONN_BOARD_Y_SIZE / 2) - x; y++) {
73             board->cells[x][y].type = DVONN_CELL_INVALID;
74             board->cells
75                 [DVONN_BOARD_X_SIZE-1-x]
76                 [DVONN_BOARD_Y_SIZE-1-y].type = DVONN_CELL_INVALID;
77         }
78     }
79
80     board->phase = DVONN_PHASE_PLACEMENT;
81     board->player = DVONN_PLAYER_WHITE;
82     board->moves = 0;
83 }
84
85 static dvonn_bool_t
86 dvonn_board_move_legal (dvonn_board_t *board,
87                         int x1, int y1,
88                         int x2, int y2,
89                         char **error)
90 {
91     if (x1 < 0 || x1 >= DVONN_BOARD_X_SIZE ||
92         y1 < 0 || y1 >= DVONN_BOARD_Y_SIZE ||
93         x2 < 0 || x2 >= DVONN_BOARD_X_SIZE ||
94         y2 < 0 || y2 >= DVONN_BOARD_Y_SIZE)
95     {
96         *error = "Invalid coordinates (not on board)";
97         return FALSE;
98     }
99
100     if (board->cells[x1][y1].type == DVONN_CELL_INVALID) {
101         *error = "Not a valid board space";
102         return FALSE;
103     }
104
105     if (board->cells[x1][y1].type == DVONN_CELL_EMPTY) {
106         *error = "There is no piece there to move";
107         return FALSE;
108     }
109
110     if (board->cells[x1][y1].type != board->player) {
111         *error = "You cannot move your opponent's piece";
112         return FALSE;
113     }
114
115     /* XXX: Need to code up DVONN-legal move calculation here. */
116
117     return TRUE;
118 }
119
120 static void
121 dvonn_board_next_player (dvonn_board_t *board)
122 {
123     if (board->player == DVONN_PLAYER_BLACK)
124         board->player = DVONN_PLAYER_WHITE;
125     else
126         board->player = DVONN_PLAYER_BLACK;
127 }
128
129 int
130 dvonn_board_place (dvonn_board_t *board,
131                    int x, int y,
132                    char **error)
133 {
134     if (board->phase != DVONN_PHASE_PLACEMENT) {
135         *error = "Cannot place outside of placement phase";
136         return FALSE;
137     }
138
139     if (board->cells[x][y].type != DVONN_CELL_EMPTY) {
140         *error = "Cannot place on an occupied space";
141         return FALSE;
142     }
143
144     if (board->moves < 3) {
145         board->cells[x][y].type = DVONN_CELL_RED;
146         board->cells[x][y].contains_red = TRUE;
147     } else if (board->moves % 2) {
148         board->cells[x][y].type = DVONN_CELL_BLACK;
149     } else {
150         board->cells[x][y].type = DVONN_CELL_WHITE;
151     }
152
153     board->cells[x][y].height = 1;
154
155     board->moves++;
156
157     if (board->moves == 49) {
158         board->phase = DVONN_PHASE_MOVEMENT;
159         board->moves = 0;
160     }
161
162     return TRUE;
163 }
164
165 int
166 dvonn_board_move (dvonn_board_t *board,
167                   int x1, int y1,
168                   int x2, int y2,
169                   char **error)
170 {
171     if (board->phase != DVONN_PHASE_MOVEMENT) {
172         *error = "Cannot move outside of placement phase";
173         return FALSE;
174     }
175
176     if (! dvonn_board_move_legal (board, x1, y1, x2, y2, error))
177         return FALSE;
178
179     board->cells[x2][y2].height += board->cells[x1][y1].height;
180     board->cells[x2][y2].type = board->cells[x1][y1].type;
181     board->cells[x2][y2].contains_red |= board->cells[x1][y1].contains_red;
182
183     board->cells[x1][y1].type = DVONN_CELL_EMPTY;
184     board->cells[x1][y1].height = 0;
185     board->cells[x1][y1].contains_red = FALSE;
186
187     dvonn_board_next_player (board);
188
189     return TRUE;
190 }