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 }