Sat, 22 Mar 2014 16:25:49 +0100
implemented castling (without validation)
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2014 Mike Becker. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
30 #include "game.h"
31 #include "input.h"
32 #include <ncurses.h>
33 #include <string.h>
35 static const uint8_t boardx = 10, boardy = 10;
37 static void draw_board(Board board, uint8_t mycolor) {
39 for (uint8_t y = 0 ; y < 8 ; y++) {
40 for (uint8_t x = 0 ; x < 8 ; x++) {
41 uint8_t col = board[y][x] & COLOR_MASK;
42 uint8_t piece = board[y][x] & PIECE_MASK;
43 char piecec = ' ';
44 switch (piece) {
45 case PAWN: piecec = 'P'; break;
46 case ROOK: piecec = 'R'; break;
47 case KNIGHT: piecec = 'N'; break;
48 case BISHOP: piecec = 'B'; break;
49 case QUEEN: piecec = 'Q'; break;
50 case KING: piecec = 'K'; break;
51 }
53 attrset((col == WHITE ? A_BOLD : A_DIM) |
54 COLOR_PAIR((y&1)==(x&1) ? COL_WB : COL_BW));
56 int cy = mycolor == WHITE ? boardy-y : boardy-7+y;
57 int cx = mycolor == WHITE ? boardx+x*3 : boardx+21-x*3;
58 mvaddch(cy, cx, ' ');
59 mvaddch(cy, cx+1, piecec);
60 mvaddch(cy, cx+2, ' ');
61 }
62 }
64 attrset(A_NORMAL);
65 for (uint8_t i = 0 ; i < 8 ; i++) {
66 int x = mycolor == WHITE ? boardx+i*3+1 : boardx+22-i*3;
67 int y = mycolor == WHITE ? boardy-i : boardy-7+i;
68 mvaddch(boardy+1, x, 'a'+i);
69 mvaddch(y, boardx-2, '1'+i);
70 }
71 }
73 static void apply_move(Board board, Move *move) {
74 board[move->fromrow][move->fromfile] = 0;
75 // TODO: care for en passant capture
76 board[move->torow][move->tofile] = move->piece;
78 /* castling */
79 if ((move->piece & PIECE_MASK) == KING &&
80 move->fromfile == fileidx('e')) {
81 uint8_t color = move->piece & COLOR_MASK;
83 if (move->tofile == fileidx('g')) {
84 board[move->torow][fileidx('h')] = 0;
85 board[move->torow][fileidx('f')] = color|ROOK;
86 } else if (move->tofile == fileidx('c')) {
87 board[move->torow][fileidx('a')] = 0;
88 board[move->torow][fileidx('d')] = color|ROOK;
89 }
90 }
91 }
93 static _Bool validate_move(Board board, uint8_t mycolor, Move *move) {
94 _Bool result = TRUE;
96 /* does piece exist */
97 result &= board[move->fromrow][move->fromfile] == move->piece;
99 /* does move comply to rules */
100 // TODO: make it so
102 /* is piece blocked */
103 // TODO: make it so
105 /* is piece pinned */
106 // TODO: make it so
108 return result;
109 }
111 static _Bool eval_move(Board board, uint8_t mycolor, char *mstr, Move *move) {
112 memset(move, 0, sizeof(Move));
114 size_t len = strlen(mstr);
116 /* remove check */
117 if (mstr[len-1] == '+') {
118 len--; mstr[len] = '\0';
119 move->check = TRUE;
120 }
122 if (len == 2) {
123 /* pawn move (e.g. "e4") */
124 if (isfile(mstr[0]) && isrow(mstr[1])) {
125 move->piece = PAWN;
126 move->fromfile = move->tofile = fileidx(mstr[0]);
127 move->torow = rowidx(mstr[1]);
128 move->fromrow = rowidx(mstr[1]) + (mycolor == WHITE ? -1 : 1);
129 if (move->fromrow > 6) {
130 move->piece = 0;
131 } else {
132 /* advanced first move */
133 if (move->fromrow == (mycolor == WHITE ? 2 : 5) &&
134 board[move->fromrow][move->fromfile] != (mycolor|PAWN)) {
136 move->fromrow += (mycolor == WHITE ? -1 : 1);
137 if (move->fromrow > 6) {
138 move->piece = 0;
139 }
140 }
141 }
142 }
143 } else if (len == 3) {
144 if (strcmp(mstr, "O-O") == 0) {
145 /* king side castling */
146 move->piece = KING;
147 move->fromfile = fileidx('e');
148 move->tofile = fileidx('g');
149 move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
150 } else {
151 /* unambiguous move (e.g. "Nf3") */
152 }
154 } else if (len == 4) {
155 /* ambiguous move (e.g. "Ndf3") */
157 /* unambiguous capture (e.g. "Nxf3", "dxe5") */
159 } else if (len == 5) {
160 if (strcmp(mstr, "O-O-O") == 0) {
161 /* queen side castling "O-O-O" */
162 move->piece = KING;
163 move->fromfile = fileidx('e');
164 move->tofile = fileidx('c');
165 move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
166 } else {
167 /* ambiguous capture (e.g. "Ndxf3") */
169 /* long notation move (e.g. "Nc5a4") */
171 /* long notation capture (e.g. "e5xf6") */
172 }
173 } else if (len == 6) {
174 /* long notation capture (e.g. "Nc5xf3") */
175 }
177 if (move->piece) {
178 move->piece |= mycolor;
179 return TRUE;
180 } else {
181 return FALSE;
182 }
183 }
185 static int sendmove(Board board, uint8_t mycolor, int opponent) {
186 const size_t buflen = 8;
187 char movestr[buflen];
188 _Bool remisrejected = FALSE;
190 while (1) {
191 move(boardy+3, 0);
192 if (remisrejected) {
193 printw(
194 "Use chess notation to enter your move.\n"
195 "Remis offer rejected - type 'surr' to surrender. \n\n"
196 "Type your move: ");
197 } else {
198 printw(
199 "Use chess notation to enter your move.\n"
200 "Or type 'surr' to surrender or 'remis' to offer remis.\n\n"
201 "Type your move: ");
202 }
203 clrtoeol();
204 refresh();
205 getnstr(movestr, buflen);
207 if (strncmp(movestr, "surr", buflen) == 0) {
208 printw("You surrendered!");
209 refresh();
210 net_send_code(opponent, NETCODE_SURRENDER);
211 return 1;
212 } else if (strncmp(movestr, "remis", buflen) == 0) {
213 if (!remisrejected) {
214 net_send_code(opponent, NETCODE_REMIS);
215 printw("Remis offer sent - waiting for acceptance...");
216 refresh();
217 if (net_recieve_code(opponent) == NETCODE_ACCEPT) {
218 printw("\rRemis accepted!");
219 clrtoeol();
220 refresh();
221 return 1;
222 } else {
223 remisrejected = TRUE;
224 }
225 }
226 } else {
227 Move move;
228 if (eval_move(board, mycolor, movestr, &move)) {
229 net_send_code(opponent, NETCODE_MOVE);
230 net_send_data(opponent, &move, sizeof(Move));
231 if (net_recieve_code(opponent) == NETCODE_ACCEPT) {
232 apply_move(board, &move);
233 return 0;
234 } else {
235 printw("Invalid move.");
236 clrtoeol();
237 }
238 } else {
239 printw("Can't interpret move - please use algebraic notation.");
240 }
241 }
242 }
243 }
245 static int recvmove(Board board, uint8_t mycolor, int opponent) {
247 while (1) {
248 move(boardy+3, 0);
249 printw("Awaiting opponent move...");
250 clrtoeol();
251 refresh();
253 // TODO: nonblocking
254 uint32_t code = net_recieve_code(opponent);
256 Move move;
257 switch (code) {
258 case NETCODE_SURRENDER:
259 printw("\rYour opponent surrendered!");
260 clrtoeol();
261 return 1;
262 case NETCODE_REMIS:
263 if (prompt_yesno(
264 "\rYour opponent offers remis - do you accept")) {
265 printw("\rRemis accepted!");
266 clrtoeol();
267 net_send_code(opponent, NETCODE_ACCEPT);
268 return 1;
269 } else {
270 net_send_code(opponent, NETCODE_DECLINE);
271 }
272 break;
273 case NETCODE_MOVE:
274 net_recieve_data(opponent, &move, sizeof(Move));
275 if (validate_move(board, mycolor, &move)) {
276 apply_move(board, &move);
277 net_send_code(opponent, NETCODE_ACCEPT);
278 return 0;
279 } else {
280 net_send_code(opponent, NETCODE_DECLINE);
281 }
282 }
283 }
284 }
286 void game_start(Settings *settings, int opponent) {
287 _Bool myturn = is_server(settings) ==
288 (settings->gameinfo.servercolor == WHITE);
289 uint8_t mycolor = myturn ? WHITE:BLACK;
291 _Bool running;
293 Board board = {
294 {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK},
295 {WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN},
296 {0, 0, 0, 0, 0, 0, 0, 0},
297 {0, 0, 0, 0, 0, 0, 0, 0},
298 {0, 0, 0, 0, 0, 0, 0, 0},
299 {0, 0, 0, 0, 0, 0, 0, 0},
300 {BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN},
301 {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK}
302 };
304 do {
305 clear();
306 draw_board(board, mycolor);
307 if (myturn) {
308 running = !sendmove(board, mycolor, opponent);
309 } else {
310 running = !recvmove(board, mycolor, opponent);
311 flushinp(); // flush any input the user hacked in while waiting
312 }
313 myturn ^= 1;
314 } while (running);
316 mvaddstr(getmaxy(tchess_window)-1, 0,
317 "Game has ended. Press any key to leave...");
318 getch();
319 }