Sat, 22 Mar 2014 16:04:02 +0100
implemented simple pawn movement
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;
77 }
79 static _Bool validate_move(Board board, uint8_t mycolor, Move *move) {
80 _Bool result = TRUE;
82 /* does piece exist */
83 result &= board[move->fromrow][move->fromfile] == move->piece;
85 /* is move rule conform */
86 // TODO: make it so
88 /* is piece blocked */
89 // TODO: make it so
91 /* is piece pinned */
92 // TODO: make it so
94 return result;
95 }
97 static _Bool eval_move(Board board, uint8_t mycolor, char *movestr, Move *move) {
98 memset(move, 0, sizeof(Move));
100 size_t len = strlen(movestr);
102 /* remove check */
103 if (movestr[len-1] == '+') {
104 len--; movestr[len] = '\0';
105 move->check = TRUE;
106 }
108 if (len == 2) {
109 /* pawn move (e.g. "e4") */
110 if (isfile(movestr[0]) && isrow(movestr[1])) {
111 move->piece = PAWN;
112 move->fromfile = move->tofile = fileidx(movestr[0]);
113 move->torow = rowidx(movestr[1]);
114 move->fromrow = rowidx(movestr[1]) + (mycolor == WHITE ? -1 : 1);
115 if (move->fromrow > 6) {
116 move->piece = 0;
117 } else {
118 /* advanced first move */
119 if (move->fromrow == (mycolor == WHITE ? 2 : 5) &&
120 board[move->fromrow][move->fromfile] != (mycolor|PAWN)) {
122 move->fromrow += (mycolor == WHITE ? -1 : 1);
123 if (move->fromrow > 6) {
124 move->piece = 0;
125 }
126 }
127 }
128 }
129 } else if (len == 3) {
130 if (strcmp(movestr, "0-0") == 0) {
131 /* king side castling */
132 move->piece = KING;
133 move->fromfile = fileidx('e');
134 move->fromfile = fileidx('g');
135 move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
136 } else {
137 /* unambiguous move (e.g. "Nf3") */
138 }
140 } else if (len == 4) {
141 /* ambiguous move (e.g. "Ndf3") */
143 /* unambiguous capture (e.g. "Nxf3", "dxe5") */
145 } else if (len == 5) {
146 /* queen side castling "O-O-O" */
148 /* ambiguous capture (e.g. "Ndxf3") */
150 /* long notation move (e.g. "Nc5a4") */
152 /* long notation capture (e.g. "e5xf6") */
153 } else if (len == 6) {
154 /* long notation capture (e.g. "Nc5xf3") */
155 }
157 if (move->piece) {
158 move->piece |= mycolor;
159 return TRUE;
160 } else {
161 return FALSE;
162 }
163 }
165 static int sendmove(Board board, uint8_t mycolor, int opponent) {
166 const size_t buflen = 8;
167 char movestr[buflen];
168 _Bool remisrejected = FALSE;
170 while (1) {
171 move(boardy+3, 0);
172 if (remisrejected) {
173 printw(
174 "Use chess notation to enter your move.\n"
175 "Remis offer rejected - type 'surr' to surrender. \n\n"
176 "Type your move: ");
177 } else {
178 printw(
179 "Use chess notation to enter your move.\n"
180 "Or type 'surr' to surrender or 'remis' to offer remis.\n\n"
181 "Type your move: ");
182 }
183 clrtoeol();
184 refresh();
185 getnstr(movestr, buflen);
187 if (strncmp(movestr, "surr", buflen) == 0) {
188 printw("You surrendered!");
189 refresh();
190 net_send_code(opponent, NETCODE_SURRENDER);
191 return 1;
192 } else if (strncmp(movestr, "remis", buflen) == 0) {
193 if (!remisrejected) {
194 net_send_code(opponent, NETCODE_REMIS);
195 printw("Remis offer sent - waiting for acceptance...");
196 refresh();
197 if (net_recieve_code(opponent) == NETCODE_ACCEPT) {
198 printw("\rRemis accepted!");
199 clrtoeol();
200 refresh();
201 return 1;
202 } else {
203 remisrejected = TRUE;
204 }
205 }
206 } else {
207 Move move;
208 if (eval_move(board, mycolor, movestr, &move)) {
209 net_send_code(opponent, NETCODE_MOVE);
210 net_send_data(opponent, &move, sizeof(Move));
211 if (net_recieve_code(opponent) == NETCODE_ACCEPT) {
212 apply_move(board, &move);
213 return 0;
214 } else {
215 printw("Invalid move.");
216 clrtoeol();
217 }
218 } else {
219 printw("Can't interpret move - please use algebraic notation.");
220 }
221 }
222 }
223 }
225 static int recvmove(Board board, uint8_t mycolor, int opponent) {
227 while (1) {
228 move(boardy+3, 0);
229 printw("Awaiting opponent move...");
230 clrtoeol();
231 refresh();
233 // TODO: nonblocking
234 uint32_t code = net_recieve_code(opponent);
236 Move move;
237 switch (code) {
238 case NETCODE_SURRENDER:
239 printw("\rYour opponent surrendered!");
240 clrtoeol();
241 return 1;
242 case NETCODE_REMIS:
243 if (prompt_yesno(
244 "\rYour opponent offers remis - do you accept")) {
245 printw("\rRemis accepted!");
246 clrtoeol();
247 net_send_code(opponent, NETCODE_ACCEPT);
248 return 1;
249 } else {
250 net_send_code(opponent, NETCODE_DECLINE);
251 }
252 break;
253 case NETCODE_MOVE:
254 net_recieve_data(opponent, &move, sizeof(Move));
255 if (validate_move(board, mycolor, &move)) {
256 apply_move(board, &move);
257 net_send_code(opponent, NETCODE_ACCEPT);
258 return 0;
259 } else {
260 net_send_code(opponent, NETCODE_DECLINE);
261 }
262 }
263 }
264 }
266 void game_start(Settings *settings, int opponent) {
267 _Bool myturn = is_server(settings) ==
268 (settings->gameinfo.servercolor == WHITE);
269 uint8_t mycolor = myturn ? WHITE:BLACK;
271 _Bool running;
273 Board board = {
274 {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK},
275 {WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN},
276 {0, 0, 0, 0, 0, 0, 0, 0},
277 {0, 0, 0, 0, 0, 0, 0, 0},
278 {0, 0, 0, 0, 0, 0, 0, 0},
279 {0, 0, 0, 0, 0, 0, 0, 0},
280 {BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN},
281 {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK}
282 };
284 do {
285 clear();
286 draw_board(board, mycolor);
287 if (myturn) {
288 running = !sendmove(board, mycolor, opponent);
289 } else {
290 running = !recvmove(board, mycolor, opponent);
291 flushinp(); // flush any input the user hacked in while waiting
292 }
293 myturn ^= 1;
294 } while (running);
296 mvaddstr(getmaxy(tchess_window)-1, 0,
297 "Game has ended. Press any key to leave...");
298 getch();
299 }