src/chess/rules.h

changeset 194
619f07c95894
parent 193
d1420f5c5704
child 195
27d02ccb0cef
equal deleted inserted replaced
193:d1420f5c5704 194:619f07c95894
50 #define RULES_VIOLATED 32 50 #define RULES_VIOLATED 32
51 51
52 #if __STDC_VERSION__ < 202310L 52 #if __STDC_VERSION__ < 202310L
53 /* since #warning is also a C23 feature, the only hope is this: */ 53 /* since #warning is also a C23 feature, the only hope is this: */
54 #pragma GCC warning "Type safety for enums is only available since C23" 54 #pragma GCC warning "Type safety for enums is only available since C23"
55 #define enum_uint8_t(name) enum e##name 55 #define enum_byte(name) enum e##name
56 #define typedef_enum_uint8_t(name) typedef uint8_t name 56 #define typedef_enum_byte(name) typedef uint8_t name
57 #else 57 #else
58 #define enum_uint8_t(name) enum e##name : uint8_t 58 #define enum_byte(name) enum e##name : uint8_t
59 #define typedef_enum_uint8_t(name) typedef enum e##name name 59 #define typedef_enum_byte(name) typedef enum e##name name
60 #endif 60 #endif
61 61
62 #define ENPASSANT_THREAT 0x40u 62 #define ENPASSANT_THREAT 0x40u
63 63
64 enum_uint8_t(Color) { 64 enum_byte(Color) {
65 WHITE = 0x10u, 65 WHITE = 0x10u,
66 BLACK = 0x20u, 66 BLACK = 0x20u,
67 }; 67 };
68 typedef_enum_uint8_t(Color); 68 typedef_enum_byte(Color);
69 69
70 static inline Color opponent_color(Color color) { 70 static inline Color opponent_color(Color color) {
71 return color == WHITE ? BLACK : WHITE; 71 return color == WHITE ? BLACK : WHITE;
72 } 72 }
73 73
79 #define KNIGHT 0x03u 79 #define KNIGHT 0x03u
80 #define BISHOP 0x04u 80 #define BISHOP 0x04u
81 #define QUEEN 0x05u 81 #define QUEEN 0x05u
82 #define KING 0x06u 82 #define KING 0x06u
83 83
84 enum_uint8_t(Piece) { 84 enum_byte(Piece) {
85 WPAWN = WHITE|PAWN, 85 WPAWN = WHITE|PAWN,
86 WROOK = WHITE|ROOK, 86 WROOK = WHITE|ROOK,
87 WKNIGHT = WHITE|KNIGHT, 87 WKNIGHT = WHITE|KNIGHT,
88 WBISHOP = WHITE|BISHOP, 88 WBISHOP = WHITE|BISHOP,
89 WQUEEN = WHITE|QUEEN, 89 WQUEEN = WHITE|QUEEN,
93 BKNIGHT = BLACK|KNIGHT, 93 BKNIGHT = BLACK|KNIGHT,
94 BBISHOP = BLACK|BISHOP, 94 BBISHOP = BLACK|BISHOP,
95 BQUEEN = BLACK|QUEEN, 95 BQUEEN = BLACK|QUEEN,
96 BKING = BLACK|KING, 96 BKING = BLACK|KING,
97 }; 97 };
98 typedef_enum_uint8_t(Piece); 98 typedef_enum_byte(Piece);
99 99
100 #define POS_UNSPECIFIED 255u 100 #define POS_UNSPECIFIED 255u
101 enum_uint8_t(Row) { 101 enum_byte(Rank) {
102 RANK_1 = 0, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, 102 RANK_1 = 0, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8,
103 RANK_UNSPECIFIED = POS_UNSPECIFIED 103 RANK_UNSPECIFIED = POS_UNSPECIFIED
104 }; 104 };
105 typedef_enum_uint8_t(Row); 105 typedef_enum_byte(Rank);
106 106
107 enum_uint8_t(File) { 107 enum_byte(File) {
108 FILE_A = 0, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, 108 FILE_A = 0, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H,
109 FILE_UNSPECIFIED = POS_UNSPECIFIED 109 FILE_UNSPECIFIED = POS_UNSPECIFIED
110 }; 110 };
111 typedef_enum_uint8_t(File); 111 typedef_enum_byte(File);
112 112
113 typedef uint8_t Board[8][8]; 113 typedef uint8_t Board[8][8];
114 114
115 struct movetimeval { 115 struct movetimeval {
116 uint64_t sec; 116 uint64_t sec;
121 char string[8]; 121 char string[8];
122 struct movetimeval timestamp; /* TODO: remove this from the struct */ 122 struct movetimeval timestamp; /* TODO: remove this from the struct */
123 uint64_t movetime; /* the time for this move in microseconds */ 123 uint64_t movetime; /* the time for this move in microseconds */
124 Piece piece; 124 Piece piece;
125 File fromfile; 125 File fromfile;
126 Row fromrow; 126 Rank fromrank;
127 File tofile; 127 File tofile;
128 Row torow; 128 Rank torank;
129 Piece promotion; 129 Piece promotion;
130 bool check; /* must always be set if checkmate is set */ 130 bool check; /* must always be set if checkmate is set */
131 bool checkmate; 131 bool checkmate;
132 bool capture; 132 bool capture;
133 } Move; 133 } Move;
183 183
184 #define piece_type(piece) ((uint8_t)(piece)&PIECE_MASK) 184 #define piece_type(piece) ((uint8_t)(piece)&PIECE_MASK)
185 #define piece_color(piece) ((uint8_t)(piece)&COLOR_MASK) 185 #define piece_color(piece) ((uint8_t)(piece)&COLOR_MASK)
186 #define mkpiece(type,color) (Piece)((type)|(color)) 186 #define mkpiece(type,color) (Piece)((type)|(color))
187 187
188 #define mdst(m) (m)->torow, (m)->tofile
189 #define msrc(m) (m)->fromrow, (m)->fromfile
190
191 /** Checks if the index is specified and valid. */ 188 /** Checks if the index is specified and valid. */
192 static inline bool isidx(uint8_t idx) {return idx < 8;} 189 static inline bool isidx(uint8_t idx) {return idx < 8;}
193 /** Checks if the index is unspecified or valid. */ 190 /** Checks if the index is unspecified or valid. */
194 static inline bool isidxr(uint8_t idx) {return idx==POS_UNSPECIFIED || idx<8;} 191 static inline bool isidxr(uint8_t idx) {return idx==POS_UNSPECIFIED || idx<8;}
195 192
196 static inline bool isfile(char file) {return file >= 'a' && file <= 'h';} 193 static inline bool isfile(char file) {return file >= 'a' && file <= 'h';}
197 static inline bool isrow(char row) {return row >= '1' && row <= '8';} 194 static inline bool isrank(char rank) {return rank >= '1' && rank <= '8';}
198 195
199 static inline Row rowidx(char row) {return row-'1';} 196 static inline Rank rankidx(char rank) {return rank-'1';}
200 static inline File fileidx(char file) {return file-'a';} 197 static inline File fileidx(char file) {return file-'a';}
201 198
202 static inline char rowchr(Row row) {return (char)row+'1';} 199 static inline char rankchr(Rank rank) {return (char)rank+'1';}
203 static inline char filechr(File file) {return (char)file+'a';} 200 static inline char filechr(File file) {return (char)file+'a';}
204 201
205 202
206 static inline void enpassant_threat_add(GameState *gamestate, 203 static inline void enpassant_threat_add(GameState *gamestate,
207 Row row, File file) { 204 Rank rank, File file) {
208 gamestate->board[row][file] |= ENPASSANT_THREAT; 205 gamestate->board[rank][file] |= ENPASSANT_THREAT;
209 } 206 }
210 207
211 static inline void enpassant_threat_remove(GameState *gamestate, 208 static inline void enpassant_threat_remove(GameState *gamestate,
212 Row row, File file) { 209 Rank rank, File file) {
213 gamestate->board[row][file] &= ~ENPASSANT_THREAT; 210 gamestate->board[rank][file] &= ~ENPASSANT_THREAT;
214 } 211 }
215 212
216 static inline bool enpassant_threat_exists(const GameState *gamestate, 213 static inline bool enpassant_threat_exists(const GameState *gamestate,
217 Row row, File file) { 214 Rank rank, File file) {
218 return gamestate->board[row][file] & ENPASSANT_THREAT; 215 return gamestate->board[rank][file] & ENPASSANT_THREAT;
219 } 216 }
220 217
221 static inline bool is_game_drawn(const GameState *gamestate) { 218 static inline bool is_game_drawn(const GameState *gamestate) {
222 return gamestate->threefold || gamestate->stalemate 219 return gamestate->threefold || gamestate->stalemate
223 || gamestate->nomaterial || gamestate->remis; 220 || gamestate->nomaterial || gamestate->remis;
230 227
231 static inline bool is_check_position(const GameState *gamestate) { 228 static inline bool is_check_position(const GameState *gamestate) {
232 return gamestate->moves[gamestate->movecount - 1].check; 229 return gamestate->moves[gamestate->movecount - 1].check;
233 } 230 }
234 231
235 static inline Color field_color(Row r, File f) { 232 static inline Color field_color(Rank r, File f) {
236 return (r + f) % 2 == 0 ? BLACK : WHITE; 233 return (r + f) % 2 == 0 ? BLACK : WHITE;
237 } 234 }
238 235
239 /** 236 /**
240 * Initializes a game state and prepares the chess board. 237 * Initializes a game state and prepares the chess board.
290 287
291 /** 288 /**
292 * Returns the piece at the specified position. 289 * Returns the piece at the specified position.
293 * 290 *
294 * @param gamestate the current game state 291 * @param gamestate the current game state
295 * @param row the row 292 * @param rank the rank
296 * @param file the file 293 * @param file the file
297 * @return the piece at the specified position 294 * @return the piece at the specified position
298 */ 295 */
299 Piece piece_at(const GameState *gamestate, Row row, File file); 296 Piece piece_at(const GameState *gamestate, Rank rank, File file);
300 297
301 /** 298 /**
302 * Places a piece at the specified position in the current game state. 299 * Places a piece at the specified position in the current game state.
303 * 300 *
304 * @param gamestate the current game state 301 * @param gamestate the current game state
305 * @param row the row 302 * @param rank the rank
306 * @param file the file 303 * @param file the file
307 * @param piece the piece to place at the specified position 304 * @param piece the piece to place at the specified position
308 */ 305 */
309 void piece_set(GameState *gamestate, Row row, File file, Piece piece); 306 void piece_set(GameState *gamestate, Rank rank, File file, Piece piece);
310 307
311 /** 308 /**
312 * Removes the piece at the specified position in the current game state. 309 * Removes the piece at the specified position in the current game state.
313 * 310 *
314 * @param gamestate the current game state 311 * @param gamestate the current game state
315 * @param row the row 312 * @param rank the rank
316 * @param file the file 313 * @param file the file
317 */ 314 */
318 static inline void piece_remove(GameState *gamestate, Row row, File file) { 315 static inline void piece_remove(GameState *gamestate, Rank rank, File file) {
319 piece_set(gamestate, row, file, 0); 316 piece_set(gamestate, rank, file, 0);
320 } 317 }
321 318
322 typedef size_t(*moves_generator_func)(const GameState *gamestate, 319 typedef size_t(*moves_generator_func)(const GameState *gamestate,
323 Color c, Row r, File f, Move *moves); 320 Color c, Rank r, File f, Move *moves);
324 321
325 /** 322 /**
326 * Calculates all allowed moves for a specific piece. 323 * Calculates all allowed moves for a specific piece.
327 * 324 *
328 * Use the macros for the specific pieces instead. 325 * Use the macros for the specific pieces instead.
329 * 326 *
330 * @param gamestate the current gamestate 327 * @param gamestate the current gamestate
331 * @param r the row of the piece 328 * @param r the rank of the piece
332 * @param f the file of the piece 329 * @param f the file of the piece
333 * @param moves target array for the list of moves 330 * @param moves target array for the list of moves
334 * @return the number of moves stored in the @p moves array 331 * @return the number of moves stored in the @p moves array
335 */ 332 */
336 size_t piece_moves_allowed(const GameState *gamestate, 333 size_t piece_moves_allowed(const GameState *gamestate,
337 Row r, File f, Move *moves); 334 Rank r, File f, Move *moves);
338 335
339 /** 336 /**
340 * Internal function used to filter out illegal moves. 337 * Internal function used to filter out illegal moves.
341 * 338 *
342 * Use the macros for the specific pieces instead. 339 * Use the macros for the specific pieces instead.
343 * 340 *
344 * @param gamestate the current gamestate 341 * @param gamestate the current gamestate
345 * @param c color of the piece 342 * @param c color of the piece
346 * @param r the row of the piece 343 * @param r the rank of the piece
347 * @param f the file of the piece 344 * @param f the file of the piece
348 * @param moves target array for the list of moves 345 * @param moves target array for the list of moves
349 * @param func a function that unconditionally generates the moves 346 * @param func a function that unconditionally generates the moves
350 * @return the number of moves stored in the @p moves array 347 * @return the number of moves stored in the @p moves array
351 */ 348 */
352 size_t filter_moves_allowed(const GameState *gamestate, 349 size_t filter_moves_allowed(const GameState *gamestate,
353 Color c, Row r, File f, Move *moves, moves_generator_func func); 350 Color c, Rank r, File f, Move *moves, moves_generator_func func);
354 351
355 /** 352 /**
356 * Determines a list of theoretically possible moves to the specified field. 353 * Determines a list of theoretically possible moves to the specified field.
357 * 354 *
358 * This will also list moves for pieces that are actually pinned. 355 * This will also list moves for pieces that are actually pinned.
360 * 357 *
361 * The out-parameters may both be NULL, but if any of them is set, the other 358 * The out-parameters may both be NULL, but if any of them is set, the other
362 * must be set, too. 359 * must be set, too.
363 * 360 *
364 * @param gamestate the current game state 361 * @param gamestate the current game state
365 * @param row row of the field to check 362 * @param rank rank of the field to check
366 * @param file file of the field to check 363 * @param file file of the field to check
367 * @param color the color of the piece that should move to the field 364 * @param color the color of the piece that should move to the field
368 * @param moves the array where to store the moves 365 * @param moves the array where to store the moves
369 * (must be large enough, 16 is always enough) 366 * (must be large enough, 16 is always enough)
370 * @param movecount a pointer where the number of moves is stored 367 * @param movecount a pointer where the number of moves is stored
371 * @return true, if any piece of the specified color can move to the specified 368 * @return true, if any piece of the specified color can move to the specified
372 * field regardless of being pinned 369 * field regardless of being pinned
373 */ 370 */
374 bool get_candidates(const GameState *gamestate, Row row, File file, 371 bool get_candidates(const GameState *gamestate, Rank rank, File file,
375 Color color, Move* moves, size_t* movecount); 372 Color color, Move* moves, size_t* movecount);
376 373
377 /** 374 /**
378 * Determines a list of possible moves to the specified field. 375 * Determines a list of possible moves to the specified field.
379 * 376 *
383 * 380 *
384 * The out-parameters may both be NULL, but if any of them is set, the other 381 * The out-parameters may both be NULL, but if any of them is set, the other
385 * must be set, too. 382 * must be set, too.
386 * 383 *
387 * @param gamestate the current game state 384 * @param gamestate the current game state
388 * @param row row of the field to check 385 * @param rank rank of the field to check
389 * @param file file of the field to check 386 * @param file file of the field to check
390 * @param color the color of the piece that should move to the field 387 * @param color the color of the piece that should move to the field
391 * @param moves the array where to store the moves 388 * @param moves the array where to store the moves
392 * (must be large enough, 16 is always enough) 389 * (must be large enough, 16 is always enough)
393 * @param movecount a pointer where the number of moves is stored 390 * @param movecount a pointer where the number of moves is stored
394 * @return true, if any piece of the specified color can move to the specified 391 * @return true, if any piece of the specified color can move to the specified
395 * field and is not pinned 392 * field and is not pinned
396 */ 393 */
397 bool get_real_candidates(const GameState *gamestate, Row row, File file, 394 bool get_real_candidates(const GameState *gamestate, Rank rank, File file,
398 Color color, Move* moves, size_t* movecount); 395 Color color, Move* moves, size_t* movecount);
399 396
400 /** 397 /**
401 * Checks, if a specified field is threatened by a piece of a certain color. 398 * Checks, if a specified field is threatened by a piece of a certain color.
402 * 399 *
405 * 402 *
406 * The out-parameters may both be NULL, but if any of them is set, the other 403 * The out-parameters may both be NULL, but if any of them is set, the other
407 * must be set, too. 404 * must be set, too.
408 * 405 *
409 * @param gamestate the current game state 406 * @param gamestate the current game state
410 * @param row row of the field to check 407 * @param rank rank of the field to check
411 * @param file file of the field to check 408 * @param file file of the field to check
412 * @param color the color of the piece that should threaten the field 409 * @param color the color of the piece that should threaten the field
413 * @param threats the array where to store the threats 410 * @param threats the array where to store the threats
414 * (must be large enough, 16 is always enough) 411 * (must be large enough, 16 is always enough)
415 * @param threatcount a pointer where the count of threats is stored 412 * @param threatcount a pointer where the count of threats is stored
416 * @return true, if any piece of the specified color threatens the specified 413 * @return true, if any piece of the specified color threatens the specified
417 * field 414 * field
418 */ 415 */
419 bool get_threats(const GameState *gamestate, Row row, File file, 416 bool get_threats(const GameState *gamestate, Rank rank, File file,
420 Color color, Move* threats, size_t* threatcount); 417 Color color, Move* threats, size_t* threatcount);
421 418
422 /** 419 /**
423 * Checks, if a specified field is threatened by a piece of a certain color AND 420 * Checks, if a specified field is threatened by a piece of a certain color AND
424 * if this piece is not pinned and therefore able to perform the move. 421 * if this piece is not pinned and therefore able to perform the move.
425 * 422 *
426 * The out-parameters may both be NULL, but if any of them is set, the other 423 * The out-parameters may both be NULL, but if any of them is set, the other
427 * must be set, too. 424 * must be set, too.
428 * 425 *
429 * @param gamestate the current game state 426 * @param gamestate the current game state
430 * @param row row of the field to check 427 * @param rank rank of the field to check
431 * @param file file of the field to check 428 * @param file file of the field to check
432 * @param color the color of the piece that should threaten the field 429 * @param color the color of the piece that should threaten the field
433 * @param threats the array where to store the threats 430 * @param threats the array where to store the threats
434 * (must be large enough, 16 is always enough) 431 * (must be large enough, 16 is always enough)
435 * @param threatcount a pointer where the count of threats is stored 432 * @param threatcount a pointer where the count of threats is stored
436 * @return true, if any piece of the specified color threatens the specified 433 * @return true, if any piece of the specified color threatens the specified
437 * field and is not pinned 434 * field and is not pinned
438 */ 435 */
439 bool get_real_threats(const GameState *gamestate, Row row, File file, 436 bool get_real_threats(const GameState *gamestate, Rank rank, File file,
440 Color color, Move* threats, size_t* threatcount); 437 Color color, Move* threats, size_t* threatcount);
441 438
442 /** 439 /**
443 * Checks, if a specified field is threatened by a piece of a certain color. 440 * Checks, if a specified field is threatened by a piece of a certain color.
444 * 441 *
445 * A field is threatened, if there is a piece of the specified color that could 442 * A field is threatened, if there is a piece of the specified color that could
446 * capture an opponent piece on this field, regardless of being pinned. 443 * capture an opponent piece on this field, regardless of being pinned.
447 * 444 *
448 * @param gamestate the current game state 445 * @param gamestate the current game state
449 * @param row row of the field to check 446 * @param rank rank of the field to check
450 * @param file file of the field to check 447 * @param file file of the field to check
451 * @param color the color of the piece that should cover the field 448 * @param color the color of the piece that should cover the field
452 * @return true, if any piece of the specified color threatens the specified 449 * @return true, if any piece of the specified color threatens the specified
453 * field 450 * field
454 */ 451 */
455 #define is_covered(gamestate, row, file, color) \ 452 #define is_covered(gamestate, rank, file, color) \
456 get_threats(gamestate, row, file, color, NULL, NULL) 453 get_threats(gamestate, rank, file, color, NULL, NULL)
457 454
458 /** 455 /**
459 * Checks, if a specified field is attacked by a piece of a certain color. 456 * Checks, if a specified field is attacked by a piece of a certain color.
460 * 457 *
461 * I.e. the field is threatened by a piece AND this piece is not pinned and 458 * I.e. the field is threatened by a piece AND this piece is not pinned and
462 * therefore able to perform the move. 459 * therefore able to perform the move.
463 * 460 *
464 * @param gamestate the current game state 461 * @param gamestate the current game state
465 * @param row row of the field to check 462 * @param rank rank of the field to check
466 * @param file file of the field to check 463 * @param file file of the field to check
467 * @param color the color of the piece that should cover the field 464 * @param color the color of the piece that should cover the field
468 * @return true, if any piece of the specified color threatens the specified 465 * @return true, if any piece of the specified color threatens the specified
469 * field and could capture an opponent piece 466 * field and could capture an opponent piece
470 */ 467 */
471 #define is_attacked(gamestate, row, file, color) \ 468 #define is_attacked(gamestate, rank, file, color) \
472 get_real_threats(gamestate, row, file, color, NULL, NULL) 469 get_real_threats(gamestate, rank, file, color, NULL, NULL)
473 470
474 /** 471 /**
475 * Checks, if a specified field is protected by a piece of a certain color. 472 * Checks, if a specified field is protected by a piece of a certain color.
476 * 473 *
477 * A field is protected, if any piece except the king can either capture on 474 * A field is protected, if any piece except the king can either capture on
478 * that field or move to that field (and is not pinned). 475 * that field or move to that field (and is not pinned).
479 * 476 *
480 * @param gamestate the current game state 477 * @param gamestate the current game state
481 * @param row row of the field to check 478 * @param rank rank of the field to check
482 * @param file file of the field to check 479 * @param file file of the field to check
483 * @param color the color of the piece that should cover the field 480 * @param color the color of the piece that should cover the field
484 * @return true, if any piece (excluding the king) of the specified color 481 * @return true, if any piece (excluding the king) of the specified color
485 * can move to the specified field (including capturing moves) 482 * can move to the specified field (including capturing moves)
486 */ 483 */
487 bool is_protected(const GameState *gamestate, Row row, File file, Color color); 484 bool is_protected(const GameState *gamestate, Rank rank, File file, Color color);
488 485
489 /** 486 /**
490 * Checks, if the specified move cannot be performed, because the piece is 487 * Checks, if the specified move cannot be performed, because the piece is
491 * either pinned or cannot remove the check. 488 * either pinned or cannot remove the check.
492 * 489 *

mercurial