stellar

Stellar - Chess engine written in C
Log | Files | Refs

moves.c (10258B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 
      4 #include <cul/mem.h>
      5 
      6 #include "moves.h"
      7 
      8 int Move_cmp(Move a, Move b) { return *(uint32_t *)&a == *(uint32_t *)&b; }
      9 
     10 Move Move_encode(Square src, Square tgt, Piece_T Piece, Piece_T Capture,
     11                  Piece_T Promote, int dbl, int enpassant, int castle) {
     12     return (Move){
     13         .source = src,
     14         .target = tgt,
     15         .dbl = dbl,
     16         .enpassant = enpassant,
     17         .castle = castle,
     18         .capture = Capture != NULL,
     19         .promote = Promote != NULL,
     20         .piece = Piece_index(Piece),
     21         .piece_capture = Capture ? Piece_index(Capture) : 0,
     22         .piece_promote = Promote ? Piece_index(Promote) : 0,
     23     };
     24 }
     25 
     26 void Move_print(Move move) {
     27     printf("%5s %5s  %2s  %2s   %2s %4d %4d %4d %4d %4d\n",
     28            square_to_coordinates[Move_source(move)],
     29            square_to_coordinates[Move_target(move)],
     30            Piece_unicode(Move_piece(move)),
     31            Move_capture(move) ? Piece_unicode(Move_piece_capture(move)) : "X ",
     32            Move_promote(move) ? Piece_unicode(Move_piece_promote(move)) : "X ",
     33            Move_double(move) ? 1 : 0, Move_enpassant(move) ? 1 : 0,
     34            Move_castle(move) ? 1 : 0, Move_capture(move) ? 1 : 0,
     35            Move_promote(move) ? 1 : 0);
     36 }
     37 
     38 MoveList_T MoveList_new(void) {
     39     MoveList_T p;
     40     NEW0(p);
     41     return p;
     42 }
     43 
     44 void MoveList_free(MoveList_T *p) { FREE(*p); }
     45 
     46 Move MoveList_move(MoveList_T self, int index) { return self->moves[index]; }
     47 int MoveList_size(MoveList_T self) { return self->count; }
     48 void MoveList_reset(MoveList_T self) { self->count = 0; }
     49 
     50 void MoveList_add(MoveList_T self, Move move) {
     51     self->moves[self->count++] = move;
     52 }
     53 
     54 void MoveList_print(MoveList_T self) {
     55     printf(" From    To  Pi  Cap  Prmt  Dbl  Enp  Cst  C   P\n");
     56     for (int i = 0; i < self->count; i++)
     57         Move_print(self->moves[i]);
     58     printf("Total: %d\n", self->count);
     59 }
     60 
     61 #define pawn_canPromote(color, source)                                         \
     62     ((color == WHITE && source >= a7 && source <= h7) ||                       \
     63      (color == BLACK && source >= a2 && source <= h2))
     64 
     65 #define pawn_onStart(color, source)                                            \
     66     ((color == BLACK && source >= a7 && source <= h7) ||                       \
     67      (color == WHITE && source >= a2 && source <= h2))
     68 
     69 #define pawn_promote(source, target, Piece, Capture)                           \
     70     for (int i = 1; i < 5; i++) {                                              \
     71         move = Move_encode(source, target, Piece, Capture,                     \
     72                            Piece_get(i, color), 0, 0, 0);                      \
     73         MoveList_add(moves, move);                                             \
     74     }
     75 
     76 MoveList_T MoveList_generate(MoveList_T moves, CBoard_T board) {
     77     Move move;
     78     Square src, tgt;
     79     eColor color = CBoard_side(board);
     80 
     81     if (!moves) moves = MoveList_new();
     82 
     83     { // pawn moves
     84         Piece_T Piece = Piece_get(PAWN, color);
     85         U64 bitboard = CBoard_pieceSet(board, Piece);
     86         bitboard_for_each_bit(src, bitboard) {
     87             { // quiet
     88                 int add = (color == WHITE) ? +8 : -8;
     89                 tgt = src + add;
     90                 if (tgt > a1 && tgt < h8 &&
     91                     !CBoard_square_isOccupied(board, tgt)) {
     92                     if (pawn_canPromote(color, src)) {
     93                         pawn_promote(src, tgt, Piece, 0);
     94                     } else {
     95                         MoveList_add(
     96                             moves, Move_encode(src, tgt, Piece, 0, 0, 0, 0, 0));
     97 
     98                         // two ahead
     99                         if (pawn_onStart(color, src) &&
    100                             !CBoard_square_isOccupied(board, tgt += add))
    101                             MoveList_add(moves, Move_encode(src, tgt, Piece, 0,
    102                                                             0, 1, 0, 0));
    103                     }
    104                 }
    105             }
    106             { // capture
    107                 U64 attack = CBoard_piece_attacks(board, Piece, src) &
    108                              CBoard_colorBB(board, !color);
    109                 bitboard_for_each_bit(tgt, attack) {
    110                     if (pawn_canPromote(color, src)) {
    111                         pawn_promote(src, tgt, Piece,
    112                                      CBoard_square_piece(board, tgt, !color));
    113                     } else {
    114                         MoveList_add(moves, Move_encode(src, tgt, Piece,
    115                                                         CBoard_square_piece(
    116                                                             board, tgt, !color),
    117                                                         0, 0, 0, 0));
    118                     }
    119                 }
    120             }
    121 
    122             { // en passant
    123                 if (CBoard_enpassant(board) != no_sq &&
    124                     CBoard_piece_attacks(board, Piece, src) &
    125                         (C64(1) << CBoard_enpassant(board)))
    126                     MoveList_add(
    127                         moves,
    128                         Move_encode(src, CBoard_enpassant(board), Piece,
    129                                     CBoard_square_piece(board, tgt, !color), 0,
    130                                     0, 1, 0));
    131             }
    132         }
    133     }
    134 
    135     // All piece move
    136     for (int piece = 1; piece < 6; piece++) {
    137         Piece_T Piece = Piece_get(piece, color);
    138         U64 bitboard = CBoard_pieceSet(board, Piece);
    139         bitboard_for_each_bit(src, bitboard) {
    140             U64 attack = CBoard_piece_attacks(board, Piece, src) &
    141                          ~CBoard_colorBB(board, color);
    142             bitboard_for_each_bit(tgt, attack) {
    143                 /* int take = bit_get(CBoard_colorBB(board, !color), tgt); */
    144                 MoveList_add(
    145                     moves, Move_encode(src, tgt, Piece,
    146                                        CBoard_square_piece(board, tgt, !color),
    147                                        0, 0, 0, 0));
    148             }
    149         }
    150     }
    151 
    152     // Castling
    153     {
    154         if (color == WHITE) {
    155             Piece_T Piece = Piece_get(KING, WHITE);
    156             if (CBoard_castle(board) & WK) {
    157                 if (!CBoard_square_isOccupied(board, f1) &&
    158                     !CBoard_square_isOccupied(board, g1) &&
    159                     !CBoard_square_isAttack(board, e1, BLACK) &&
    160                     !CBoard_square_isAttack(board, f1, BLACK))
    161                     MoveList_add(moves,
    162                                  Move_encode(e1, g1, Piece, 0, 0, 0, 0, 1));
    163             }
    164             if (CBoard_castle(board) & WQ) {
    165                 if (!CBoard_square_isOccupied(board, d1) &&
    166                     !CBoard_square_isOccupied(board, c1) &&
    167                     !CBoard_square_isOccupied(board, b1) &&
    168                     !CBoard_square_isAttack(board, e1, BLACK) &&
    169                     !CBoard_square_isAttack(board, d1, BLACK))
    170                     MoveList_add(moves,
    171                                  Move_encode(e1, c1, Piece, 0, 0, 0, 0, 1));
    172             }
    173         } else {
    174             Piece_T Piece = Piece_get(KING, BLACK);
    175             if (CBoard_castle(board) & BK) {
    176                 if (!CBoard_square_isOccupied(board, f8) &&
    177                     !CBoard_square_isOccupied(board, g8) &&
    178                     !CBoard_square_isAttack(board, e8, WHITE) &&
    179                     !CBoard_square_isAttack(board, f8, WHITE))
    180                     MoveList_add(moves,
    181                                  Move_encode(e8, g8, Piece, 0, 0, 0, 0, 1));
    182             }
    183             if (CBoard_castle(board) & BQ) {
    184                 if (!CBoard_square_isOccupied(board, d8) &&
    185                     !CBoard_square_isOccupied(board, c8) &&
    186                     !CBoard_square_isOccupied(board, b8) &&
    187                     !CBoard_square_isAttack(board, e8, WHITE) &&
    188                     !CBoard_square_isAttack(board, d8, WHITE))
    189                     MoveList_add(moves,
    190                                  Move_encode(e8, c8, Piece, 0, 0, 0, 0, 1));
    191             }
    192         }
    193     }
    194 
    195     return moves;
    196 }
    197 
    198 // clang-format off
    199 const int castling_rights[64] = {
    200     13, 15, 15, 15, 12, 15, 15, 14,
    201     15, 15, 15, 15, 15, 15, 15, 15,
    202     15, 15, 15, 15, 15, 15, 15, 15,
    203     15, 15, 15, 15, 15, 15, 15, 15,
    204     15, 15, 15, 15, 15, 15, 15, 15,
    205     15, 15, 15, 15, 15, 15, 15, 15,
    206     15, 15, 15, 15, 15, 15, 15, 15,
    207     7,  15, 15, 15, 3,  15, 15, 11,
    208 };
    209 // clang-format on
    210 
    211 int Move_make(Move move, CBoard_T board, int flag) {
    212     if (flag == 0) {
    213 
    214         Square source = Move_source(move);
    215         Square target = Move_target(move);
    216         Piece_T Piece = Move_piece(move);
    217         eColor color = CBoard_side(board);
    218 
    219         if (!Move_capture(move))
    220             CBoard_piece_move(board, Piece, source, target);
    221         else
    222             CBoard_piece_capture(board, Piece, Move_piece_capture(move), source,
    223                                  target);
    224 
    225         if (Move_promote(move)) {
    226             CBoard_piece_pop(board, Piece, target);
    227             CBoard_piece_set(board, Move_piece_promote(move), target);
    228         }
    229 
    230         {
    231             int ntarget = target + (color == WHITE ? -8 : +8);
    232             if (Move_enpassant(move))
    233                 CBoard_piece_pop(board, Piece_get(PAWN, !color), ntarget);
    234 
    235             CBoard_enpassant_set(board, Move_double(move) ? ntarget : no_sq);
    236         }
    237 
    238         if (Move_castle(move)) {
    239             Piece_T Rook = Piece_get(ROOK, CBoard_side(board));
    240             switch (target) {
    241             case g1:
    242                 CBoard_piece_move(board, Rook, h1, f1);
    243                 break;
    244             case c1:
    245                 CBoard_piece_move(board, Rook, a1, d1);
    246                 break;
    247             case g8:
    248                 CBoard_piece_move(board, Rook, h8, f8);
    249                 break;
    250             case c8:
    251                 CBoard_piece_move(board, Rook, a8, d8);
    252                 break;
    253             default:
    254                 break;
    255             }
    256         }
    257 
    258         CBoard_castle_and(board, castling_rights[source]);
    259         CBoard_castle_and(board, castling_rights[target]);
    260 
    261         if (!CBoard_isCheck(board)) {
    262             CBoard_side_switch(board);
    263             return 1;
    264         } else
    265             return 0;
    266     } else {
    267         if (Move_capture(move))
    268             return Move_make(move, board, 0);
    269         else
    270             return 0;
    271     }
    272 }