src/game.c

changeset 19
6a26114297a1
parent 18
6008840b859e
child 21
2e5846019b4f
equal deleted inserted replaced
18:6008840b859e 19:6a26114297a1
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 * 27 *
28 */ 28 */
29 29
30 #include "game.h" 30 #include "game.h"
31 #include "network.h"
31 #include "input.h" 32 #include "input.h"
32 #include "rules/rules.h"
33 #include <ncurses.h> 33 #include <ncurses.h>
34 #include <string.h> 34 #include <string.h>
35 35
36 static const uint8_t boardx = 10, boardy = 10; 36 static const uint8_t boardx = 10, boardy = 10;
37
38 static uint8_t getpiecechr(uint8_t piece) {
39 switch (piece & PIECE_MASK) {
40 case ROOK: return 'R';
41 case KNIGHT: return 'N';
42 case BISHOP: return 'B';
43 case QUEEN: return 'Q';
44 case KING: return 'K';
45 default: return '\0';
46 }
47 }
48
49 /**
50 * Maps a character to a piece.
51 *
52 * Does not work for pawns, since they don't have a character.
53 *
54 * @param c one of R,N,B,Q,K
55 * @return numeric value for the specified piece
56 */
57 static uint8_t getpiece(char c) {
58 switch (c) {
59 case 'R': return ROOK;
60 case 'N': return KNIGHT;
61 case 'B': return BISHOP;
62 case 'Q': return QUEEN;
63 case 'K': return KING;
64 default: return 0;
65 }
66 }
67
68 /**
69 * Guesses the location of a piece for short algebraic notation.
70 *
71 * @param board the current state of the board
72 * @param move the move date to operate on
73 * @return status code (see rules/rules.h for the codes)
74 */
75 static int getlocation(Board board, Move *move) {
76 uint8_t piece = move->piece & PIECE_MASK;
77 switch (piece) {
78 case PAWN: return pawn_getlocation(board, move);
79 case ROOK: return rook_getlocation(board, move);
80 case KNIGHT: return knight_getlocation(board, move);
81 case BISHOP: return bishop_getlocation(board, move);
82 case QUEEN: return queen_getlocation(board, move);
83 case KING: return king_getlocation(board, move);
84 default: return INVALID_MOVE_SYNTAX;
85 }
86 }
87
88 37
89 static void draw_board(Board board, MoveListRoot *movelist, uint8_t mycolor) { 38 static void draw_board(Board board, MoveListRoot *movelist, uint8_t mycolor) {
90 39
91 for (uint8_t y = 0 ; y < 8 ; y++) { 40 for (uint8_t y = 0 ; y < 8 ; y++) {
92 for (uint8_t x = 0 ; x < 8 ; x++) { 41 for (uint8_t x = 0 ; x < 8 ; x++) {
156 logelem = logelem->next; 105 logelem = logelem->next;
157 } 106 }
158 } 107 }
159 } 108 }
160 109
161 /**
162 * Applies a move and deletes captured pieces.
163 *
164 * @param board the current board state
165 * @param move the move to apply
166 */
167 static void apply_move(Board board, Move *move) {
168 uint8_t piece = move->piece & PIECE_MASK;
169 uint8_t color = move->piece & COLOR_MASK;
170
171 /* en passant capture */
172 if (move->capture && piece == PAWN &&
173 mdst(board, move) == 0) {
174 board[move->fromrow][move->tofile] = 0;
175 }
176
177 /* remove old en passant threats */
178 for (uint8_t file = 0 ; file < 8 ; file++) {
179 board[3][file] &= ~ENPASSANT_THREAT;
180 board[4][file] &= ~ENPASSANT_THREAT;
181 }
182
183 /* add new en passant threat */
184 if (piece == PAWN && (
185 (move->fromrow == 1 && move->torow == 3) ||
186 (move->fromrow == 6 && move->torow == 4))) {
187 move->piece |= ENPASSANT_THREAT;
188 }
189
190 /* move (and maybe capture or promote) */
191 msrc(board, move) = 0;
192 if (move->promotion) {
193 mdst(board, move) = move->promotion;
194 } else {
195 mdst(board, move) = move->piece;
196 }
197
198 /* castling */
199 if (piece == KING &&
200 move->fromfile == fileidx('e')) {
201
202 if (move->tofile == fileidx('g')) {
203 board[move->torow][fileidx('h')] = 0;
204 board[move->torow][fileidx('f')] = color|ROOK;
205 } else if (move->tofile == fileidx('c')) {
206 board[move->torow][fileidx('a')] = 0;
207 board[move->torow][fileidx('d')] = color|ROOK;
208 }
209 }
210 }
211
212 /**
213 * Validates move by applying chess rules.
214 * @param board the current board state
215 * @param move the move to validate
216 * @return TRUE, if the move complies to chess rules, FALSE otherwise
217 */
218 static _Bool validate_move(Board board, Move *move) {
219 _Bool result;
220
221 /* validate indices (don't trust opponent) */
222 if (!chkidx(move)) {
223 return FALSE;
224 }
225
226 /* does piece exist */
227 result = msrc(board, move) == move->piece;
228
229 /* can't capture own pieces */
230 if ((mdst(board, move) & COLOR_MASK) == (move->piece & COLOR_MASK)) {
231 return FALSE;
232 }
233
234 /* validate individual rules */
235 switch (move->piece & PIECE_MASK) {
236 case PAWN:
237 result = result && pawn_chkrules(board, move);
238 result = result && !pawn_isblocked(board, move);
239 break;
240 case ROOK:
241 result = result && rook_chkrules(move);
242 result = result && !rook_isblocked(board, move);
243 break;
244 case KNIGHT:
245 result = result && knight_chkrules(move);
246 result = result && !knight_isblocked(board, move);
247 break;
248 case BISHOP:
249 result = result && bishop_chkrules(move);
250 result = result && !bishop_isblocked(board, move);
251 break;
252 case QUEEN:
253 result = result && queen_chkrules(move);
254 result = result && !queen_isblocked(board, move);
255 break;
256 case KING:
257 result = result && king_chkrules(board, move);
258 result = result && !king_isblocked(board, move);
259 break;
260 default:
261 result = FALSE;
262 }
263
264 /* is piece pinned */
265 // TODO: make it so
266
267 /* correct check and checkmate flags */
268 // TODO: make it so
269
270 return result;
271 }
272
273 /**
274 * Evaluates a move syntactically and stores the move data in the specified
275 * object.
276 *
277 * @param board the current state of the board
278 * @param mycolor the color of the current player
279 * @param mstr the input string to parse
280 * @param move a pointer to object where the move data shall be stored
281 * @return status code (see rules/rules.h for the list of codes)
282 */
283 static int eval_move(Board board, uint8_t mycolor, char *mstr, Move *move) {
284 memset(move, 0, sizeof(Move));
285 move->fromfile = POS_UNSPECIFIED;
286 move->fromrow = POS_UNSPECIFIED;
287
288 size_t len = strlen(mstr);
289
290 /* evaluate check/checkmate flags */
291 if (mstr[len-1] == '+') {
292 len--; mstr[len] = '\0';
293 move->check = TRUE;
294 } else if (mstr[len-1] == '#') {
295 len--; mstr[len] = '\0';
296 move->checkmate = TRUE;
297 }
298
299 /* evaluate promotion */
300 if (len > 3 && mstr[len-2] == '=') {
301 move->promotion = getpiece(mstr[len-1]);
302 if (!move->promotion) {
303 return INVALID_MOVE_SYNTAX;
304 } else {
305 move->promotion |= mycolor;
306 len -= 2;
307 mstr[len] = 0;
308 }
309 }
310
311 if (len == 2) {
312 /* pawn move (e.g. "e4") */
313 move->piece = PAWN;
314 move->tofile = fileidx(mstr[0]);
315 move->torow = rowidx(mstr[1]);
316 } else if (len == 3) {
317 if (strcmp(mstr, "O-O") == 0) {
318 /* king side castling */
319 move->piece = KING;
320 move->fromfile = fileidx('e');
321 move->tofile = fileidx('g');
322 move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
323 } else {
324 /* move (e.g. "Nf3") */
325 move->piece = getpiece(mstr[0]);
326 move->tofile = fileidx(mstr[1]);
327 move->torow = rowidx(mstr[2]);
328 }
329
330 } else if (len == 4) {
331 move->piece = getpiece(mstr[0]);
332 if (!move->piece) {
333 move->piece = PAWN;
334 move->fromfile = fileidx(mstr[0]);
335 }
336 if (mstr[1] == 'x') {
337 /* capture (e.g. "Nxf3", "dxe5") */
338 move->capture = TRUE;
339 } else {
340 /* move (e.g. "Ndf3", "N2c3", "e2e4") */
341 if (isfile(mstr[1])) {
342 move->fromfile = fileidx(mstr[1]);
343 if (move->piece == PAWN) {
344 move->piece = 0;
345 }
346 } else {
347 move->fromrow = rowidx(mstr[1]);
348 }
349 }
350 move->tofile = fileidx(mstr[2]);
351 move->torow = rowidx(mstr[3]);
352 } else if (len == 5) {
353 if (strcmp(mstr, "O-O-O") == 0) {
354 /* queen side castling "O-O-O" */
355 move->piece = KING;
356 move->fromfile = fileidx('e');
357 move->tofile = fileidx('c');
358 move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
359 } else {
360 move->piece = getpiece(mstr[0]);
361 if (mstr[2] == 'x') {
362 move->capture = TRUE;
363 if (move->piece) {
364 /* capture (e.g. "Ndxf3") */
365 move->fromfile = fileidx(mstr[1]);
366 } else {
367 /* long notation capture (e.g. "e5xf6") */
368 move->piece = PAWN;
369 move->fromfile = fileidx(mstr[0]);
370 move->fromrow = rowidx(mstr[1]);
371 }
372 } else {
373 /* long notation move (e.g. "Nc5a4") */
374 move->fromfile = fileidx(mstr[1]);
375 move->fromrow = rowidx(mstr[2]);
376 }
377 move->tofile = fileidx(mstr[3]);
378 move->torow = rowidx(mstr[4]);
379 }
380 } else if (len == 6) {
381 /* long notation capture (e.g. "Nc5xf3") */
382 if (mstr[3] == 'x') {
383 move->capture = TRUE;
384 move->piece = getpiece(mstr[0]);
385 move->fromfile = fileidx(mstr[1]);
386 move->fromrow = rowidx(mstr[2]);
387 move->tofile = fileidx(mstr[4]);
388 move->torow = rowidx(mstr[5]);
389 }
390 }
391
392
393 if (move->piece) {
394 if (move->piece == PAWN && move->torow == (mycolor==WHITE?7:0)
395 && !move->promotion) {
396 return NEED_PROMOTION;
397 }
398
399 move->piece |= mycolor;
400 if (move->fromfile == POS_UNSPECIFIED
401 || move->fromrow == POS_UNSPECIFIED) {
402 return getlocation(board, move);
403 } else {
404 return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION;
405 }
406 } else {
407 return INVALID_MOVE_SYNTAX;
408 }
409 }
410 110
411 static int sendmove(Board board, MoveListRoot *movelist, 111 static int sendmove(Board board, MoveListRoot *movelist,
412 uint8_t mycolor, int opponent) { 112 uint8_t mycolor, int opponent) {
413 113
414 const size_t buflen = 8; 114 const size_t buflen = 8;

mercurial