| 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; |
| 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; |
| 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 * |