Rev 33 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 33 | pmbaty | 1 | #include "chess.h" |
| 2 | #include "data.h" |
||
| 108 | pmbaty | 3 | /* last modified 01/06/16 */ |
| 33 | pmbaty | 4 | /* |
| 5 | ******************************************************************************* |
||
| 6 | * * |
||
| 7 | * MakeMove() is responsible for updating the position database whenever a * |
||
| 8 | * piece is moved. It performs the following operations: (1) update the * |
||
| 9 | * board structure itself by moving the piece and removing any captured * |
||
| 10 | * piece. (2) update the hash keys. (3) update material counts. (4) then * |
||
| 11 | * update castling status. (5) and finally update number of moves since * |
||
| 12 | * last reversible move. * |
||
| 13 | * * |
||
| 14 | * There are some special-cases handled here, such as en passant captures * |
||
| 15 | * where the enemy pawn is not on the <target> square, castling which moves * |
||
| 16 | * both the king and rook, and then rook moves/captures which give up the * |
||
| 17 | * castling right to that side when the rook is moved. * |
||
| 18 | * * |
||
| 19 | * note: side = 1 if white is to move, 0 otherwise. enemy is the opposite * |
||
| 20 | * and is 1 if it is not white to move, 0 otherwise. * |
||
| 21 | * * |
||
| 22 | ******************************************************************************* |
||
| 23 | */ |
||
| 108 | pmbaty | 24 | void MakeMove(TREE * RESTRICT tree, int ply, int side, int move) { |
| 33 | pmbaty | 25 | uint64_t bit_move; |
| 108 | pmbaty | 26 | int piece, from, to, captured, promote, enemy = Flip(side), cpiece; |
| 33 | pmbaty | 27 | #if defined(DEBUG) |
| 28 | int i; |
||
| 29 | #endif |
||
| 30 | |||
| 31 | /* |
||
| 32 | ************************************************************ |
||
| 33 | * * |
||
| 34 | * First, some basic information is updated for all moves * |
||
| 35 | * before we do the piece-specific stuff. We need to save * |
||
| 36 | * the current position and both hash signatures, and add * |
||
| 37 | * the current position to the repetition-list for the * |
||
| 38 | * side on move, before the move is actually made on the * |
||
| 39 | * board. We also update the 50 move rule counter which * |
||
| 40 | * will be reset if a capture or pawn move is made here. * |
||
| 41 | * * |
||
| 42 | * If the en passant flag was set the previous ply, we * |
||
| 43 | * have already used it to generate moves at this ply and * |
||
| 44 | * we need to clear it before continuing. If it is set, * |
||
| 45 | * we also need to update the hash signature since the EP * |
||
| 46 | * opportunity no longer exists after making any move at * |
||
| 47 | * this ply (one ply deeper than when a pawn was advanced * |
||
| 48 | * two squares). * |
||
| 49 | * * |
||
| 50 | ************************************************************ |
||
| 51 | */ |
||
| 52 | #if defined(DEBUG) |
||
| 53 | ValidatePosition(tree, ply, move, "MakeMove(1)"); |
||
| 54 | #endif |
||
| 55 | tree->status[ply + 1] = tree->status[ply]; |
||
| 56 | tree->save_hash_key[ply] = HashKey; |
||
| 57 | tree->save_pawn_hash_key[ply] = PawnHashKey; |
||
| 58 | if (EnPassant(ply + 1)) { |
||
| 59 | HashEP(EnPassant(ply + 1)); |
||
| 60 | EnPassant(ply + 1) = 0; |
||
| 61 | } |
||
| 62 | Reversible(ply + 1)++; |
||
| 63 | /* |
||
| 64 | ************************************************************ |
||
| 65 | * * |
||
| 66 | * Now do the things that are common to all pieces, such * |
||
| 67 | * as updating the bitboards and hash signature. * |
||
| 68 | * * |
||
| 69 | ************************************************************ |
||
| 70 | */ |
||
| 71 | piece = Piece(move); |
||
| 72 | from = From(move); |
||
| 73 | to = To(move); |
||
| 74 | captured = Captured(move); |
||
| 75 | promote = Promote(move); |
||
| 76 | bit_move = SetMask(from) | SetMask(to); |
||
| 77 | cpiece = PcOnSq(to); |
||
| 78 | ClearSet(bit_move, Pieces(side, piece)); |
||
| 79 | ClearSet(bit_move, Occupied(side)); |
||
| 80 | Hash(side, piece, from); |
||
| 81 | Hash(side, piece, to); |
||
| 82 | PcOnSq(from) = 0; |
||
| 83 | PcOnSq(to) = pieces[side][piece]; |
||
| 84 | /* |
||
| 85 | ************************************************************ |
||
| 86 | * * |
||
| 87 | * Now do the piece-specific things by jumping to the * |
||
| 88 | * appropriate routine. * |
||
| 89 | * * |
||
| 90 | ************************************************************ |
||
| 91 | */ |
||
| 92 | switch (piece) { |
||
| 93 | case pawn: |
||
| 94 | HashP(side, from); |
||
| 95 | HashP(side, to); |
||
| 96 | Reversible(ply + 1) = 0; |
||
| 97 | if (captured == 1 && !cpiece) { |
||
| 98 | Clear(to + epsq[side], Pawns(enemy)); |
||
| 99 | Clear(to + epsq[side], Occupied(enemy)); |
||
| 100 | Hash(enemy, pawn, to + epsq[side]); |
||
| 101 | HashP(enemy, to + epsq[side]); |
||
| 102 | PcOnSq(to + epsq[side]) = 0; |
||
| 103 | Material -= PieceValues(enemy, pawn); |
||
| 104 | TotalPieces(enemy, pawn)--; |
||
| 105 | TotalAllPieces--; |
||
| 106 | captured = 0; |
||
| 107 | } |
||
| 108 | if (promote) { |
||
| 109 | TotalPieces(side, pawn)--; |
||
| 110 | Material -= PieceValues(side, pawn); |
||
| 111 | Clear(to, Pawns(side)); |
||
| 112 | Hash(side, pawn, to); |
||
| 113 | HashP(side, to); |
||
| 114 | Hash(side, promote, to); |
||
| 115 | PcOnSq(to) = pieces[side][promote]; |
||
| 116 | TotalPieces(side, occupied) += p_vals[promote]; |
||
| 117 | TotalPieces(side, promote)++; |
||
| 118 | Material += PieceValues(side, promote); |
||
| 119 | Set(to, Pieces(side, promote)); |
||
| 120 | } else if ((Abs(to - from) == 16) && (mask_eptest[to] & Pawns(enemy))) { |
||
| 121 | EnPassant(ply + 1) = to + epsq[side]; |
||
| 122 | HashEP(to + epsq[side]); |
||
| 123 | } |
||
| 124 | break; |
||
| 125 | case knight: |
||
| 126 | case bishop: |
||
| 127 | case queen: |
||
| 128 | break; |
||
| 129 | case rook: |
||
| 130 | if (Castle(ply + 1, side) > 0) { |
||
| 131 | if ((from == rook_A[side]) && (Castle(ply + 1, side) & 2)) { |
||
| 132 | Castle(ply + 1, side) &= 1; |
||
| 133 | HashCastle(1, side); |
||
| 134 | } else if ((from == rook_H[side]) && (Castle(ply + 1, side) & 1)) { |
||
| 135 | Castle(ply + 1, side) &= 2; |
||
| 136 | HashCastle(0, side); |
||
| 137 | } |
||
| 138 | } |
||
| 139 | break; |
||
| 140 | case king: |
||
| 141 | KingSQ(side) = to; |
||
| 142 | if (Castle(ply + 1, side) > 0) { |
||
| 143 | if (Castle(ply + 1, side) & 2) |
||
| 144 | HashCastle(1, side); |
||
| 145 | if (Castle(ply + 1, side) & 1) |
||
| 146 | HashCastle(0, side); |
||
| 147 | if (Abs(to - from) == 2) { |
||
| 148 | Castle(ply + 1, side) = -1; |
||
| 149 | piece = rook; |
||
| 150 | if (to == rook_G[side]) { |
||
| 151 | from = rook_H[side]; |
||
| 152 | to = rook_F[side]; |
||
| 153 | } else { |
||
| 154 | from = rook_A[side]; |
||
| 155 | to = rook_D[side]; |
||
| 156 | } |
||
| 157 | bit_move = SetMask(from) | SetMask(to); |
||
| 158 | ClearSet(bit_move, Rooks(side)); |
||
| 159 | ClearSet(bit_move, Occupied(side)); |
||
| 160 | Hash(side, rook, from); |
||
| 161 | Hash(side, rook, to); |
||
| 162 | PcOnSq(from) = 0; |
||
| 163 | PcOnSq(to) = pieces[side][rook]; |
||
| 164 | } else |
||
| 165 | Castle(ply + 1, side) = 0; |
||
| 166 | } |
||
| 167 | break; |
||
| 168 | } |
||
| 169 | /* |
||
| 170 | ************************************************************ |
||
| 171 | * * |
||
| 172 | * If this is a capture move, we also have to update the * |
||
| 173 | * information that must change when a piece is removed * |
||
| 174 | * from the board. * |
||
| 175 | * * |
||
| 176 | ************************************************************ |
||
| 177 | */ |
||
| 178 | if (captured) { |
||
| 179 | Reversible(ply + 1) = 0; |
||
| 180 | TotalAllPieces--; |
||
| 181 | if (promote) |
||
| 182 | piece = promote; |
||
| 183 | Hash(enemy, captured, to); |
||
| 184 | Clear(to, Pieces(enemy, captured)); |
||
| 185 | Clear(to, Occupied(enemy)); |
||
| 186 | Material -= PieceValues(enemy, captured); |
||
| 187 | TotalPieces(enemy, captured)--; |
||
| 188 | if (captured != pawn) |
||
| 189 | TotalPieces(enemy, occupied) -= p_vals[captured]; |
||
| 190 | switch (captured) { |
||
| 191 | case pawn: |
||
| 192 | HashP(enemy, to); |
||
| 193 | break; |
||
| 194 | case knight: |
||
| 195 | case bishop: |
||
| 108 | pmbaty | 196 | case queen: |
| 33 | pmbaty | 197 | break; |
| 198 | case rook: |
||
| 199 | if (Castle(ply + 1, enemy) > 0) { |
||
| 200 | if ((to == rook_A[enemy]) && (Castle(ply + 1, enemy) & 2)) { |
||
| 201 | Castle(ply + 1, enemy) &= 1; |
||
| 202 | HashCastle(1, enemy); |
||
| 203 | } else if ((to == rook_H[enemy]) && (Castle(ply + 1, enemy) & 1)) { |
||
| 204 | Castle(ply + 1, enemy) &= 2; |
||
| 205 | HashCastle(0, enemy); |
||
| 206 | } |
||
| 207 | } |
||
| 208 | break; |
||
| 209 | case king: |
||
| 210 | #if defined(DEBUG) |
||
| 108 | pmbaty | 211 | Print(2048, "captured a king (Make)\n"); |
| 33 | pmbaty | 212 | for (i = 1; i <= ply; i++) |
| 108 | pmbaty | 213 | Print(2048, |
| 214 | "ply=%2d, phase=%d, piece=%2d,from=%2d,to=%2d,captured=%2d\n", |
||
| 215 | i, tree->phase[i], Piece(tree->curmv[i]), From(tree->curmv[i]), |
||
| 216 | To(tree->curmv[i]), Captured(tree->curmv[i])); |
||
| 217 | Print(2048, "ply=%2d, piece=%2d,from=%2d,to=%2d,captured=%2d\n", i, |
||
| 33 | pmbaty | 218 | piece, from, to, captured); |
| 219 | if (log_file) |
||
| 220 | DisplayChessBoard(log_file, tree->position); |
||
| 221 | #endif |
||
| 222 | break; |
||
| 223 | } |
||
| 224 | } |
||
| 225 | #if defined(DEBUG) |
||
| 226 | ValidatePosition(tree, ply + 1, move, "MakeMove(2)"); |
||
| 227 | #endif |
||
| 228 | return; |
||
| 229 | } |
||
| 230 | |||
| 108 | pmbaty | 231 | /* last modified 01/06/16 */ |
| 33 | pmbaty | 232 | /* |
| 233 | ******************************************************************************* |
||
| 234 | * * |
||
| 235 | * MakeMoveRoot() is used to make a move at the root of the game tree, * |
||
| 236 | * before any searching is done. It uses MakeMove() to execute the move, * |
||
| 237 | * but then copies the resulting position back to position[0], the actual * |
||
| 238 | * board position. It handles the special-case of the draw-by-repetition * |
||
| 239 | * rule by clearing the repetition list when a non-reversible move is made, * |
||
| 240 | * since no repetitions are possible once such a move is played. * |
||
| 241 | * * |
||
| 242 | ******************************************************************************* |
||
| 243 | */ |
||
| 108 | pmbaty | 244 | void MakeMoveRoot(TREE * RESTRICT tree, int side, int move) { |
| 33 | pmbaty | 245 | int player; |
| 246 | |||
| 247 | /* |
||
| 248 | ************************************************************ |
||
| 249 | * * |
||
| 250 | * First, make the move and then reset the repetition * |
||
| 251 | * index if the 50 move rule counter was reset to zero. * |
||
| 252 | * * |
||
| 253 | ************************************************************ |
||
| 254 | */ |
||
| 108 | pmbaty | 255 | MakeMove(tree, 0, side, move); |
| 33 | pmbaty | 256 | if (Reversible(1) == 0) |
| 108 | pmbaty | 257 | rep_index = -1; |
| 258 | tree->rep_list[++rep_index] = HashKey; |
||
| 33 | pmbaty | 259 | /* |
| 260 | ************************************************************ |
||
| 261 | * * |
||
| 262 | * One odd action is to note if the castle status is * |
||
| 263 | * currently negative, which indicates that that side * |
||
| 264 | * castled during the previous search. We simply set the * |
||
| 265 | * castle status for that side to zero and we are done. * |
||
| 266 | * * |
||
| 267 | * We then copy this back to ply=0 status (which is the * |
||
| 268 | * permanent game-board ply). * |
||
| 269 | * * |
||
| 270 | ************************************************************ |
||
| 271 | */ |
||
| 272 | for (player = black; player <= white; player++) |
||
| 273 | Castle(1, player) = Max(0, Castle(1, player)); |
||
| 274 | tree->status[0] = tree->status[1]; |
||
| 275 | } |