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 | /* modified 12/31/15 */ |
| 33 | pmbaty | 4 | /* |
| 5 | ******************************************************************************* |
||
| 6 | * * |
||
| 7 | * GenerateCaptures() is used to generate capture and pawn promotion moves * |
||
| 8 | * from the current position. * |
||
| 9 | * * |
||
| 10 | * The destination square set is the set of squares occupied by opponent * |
||
| 11 | * pieces, plus the set of squares on the 8th rank that pawns can advance to * |
||
| 12 | * and promote. * |
||
| 13 | * * |
||
| 14 | ******************************************************************************* |
||
| 15 | */ |
||
| 108 | pmbaty | 16 | unsigned *GenerateCaptures(TREE * RESTRICT tree, int ply, int side, |
| 17 | unsigned *move) { |
||
| 18 | uint64_t target, piecebd, moves, promotions, pcapturesl, pcapturesr; |
||
| 33 | pmbaty | 19 | int from, to, temp, common, enemy = Flip(side); |
| 20 | |||
| 21 | /* |
||
| 22 | ************************************************************ |
||
| 23 | * * |
||
| 24 | * We produce knight moves by locating the most advanced * |
||
| 25 | * knight and then using that <from> square as an index * |
||
| 26 | * into the precomputed knight_attacks data. We repeat * |
||
| 27 | * for each knight. * |
||
| 28 | * * |
||
| 29 | ************************************************************ |
||
| 30 | */ |
||
| 31 | for (piecebd = Knights(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 32 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 33 | moves = knight_attacks[from] & Occupied(enemy); |
| 34 | temp = from + (knight << 12); |
||
| 35 | Extract(side, move, moves, temp); |
||
| 36 | } |
||
| 37 | /* |
||
| 38 | ************************************************************ |
||
| 39 | * * |
||
| 108 | pmbaty | 40 | * We produce sliding piece moves by locating each piece * |
| 41 | * type in turn. We then start with the most advanced * |
||
| 42 | * piece and generate moves from that square. This uses * |
||
| 43 | * "magic move generation" to produce the destination * |
||
| 44 | * squares. * |
||
| 33 | pmbaty | 45 | * * |
| 46 | ************************************************************ |
||
| 47 | */ |
||
| 48 | for (piecebd = Bishops(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 49 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 50 | moves = BishopAttacks(from, OccupiedSquares) & Occupied(enemy); |
| 51 | temp = from + (bishop << 12); |
||
| 52 | Extract(side, move, moves, temp); |
||
| 53 | } |
||
| 54 | for (piecebd = Rooks(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 55 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 56 | moves = RookAttacks(from, OccupiedSquares) & Occupied(enemy); |
| 57 | temp = from + (rook << 12); |
||
| 58 | Extract(side, move, moves, temp); |
||
| 59 | } |
||
| 60 | for (piecebd = Queens(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 61 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 62 | moves = QueenAttacks(from, OccupiedSquares) & Occupied(enemy); |
| 63 | temp = from + (queen << 12); |
||
| 64 | Extract(side, move, moves, temp); |
||
| 65 | } |
||
| 66 | /* |
||
| 67 | ************************************************************ |
||
| 68 | * * |
||
| 69 | * We produce king moves by locating the only king and * |
||
| 70 | * then using that <from> square as an index into the * |
||
| 71 | * precomputed king_attacks data. * |
||
| 72 | * * |
||
| 73 | ************************************************************ |
||
| 74 | */ |
||
| 75 | from = KingSQ(side); |
||
| 76 | moves = king_attacks[from] & Occupied(enemy); |
||
| 77 | temp = from + (king << 12); |
||
| 78 | Extract(side, move, moves, temp); |
||
| 79 | /* |
||
| 80 | ************************************************************ |
||
| 81 | * * |
||
| 82 | * Now, produce pawn moves. This is done differently due * |
||
| 83 | * to inconsistencies in the way a pawn moves when it * |
||
| 84 | * captures as opposed to normal non-capturing moves. * |
||
| 85 | * Another exception is capturing enpassant. The first * |
||
| 86 | * step is to generate all possible pawn promotions. We * |
||
| 87 | * do this by removing all pawns but those on the 7th rank * |
||
| 88 | * and then advancing them if the square in front is empty.* |
||
| 89 | * * |
||
| 90 | ************************************************************ |
||
| 91 | */ |
||
| 108 | pmbaty | 92 | promotions = Pawns(side) & rank_mask[rank7[side]]; |
| 33 | pmbaty | 93 | promotions = |
| 108 | pmbaty | 94 | ((side) ? promotions << 8 : promotions >> 8) & ~OccupiedSquares; |
| 33 | pmbaty | 95 | for (; promotions; Clear(to, promotions)) { |
| 96 | to = LSB(promotions); |
||
| 97 | *move++ = |
||
| 98 | (to + pawnadv1[side]) | (to << 6) | (pawn << 12) | (queen << 18); |
||
| 99 | } |
||
| 100 | target = Occupied(enemy) | EnPassantTarget(ply); |
||
| 101 | pcapturesl = |
||
| 102 | ((side) ? (Pawns(white) & mask_left_edge) << 7 : (Pawns(black) & |
||
| 103 | mask_left_edge) >> 9) & target; |
||
| 104 | for (; pcapturesl; Clear(to, pcapturesl)) { |
||
| 108 | pmbaty | 105 | to = MostAdvanced(side, pcapturesl); |
| 33 | pmbaty | 106 | common = (to + capleft[side]) | (to << 6) | (pawn << 12); |
| 107 | if ((side) ? to < 56 : to > 7) |
||
| 108 | *move++ = common | (((PcOnSq(to)) ? Abs(PcOnSq(to)) : pawn) << 15); |
||
| 109 | else |
||
| 110 | *move++ = common | Abs(PcOnSq(to)) << 15 | queen << 18; |
||
| 111 | } |
||
| 112 | pcapturesr = |
||
| 113 | ((side) ? (Pawns(white) & mask_right_edge) << 9 : (Pawns(black) & |
||
| 114 | mask_right_edge) >> 7) & target; |
||
| 115 | for (; pcapturesr; Clear(to, pcapturesr)) { |
||
| 108 | pmbaty | 116 | to = MostAdvanced(side, pcapturesr); |
| 33 | pmbaty | 117 | common = (to + capright[side]) | (to << 6) | (pawn << 12); |
| 118 | if ((side) ? to < 56 : to > 7) |
||
| 119 | *move++ = common | (((PcOnSq(to)) ? Abs(PcOnSq(to)) : pawn) << 15); |
||
| 120 | else |
||
| 121 | *move++ = common | Abs(PcOnSq(to)) << 15 | queen << 18; |
||
| 122 | } |
||
| 123 | return move; |
||
| 124 | } |
||
| 125 | |||
| 108 | pmbaty | 126 | /* modified 12/31/15 */ |
| 33 | pmbaty | 127 | /* |
| 128 | ******************************************************************************* |
||
| 129 | * * |
||
| 130 | * GenerateChecks() is used to generate non-capture moves from the current * |
||
| 131 | * position. * |
||
| 132 | * * |
||
| 133 | * The first pass produces a bitmap that contains the squares a particular * |
||
| 134 | * piece type would attack if sitting on the square the enemy king sits on. * |
||
| 135 | * We then use each of these squares as a source and check to see if the * |
||
| 136 | * same piece type attacks one of these common targets. If so, we can move * |
||
| 137 | * that piece to that square and it will directly attack the king. We do * |
||
| 138 | * this for pawns, knights, bishops, rooks and queens to produce the set of * |
||
| 139 | * "direct checking moves." * |
||
| 140 | * * |
||
| 141 | * Then we generate discovered checks in two passes, once for diagonal * |
||
| 142 | * attacks and once for rank/file attacks (we do it in two passes since a * |
||
| 143 | * rook can't produce a discovered check along a rank or file since it moves * |
||
| 144 | * in that direction as well. For diagonals, we first generate the bishop * |
||
| 145 | * attacks from the enemy king square and mask them with the friendly piece * |
||
| 146 | * occupied squares bitmap. This gives us a set of up to 4 "blocking * |
||
| 147 | * pieces" that could be preventing a check. We then remove them via the * |
||
| 148 | * "magic move generation" tricks, and see if we now reach friendly bishops * |
||
| 149 | * or queens on those diagonals. If we have a friendly blocker, and a * |
||
| 150 | * friendly diagonal mover behind that blocker, then moving the blocker is * |
||
| 151 | * a discovered check (and there could be double-checks included but we do * |
||
| 152 | * not check for that since a single check is good enough). We repeat this * |
||
| 153 | * for the ranks/files and we are done. * |
||
| 154 | * * |
||
| 155 | * For the present, this code does not produce discovered checks by the * |
||
| 156 | * king since all king moves are not discovered checks because the king can * |
||
| 157 | * move in the same direction as the piece it blocks and not uncover the * |
||
| 158 | * attack. This might be fixed at some point, but it is rare enough to not * |
||
| 159 | * be an issue except in far endgames. * |
||
| 160 | * * |
||
| 161 | ******************************************************************************* |
||
| 162 | */ |
||
| 108 | pmbaty | 163 | unsigned *GenerateChecks(TREE * RESTRICT tree, int side, unsigned *move) { |
| 33 | pmbaty | 164 | uint64_t temp_target, target, piecebd, moves; |
| 165 | uint64_t padvances1, blockers, checkers; |
||
| 166 | int from, to, promote, temp, enemy = Flip(side); |
||
| 167 | |||
| 168 | /* |
||
| 108 | pmbaty | 169 | ************************************************************ |
| 170 | * * |
||
| 171 | * First pass: produce direct checks. For each piece * |
||
| 172 | * type, we pretend that a piece of that type stands on * |
||
| 173 | * the square of the king and we generate attacks from * |
||
| 174 | * that square for that piece. Now, if we can find any * |
||
| 175 | * piece of that type that attacks one of those squares, * |
||
| 176 | * then that piece move would deliver a direct check to * |
||
| 177 | * the enemy king. Easy, wasn't it? * |
||
| 178 | * * |
||
| 179 | ************************************************************ |
||
| 33 | pmbaty | 180 | */ |
| 181 | target = ~OccupiedSquares; |
||
| 182 | /* |
||
| 183 | ************************************************************ |
||
| 184 | * * |
||
| 185 | * Knight direct checks. * |
||
| 186 | * * |
||
| 187 | ************************************************************ |
||
| 188 | */ |
||
| 189 | temp_target = target & knight_attacks[KingSQ(enemy)]; |
||
| 190 | for (piecebd = Knights(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 191 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 192 | moves = knight_attacks[from] & temp_target; |
| 193 | temp = from + (knight << 12); |
||
| 194 | Extract(side, move, moves, temp); |
||
| 195 | } |
||
| 196 | /* |
||
| 197 | ************************************************************ |
||
| 198 | * * |
||
| 108 | pmbaty | 199 | * Sliding piece direct checks. * |
| 33 | pmbaty | 200 | * * |
| 201 | ************************************************************ |
||
| 202 | */ |
||
| 203 | temp_target = target & BishopAttacks(KingSQ(enemy), OccupiedSquares); |
||
| 204 | for (piecebd = Bishops(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 205 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 206 | moves = BishopAttacks(from, OccupiedSquares) & temp_target; |
| 207 | temp = from + (bishop << 12); |
||
| 208 | Extract(side, move, moves, temp); |
||
| 209 | } |
||
| 210 | temp_target = target & RookAttacks(KingSQ(enemy), OccupiedSquares); |
||
| 211 | for (piecebd = Rooks(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 212 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 213 | moves = RookAttacks(from, OccupiedSquares) & temp_target; |
| 214 | temp = from + (rook << 12); |
||
| 215 | Extract(side, move, moves, temp); |
||
| 216 | } |
||
| 217 | temp_target = target & QueenAttacks(KingSQ(enemy), OccupiedSquares); |
||
| 218 | for (piecebd = Queens(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 219 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 220 | moves = QueenAttacks(from, OccupiedSquares) & temp_target; |
| 221 | temp = from + (queen << 12); |
||
| 222 | Extract(side, move, moves, temp); |
||
| 223 | } |
||
| 224 | /* |
||
| 225 | ************************************************************ |
||
| 226 | * * |
||
| 227 | * Pawn direct checks. * |
||
| 228 | * * |
||
| 229 | ************************************************************ |
||
| 230 | */ |
||
| 231 | temp_target = target & pawn_attacks[enemy][KingSQ(enemy)]; |
||
| 232 | padvances1 = ((side) ? Pawns(white) << 8 : Pawns(black) >> 8) & temp_target; |
||
| 233 | for (; padvances1; Clear(to, padvances1)) { |
||
| 108 | pmbaty | 234 | to = MostAdvanced(side, padvances1); |
| 33 | pmbaty | 235 | *move++ = (to + pawnadv1[side]) | (to << 6) | (pawn << 12); |
| 236 | } |
||
| 237 | /* |
||
| 238 | ************************************************************ |
||
| 239 | * * |
||
| 108 | pmbaty | 240 | * Second pass: produce discovered checks. Here we do * |
| 241 | * things a bit differently. We first take diagonal * |
||
| 242 | * movers. From the enemy king's position, we generate * |
||
| 243 | * diagonal moves to see if any of them end at one of our * |
||
| 244 | * pieces that does not slide diagonally, such as a rook, * |
||
| 245 | * knight or pawn. If we find one, we look further down * |
||
| 246 | * that diagonal to see if we now find a diagonal moves * |
||
| 247 | * (queen or bishop). If so, any legal move by the * |
||
| 248 | * blocking piece (except captures which have already been * |
||
| 249 | * generated) will be a discovered check that needs to be * |
||
| 250 | * searched. We do the same for vertical / horizontal * |
||
| 251 | * rays that are blocked by bishops, knights or pawns that * |
||
| 252 | * would hide a discovered check by a rook or queen. * |
||
| 253 | * * |
||
| 33 | pmbaty | 254 | * First we look for diagonal discovered attacks. Once we * |
| 255 | * know which squares hold pieces that create a discovered * |
||
| 256 | * check when they move, we generate those piece moves * |
||
| 257 | * piece type by piece type. * |
||
| 258 | * * |
||
| 259 | ************************************************************ |
||
| 260 | */ |
||
| 261 | blockers = |
||
| 262 | BishopAttacks(KingSQ(enemy), |
||
| 263 | OccupiedSquares) & (Rooks(side) | Knights(side) | Pawns(side)); |
||
| 264 | if (blockers) { |
||
| 265 | checkers = |
||
| 266 | BishopAttacks(KingSQ(enemy), |
||
| 267 | OccupiedSquares & ~blockers) & (Bishops(side) | Queens(side)); |
||
| 268 | if (checkers) { |
||
| 269 | if (plus7dir[KingSQ(enemy)] & blockers && |
||
| 270 | !(plus7dir[KingSQ(enemy)] & checkers)) |
||
| 271 | blockers &= ~plus7dir[KingSQ(enemy)]; |
||
| 272 | if (plus9dir[KingSQ(enemy)] & blockers && |
||
| 273 | !(plus9dir[KingSQ(enemy)] & checkers)) |
||
| 274 | blockers &= ~plus9dir[KingSQ(enemy)]; |
||
| 275 | if (minus7dir[KingSQ(enemy)] & blockers && |
||
| 276 | !(minus7dir[KingSQ(enemy)] & checkers)) |
||
| 277 | blockers &= ~minus7dir[KingSQ(enemy)]; |
||
| 278 | if (minus9dir[KingSQ(enemy)] & blockers && |
||
| 279 | !(minus9dir[KingSQ(enemy)] & checkers)) |
||
| 280 | blockers &= ~minus9dir[KingSQ(enemy)]; |
||
| 281 | target = ~OccupiedSquares; |
||
| 282 | /* |
||
| 283 | ************************************************************ |
||
| 284 | * * |
||
| 285 | * Knight discovered checks. * |
||
| 286 | * * |
||
| 287 | ************************************************************ |
||
| 288 | */ |
||
| 289 | temp_target = target & ~knight_attacks[KingSQ(enemy)]; |
||
| 290 | for (piecebd = Knights(side) & blockers; piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 291 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 292 | moves = knight_attacks[from] & temp_target; |
| 293 | temp = from + (knight << 12); |
||
| 294 | Extract(side, move, moves, temp); |
||
| 295 | } |
||
| 296 | /* |
||
| 297 | ************************************************************ |
||
| 298 | * * |
||
| 299 | * Rook discovered checks. * |
||
| 300 | * * |
||
| 301 | ************************************************************ |
||
| 302 | */ |
||
| 303 | target = ~OccupiedSquares; |
||
| 304 | temp_target = target & ~RookAttacks(KingSQ(enemy), OccupiedSquares); |
||
| 305 | for (piecebd = Rooks(side) & blockers; piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 306 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 307 | moves = RookAttacks(from, OccupiedSquares) & temp_target; |
| 308 | temp = from + (rook << 12); |
||
| 309 | Extract(side, move, moves, temp); |
||
| 310 | } |
||
| 311 | /* |
||
| 312 | ************************************************************ |
||
| 313 | * * |
||
| 314 | * Pawn discovered checks. * |
||
| 315 | * * |
||
| 316 | ************************************************************ |
||
| 317 | */ |
||
| 318 | piecebd = |
||
| 319 | Pawns(side) & blockers & ((side) ? ~OccupiedSquares >> 8 : |
||
| 320 | ~OccupiedSquares << 8); |
||
| 321 | for (; piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 322 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 323 | to = from + pawnadv1[enemy]; |
| 324 | if ((side) ? to > 55 : to < 8) |
||
| 325 | promote = queen; |
||
| 326 | else |
||
| 327 | promote = 0; |
||
| 328 | *move++ = from | (to << 6) | (pawn << 12) | (promote << 18); |
||
| 329 | } |
||
| 330 | } |
||
| 331 | } |
||
| 332 | /* |
||
| 333 | ************************************************************ |
||
| 334 | * * |
||
| 335 | * Next, we look for rank/file discovered attacks. Once * |
||
| 336 | * we know which squares hold pieces that create a * |
||
| 337 | * discovered check when they move, we generate them * |
||
| 338 | * piece type by piece type. * |
||
| 339 | * * |
||
| 340 | ************************************************************ |
||
| 341 | */ |
||
| 342 | blockers = |
||
| 343 | RookAttacks(KingSQ(enemy), |
||
| 344 | OccupiedSquares) & (Bishops(side) | Knights(side) | (Pawns(side) & |
||
| 345 | rank_mask[Rank(KingSQ(enemy))])); |
||
| 346 | if (blockers) { |
||
| 347 | checkers = |
||
| 348 | RookAttacks(KingSQ(enemy), |
||
| 349 | OccupiedSquares & ~blockers) & (Rooks(side) | Queens(side)); |
||
| 350 | if (checkers) { |
||
| 351 | if (plus1dir[KingSQ(enemy)] & blockers && |
||
| 352 | !(plus1dir[KingSQ(enemy)] & checkers)) |
||
| 353 | blockers &= ~plus1dir[KingSQ(enemy)]; |
||
| 354 | if (plus8dir[KingSQ(enemy)] & blockers && |
||
| 355 | !(plus8dir[KingSQ(enemy)] & checkers)) |
||
| 356 | blockers &= ~plus8dir[KingSQ(enemy)]; |
||
| 357 | if (minus1dir[KingSQ(enemy)] & blockers && |
||
| 358 | !(minus1dir[KingSQ(enemy)] & checkers)) |
||
| 359 | blockers &= ~minus1dir[KingSQ(enemy)]; |
||
| 360 | if (minus8dir[KingSQ(enemy)] & blockers && |
||
| 361 | !(minus8dir[KingSQ(enemy)] & checkers)) |
||
| 362 | blockers &= ~minus8dir[KingSQ(enemy)]; |
||
| 363 | target = ~OccupiedSquares; |
||
| 364 | /* |
||
| 365 | ************************************************************ |
||
| 366 | * * |
||
| 367 | * Knight discovered checks. * |
||
| 368 | * * |
||
| 369 | ************************************************************ |
||
| 370 | */ |
||
| 371 | temp_target = target & ~knight_attacks[KingSQ(enemy)]; |
||
| 372 | for (piecebd = Knights(side) & blockers; piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 373 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 374 | moves = knight_attacks[from] & temp_target; |
| 375 | temp = from + (knight << 12); |
||
| 376 | Extract(side, move, moves, temp); |
||
| 377 | } |
||
| 378 | /* |
||
| 379 | ************************************************************ |
||
| 380 | * * |
||
| 381 | * Bishop discovered checks. * |
||
| 382 | * * |
||
| 383 | ************************************************************ |
||
| 384 | */ |
||
| 385 | target = ~OccupiedSquares; |
||
| 386 | temp_target = target & ~BishopAttacks(KingSQ(enemy), OccupiedSquares); |
||
| 387 | for (piecebd = Bishops(side) & blockers; piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 388 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 389 | moves = BishopAttacks(from, OccupiedSquares) & temp_target; |
| 390 | temp = from + (bishop << 12); |
||
| 391 | Extract(side, move, moves, temp); |
||
| 392 | } |
||
| 393 | /* |
||
| 394 | ************************************************************ |
||
| 395 | * * |
||
| 396 | * Pawn discovered checks. * |
||
| 397 | * * |
||
| 398 | ************************************************************ |
||
| 399 | */ |
||
| 400 | piecebd = |
||
| 401 | Pawns(side) & blockers & ((side) ? ~OccupiedSquares >> 8 : |
||
| 402 | ~OccupiedSquares << 8); |
||
| 403 | for (; piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 404 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 405 | to = from + pawnadv1[enemy]; |
| 406 | if ((side) ? to > 55 : to < 8) |
||
| 407 | promote = queen; |
||
| 408 | else |
||
| 409 | promote = 0; |
||
| 410 | *move++ = from | (to << 6) | (pawn << 12) | (promote << 18); |
||
| 411 | } |
||
| 412 | } |
||
| 413 | } |
||
| 414 | return move; |
||
| 415 | } |
||
| 416 | |||
| 108 | pmbaty | 417 | /* modified 12/31/15 */ |
| 33 | pmbaty | 418 | /* |
| 419 | ******************************************************************************* |
||
| 420 | * * |
||
| 421 | * GenerateCheckEvasions() is used to generate moves when the king is in * |
||
| 422 | * check. * |
||
| 423 | * * |
||
| 424 | * Three types of check-evasion moves are generated: * |
||
| 425 | * * |
||
| 426 | * (1) Generate king moves to squares that are not attacked by the * |
||
| 427 | * opponent's pieces. This includes capture and non-capture moves. * |
||
| 428 | * * |
||
| 429 | * (2) Generate interpositions along the rank/file that the checking attack * |
||
| 430 | * is coming along (assuming (a) only one piece is checking the king, and * |
||
| 431 | * (b) the checking piece is a sliding piece [bishop, rook, queen]). * |
||
| 432 | * * |
||
| 433 | * (3) Generate capture moves, but only to the square(s) that are giving * |
||
| 434 | * check. Captures are a special case. If there is one checking piece, * |
||
| 435 | * then capturing it by any piece is tried. If there are two pieces * |
||
| 436 | * checking the king, then the only legal capture to try is for the king to * |
||
| 437 | * capture one of the checking pieces that is on an unattacked square. * |
||
| 438 | * * |
||
| 439 | ******************************************************************************* |
||
| 440 | */ |
||
| 108 | pmbaty | 441 | unsigned *GenerateCheckEvasions(TREE * RESTRICT tree, int ply, int side, |
| 442 | unsigned *move) { |
||
| 443 | uint64_t target, targetc, targetp, piecebd, moves, empty, checksqs; |
||
| 444 | uint64_t padvances1, padvances2, pcapturesl, pcapturesr, padvances1_all; |
||
| 445 | int from, to, temp, common, enemy = Flip(side), king_square, checkers; |
||
| 446 | int checking_square, check_direction1 = 0, check_direction2 = 0; |
||
| 33 | pmbaty | 447 | |
| 448 | /* |
||
| 449 | ************************************************************ |
||
| 450 | * * |
||
| 451 | * First, determine how many pieces are attacking the king * |
||
| 452 | * and where they are, so we can figure out how to legally * |
||
| 453 | * get out of check. * |
||
| 454 | * * |
||
| 455 | ************************************************************ |
||
| 456 | */ |
||
| 457 | king_square = KingSQ(side); |
||
| 458 | checksqs = AttacksTo(tree, king_square) & Occupied(enemy); |
||
| 459 | checkers = PopCnt(checksqs); |
||
| 460 | if (checkers == 1) { |
||
| 461 | checking_square = LSB(checksqs); |
||
| 462 | if (PcOnSq(checking_square) != pieces[enemy][pawn]) |
||
| 463 | check_direction1 = directions[checking_square][king_square]; |
||
| 464 | target = InterposeSquares(king_square, checking_square); |
||
| 465 | target |= checksqs; |
||
| 466 | target |= Kings(enemy); |
||
| 467 | } else { |
||
| 468 | target = Kings(enemy); |
||
| 469 | checking_square = LSB(checksqs); |
||
| 470 | if (PcOnSq(checking_square) != pieces[enemy][pawn]) |
||
| 471 | check_direction1 = directions[checking_square][king_square]; |
||
| 472 | checking_square = MSB(checksqs); |
||
| 473 | if (PcOnSq(checking_square) != pieces[enemy][pawn]) |
||
| 474 | check_direction2 = directions[checking_square][king_square]; |
||
| 475 | } |
||
| 476 | /* |
||
| 477 | ************************************************************ |
||
| 478 | * * |
||
| 479 | * The next step is to produce the set of valid * |
||
| 480 | * destination squares. For king moves, this is simply * |
||
| 481 | * the set of squares that are not attacked by enemy * |
||
| 482 | * pieces (if there are any such squares.) * |
||
| 483 | * * |
||
| 484 | * Then, if the checking piece is not a knight, we need * |
||
| 485 | * to know the checking direction so that we can either * |
||
| 486 | * move the king off of that ray, or else block that ray. * |
||
| 487 | * * |
||
| 488 | * We produce king moves by locating the only king and * |
||
| 489 | * then using that <from> square as an index into the * |
||
| 490 | * precomputed king_attacks data. * |
||
| 491 | * * |
||
| 492 | ************************************************************ |
||
| 493 | */ |
||
| 494 | from = king_square; |
||
| 495 | temp = from + (king << 12); |
||
| 496 | for (moves = king_attacks[from] & ~Occupied(side); moves; Clear(to, moves)) { |
||
| 108 | pmbaty | 497 | to = MostAdvanced(side, moves); |
| 33 | pmbaty | 498 | if (!Attacks(tree, enemy, to) |
| 499 | && directions[from][to] != check_direction1 && |
||
| 500 | directions[from][to] != check_direction2) |
||
| 501 | *move++ = temp | (to << 6) | (Abs(PcOnSq(to)) << 15); |
||
| 502 | } |
||
| 503 | /* |
||
| 504 | ************************************************************ |
||
| 505 | * * |
||
| 506 | * We produce knight moves by locating the most advanced * |
||
| 507 | * knight and then using that <from> square as an index * |
||
| 508 | * into the precomputed knight_attacks data. We repeat * |
||
| 509 | * for each knight. * |
||
| 510 | * * |
||
| 511 | ************************************************************ |
||
| 512 | */ |
||
| 513 | if (checkers == 1) { |
||
| 514 | for (piecebd = Knights(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 515 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 516 | if (!PinnedOnKing(tree, side, from)) { |
| 517 | moves = knight_attacks[from] & target; |
||
| 518 | temp = from + (knight << 12); |
||
| 519 | Extract(side, move, moves, temp); |
||
| 520 | } |
||
| 521 | } |
||
| 522 | /* |
||
| 523 | ************************************************************ |
||
| 524 | * * |
||
| 108 | pmbaty | 525 | * We produce sliding piece moves by locating each piece * |
| 526 | * type in turn. We then start with the most advanced * |
||
| 527 | * piece and generate moves from that square. This uses * |
||
| 528 | * "magic move generation" to produce the destination * |
||
| 529 | * squares. * |
||
| 33 | pmbaty | 530 | * * |
| 531 | ************************************************************ |
||
| 532 | */ |
||
| 533 | for (piecebd = Bishops(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 534 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 535 | if (!PinnedOnKing(tree, side, from)) { |
| 536 | moves = BishopAttacks(from, OccupiedSquares) & target; |
||
| 537 | temp = from + (bishop << 12); |
||
| 538 | Extract(side, move, moves, temp); |
||
| 539 | } |
||
| 540 | } |
||
| 541 | for (piecebd = Rooks(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 542 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 543 | if (!PinnedOnKing(tree, side, from)) { |
| 544 | moves = RookAttacks(from, OccupiedSquares) & target; |
||
| 545 | temp = from + (rook << 12); |
||
| 546 | Extract(side, move, moves, temp); |
||
| 547 | } |
||
| 548 | } |
||
| 549 | for (piecebd = Queens(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 550 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 551 | if (!PinnedOnKing(tree, side, from)) { |
| 552 | moves = QueenAttacks(from, OccupiedSquares) & target; |
||
| 553 | temp = from + (queen << 12); |
||
| 554 | Extract(side, move, moves, temp); |
||
| 555 | } |
||
| 556 | } |
||
| 557 | /* |
||
| 558 | ************************************************************ |
||
| 559 | * * |
||
| 560 | * Now, produce pawn moves. This is done differently due * |
||
| 561 | * to inconsistencies in the way a pawn moves when it * |
||
| 562 | * captures as opposed to normal non-capturing moves. * |
||
| 563 | * Another exception is capturing enpassant. The first * |
||
| 564 | * step is to generate all possible pawn moves. We do * |
||
| 565 | * this in 2 operations: (1) shift the pawns forward one * |
||
| 566 | * rank then AND with empty squares; (2) shift the pawns * |
||
| 567 | * forward two ranks and then AND with empty squares. * |
||
| 568 | * * |
||
| 569 | ************************************************************ |
||
| 570 | */ |
||
| 571 | empty = ~OccupiedSquares; |
||
| 572 | targetp = target & empty; |
||
| 573 | if (side) { |
||
| 574 | padvances1 = Pawns(white) << 8 & targetp; |
||
| 575 | padvances1_all = Pawns(white) << 8 & empty; |
||
| 576 | padvances2 = ((padvances1_all & ((uint64_t) 255 << 16)) << 8) & targetp; |
||
| 577 | } else { |
||
| 578 | padvances1 = Pawns(black) >> 8 & targetp; |
||
| 579 | padvances1_all = Pawns(black) >> 8 & empty; |
||
| 580 | padvances2 = ((padvances1_all & ((uint64_t) 255 << 40)) >> 8) & targetp; |
||
| 581 | } |
||
| 582 | /* |
||
| 583 | ************************************************************ |
||
| 584 | * * |
||
| 585 | * Now that we got 'em, we simply enumerate the to squares * |
||
| 586 | * as before, but in four steps since we have four sets of * |
||
| 587 | * potential moves. * |
||
| 588 | * * |
||
| 589 | ************************************************************ |
||
| 590 | */ |
||
| 591 | for (; padvances2; Clear(to, padvances2)) { |
||
| 108 | pmbaty | 592 | to = MostAdvanced(side, padvances2); |
| 33 | pmbaty | 593 | if (!PinnedOnKing(tree, side, to + pawnadv2[side])) |
| 594 | *move++ = (to + pawnadv2[side]) | (to << 6) | (pawn << 12); |
||
| 595 | } |
||
| 596 | for (; padvances1; Clear(to, padvances1)) { |
||
| 108 | pmbaty | 597 | to = MostAdvanced(side, padvances1); |
| 33 | pmbaty | 598 | if (!PinnedOnKing(tree, side, to + pawnadv1[side])) { |
| 599 | common = (to + pawnadv1[side]) | (to << 6) | (pawn << 12); |
||
| 600 | if ((side) ? to < 56 : to > 7) |
||
| 601 | *move++ = common; |
||
| 602 | else { |
||
| 603 | *move++ = common | (queen << 18); |
||
| 604 | *move++ = common | (knight << 18); |
||
| 605 | } |
||
| 606 | } |
||
| 607 | } |
||
| 108 | pmbaty | 608 | /* |
| 609 | ************************************************************ |
||
| 610 | * * |
||
| 611 | * And then we try to see if the checking piece can be * |
||
| 612 | * captured by a friendly pawn. * |
||
| 613 | * * |
||
| 614 | ************************************************************ |
||
| 615 | */ |
||
| 33 | pmbaty | 616 | targetc = Occupied(enemy) | EnPassantTarget(ply); |
| 617 | targetc = targetc & target; |
||
| 618 | if (Pawns(enemy) & target & ((side) ? EnPassantTarget(ply) >> 8 : |
||
| 619 | EnPassantTarget(ply) << 8)) |
||
| 620 | targetc = targetc | EnPassantTarget(ply); |
||
| 621 | if (side) { |
||
| 622 | pcapturesl = (Pawns(white) & mask_left_edge) << 7 & targetc; |
||
| 623 | pcapturesr = (Pawns(white) & mask_right_edge) << 9 & targetc; |
||
| 624 | } else { |
||
| 625 | pcapturesl = (Pawns(black) & mask_left_edge) >> 9 & targetc; |
||
| 626 | pcapturesr = (Pawns(black) & mask_right_edge) >> 7 & targetc; |
||
| 627 | } |
||
| 628 | for (; pcapturesl; Clear(to, pcapturesl)) { |
||
| 108 | pmbaty | 629 | to = MostAdvanced(side, pcapturesl); |
| 33 | pmbaty | 630 | if (!PinnedOnKing(tree, side, to + capleft[side])) { |
| 631 | common = (to + capleft[side]) | (to << 6) | (pawn << 12); |
||
| 632 | if ((side) ? to < 56 : to > 7) |
||
| 633 | *move++ = common | (((PcOnSq(to)) ? Abs(PcOnSq(to)) : pawn) << 15); |
||
| 634 | else { |
||
| 635 | *move++ = common | Abs(PcOnSq(to)) << 15 | queen << 18; |
||
| 636 | *move++ = common | Abs(PcOnSq(to)) << 15 | knight << 18; |
||
| 637 | } |
||
| 638 | } |
||
| 639 | } |
||
| 640 | for (; pcapturesr; Clear(to, pcapturesr)) { |
||
| 108 | pmbaty | 641 | to = MostAdvanced(side, pcapturesr); |
| 33 | pmbaty | 642 | if (!PinnedOnKing(tree, side, to + capright[side])) { |
| 643 | common = (to + capright[side]) | (to << 6) | (pawn << 12); |
||
| 644 | if ((side) ? to < 56 : to > 7) |
||
| 645 | *move++ = common | (((PcOnSq(to)) ? Abs(PcOnSq(to)) : pawn) << 15); |
||
| 646 | else { |
||
| 647 | *move++ = common | Abs(PcOnSq(to)) << 15 | queen << 18; |
||
| 648 | *move++ = common | Abs(PcOnSq(to)) << 15 | knight << 18; |
||
| 649 | } |
||
| 650 | } |
||
| 651 | } |
||
| 652 | } |
||
| 653 | return move; |
||
| 654 | } |
||
| 655 | |||
| 108 | pmbaty | 656 | /* modified 12/31/15 */ |
| 33 | pmbaty | 657 | /* |
| 658 | ******************************************************************************* |
||
| 659 | * * |
||
| 660 | * GenerateNoncaptures() is used to generate non-capture moves from the * |
||
| 661 | * current position. * |
||
| 662 | * * |
||
| 663 | * Once the valid destination squares are known, we have to locate a * |
||
| 108 | pmbaty | 664 | * friendly piece to compute the squares it attacks. * |
| 33 | pmbaty | 665 | * * |
| 666 | * Pawns are handled differently. Regular pawn moves are produced by * |
||
| 667 | * shifting the pawn bitmap 8 bits "forward" and anding this with the * |
||
| 108 | pmbaty | 668 | * complement of the occupied squares bitmap double advances are then * |
| 33 | pmbaty | 669 | * produced by anding the pawn bitmap with a mask containing 1's on the * |
| 670 | * second rank, shifting this 16 bits "forward" and then anding this with * |
||
| 671 | * the complement of the occupied squares bitmap as before. If [to] reaches * |
||
| 108 | pmbaty | 672 | * the 8th rank, we produce a set of three moves, promoting the pawn to * |
| 673 | * knight, bishop and rook (queen promotions were generated earlier by * |
||
| 674 | * GenerateCaptures()). * |
||
| 33 | pmbaty | 675 | * * |
| 676 | ******************************************************************************* |
||
| 677 | */ |
||
| 108 | pmbaty | 678 | unsigned *GenerateNoncaptures(TREE * RESTRICT tree, int ply, int side, |
| 679 | unsigned *move) { |
||
| 33 | pmbaty | 680 | uint64_t target, piecebd, moves; |
| 681 | uint64_t padvances1, padvances2, pcapturesl, pcapturesr; |
||
| 682 | int from, to, temp, common, enemy = Flip(side); |
||
| 683 | |||
| 684 | /* |
||
| 685 | ************************************************************ |
||
| 686 | * * |
||
| 108 | pmbaty | 687 | * First, produce castling moves when they are legal. * |
| 33 | pmbaty | 688 | * * |
| 689 | ************************************************************ |
||
| 690 | */ |
||
| 691 | if (Castle(ply, side) > 0) { |
||
| 692 | if (Castle(ply, side) & 1 && !(OccupiedSquares & OO[side]) |
||
| 693 | && !Attacks(tree, enemy, OOsqs[side][0]) |
||
| 694 | && !Attacks(tree, enemy, OOsqs[side][1]) |
||
| 695 | && !Attacks(tree, enemy, OOsqs[side][2])) { |
||
| 696 | *move++ = (king << 12) + (OOto[side] << 6) + OOfrom[side]; |
||
| 697 | } |
||
| 698 | if (Castle(ply, side) & 2 && !(OccupiedSquares & OOO[side]) |
||
| 699 | && !Attacks(tree, enemy, OOOsqs[side][0]) |
||
| 700 | && !Attacks(tree, enemy, OOOsqs[side][1]) |
||
| 701 | && !Attacks(tree, enemy, OOOsqs[side][2])) { |
||
| 702 | *move++ = (king << 12) + (OOOto[side] << 6) + OOfrom[side]; |
||
| 703 | } |
||
| 704 | } |
||
| 705 | target = ~OccupiedSquares; |
||
| 706 | /* |
||
| 707 | ************************************************************ |
||
| 708 | * * |
||
| 709 | * We produce knight moves by locating the most advanced * |
||
| 710 | * knight and then using that <from> square as an index * |
||
| 711 | * into the precomputed knight_attacks data. We repeat * |
||
| 712 | * for each knight. * |
||
| 713 | * * |
||
| 714 | ************************************************************ |
||
| 715 | */ |
||
| 716 | for (piecebd = Knights(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 717 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 718 | moves = knight_attacks[from] & target; |
| 719 | temp = from + (knight << 12); |
||
| 720 | Extract(side, move, moves, temp); |
||
| 721 | } |
||
| 722 | /* |
||
| 723 | ************************************************************ |
||
| 724 | * * |
||
| 108 | pmbaty | 725 | * We produce sliding piece moves by locating each piece * |
| 726 | * type in turn. We then start with the most advanced * |
||
| 727 | * piece and generate moves from that square. This uses * |
||
| 728 | * "magic move generation" to produce the destination * |
||
| 729 | * squares. * |
||
| 33 | pmbaty | 730 | * * |
| 731 | ************************************************************ |
||
| 732 | */ |
||
| 733 | for (piecebd = Bishops(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 734 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 735 | moves = BishopAttacks(from, OccupiedSquares) & target; |
| 736 | temp = from + (bishop << 12); |
||
| 737 | Extract(side, move, moves, temp); |
||
| 738 | } |
||
| 739 | for (piecebd = Rooks(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 740 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 741 | moves = RookAttacks(from, OccupiedSquares) & target; |
| 742 | temp = from + (rook << 12); |
||
| 743 | Extract(side, move, moves, temp); |
||
| 744 | } |
||
| 745 | for (piecebd = Queens(side); piecebd; Clear(from, piecebd)) { |
||
| 108 | pmbaty | 746 | from = MostAdvanced(side, piecebd); |
| 33 | pmbaty | 747 | moves = QueenAttacks(from, OccupiedSquares) & target; |
| 748 | temp = from + (queen << 12); |
||
| 749 | Extract(side, move, moves, temp); |
||
| 750 | } |
||
| 751 | /* |
||
| 752 | ************************************************************ |
||
| 753 | * * |
||
| 754 | * We produce king moves by locating the only king and * |
||
| 755 | * then using that <from> square as an index into the * |
||
| 756 | * precomputed king_attacks data. * |
||
| 757 | * * |
||
| 758 | ************************************************************ |
||
| 759 | */ |
||
| 760 | from = KingSQ(side); |
||
| 761 | moves = king_attacks[from] & target; |
||
| 762 | temp = from + (king << 12); |
||
| 763 | Extract(side, move, moves, temp); |
||
| 764 | /* |
||
| 765 | ************************************************************ |
||
| 766 | * * |
||
| 767 | * Now, produce pawn moves. This is done differently due * |
||
| 768 | * to inconsistencies in the way a pawn moves when it * |
||
| 769 | * captures as opposed to normal non-capturing moves. * |
||
| 770 | * First we generate all possible pawn moves. We do this * |
||
| 771 | * in 4 operations: (1) shift the pawns forward one rank * |
||
| 772 | * then and with empty squares; (2) shift the pawns * |
||
| 773 | * forward two ranks and then and with empty squares; * |
||
| 774 | * (3) remove the a-pawn(s) then shift the pawns * |
||
| 775 | * diagonally left then and with enemy occupied squares; * |
||
| 776 | * (4) remove the h-pawn(s) then shift the pawns * |
||
| 777 | * diagonally right then and with enemy occupied squares. * |
||
| 778 | * note that the only captures produced are under- * |
||
| 779 | * promotions, because the rest were done in GenCap. * |
||
| 780 | * * |
||
| 781 | ************************************************************ |
||
| 782 | */ |
||
| 783 | padvances1 = ((side) ? Pawns(side) << 8 : Pawns(side) >> 8) & target; |
||
| 784 | padvances2 = |
||
| 785 | ((side) ? (padvances1 & mask_advance_2_w) << 8 : (padvances1 & |
||
| 786 | mask_advance_2_b) >> 8) & target; |
||
| 787 | /* |
||
| 788 | ************************************************************ |
||
| 789 | * * |
||
| 790 | * Now that we got 'em, we simply enumerate the to * |
||
| 791 | * squares as before, but in four steps since we have * |
||
| 792 | * four sets of potential moves. * |
||
| 793 | * * |
||
| 794 | ************************************************************ |
||
| 795 | */ |
||
| 796 | for (; padvances2; Clear(to, padvances2)) { |
||
| 108 | pmbaty | 797 | to = MostAdvanced(side, padvances2); |
| 33 | pmbaty | 798 | *move++ = (to + pawnadv2[side]) | (to << 6) | (pawn << 12); |
| 799 | } |
||
| 800 | for (; padvances1; Clear(to, padvances1)) { |
||
| 108 | pmbaty | 801 | to = MostAdvanced(side, padvances1); |
| 33 | pmbaty | 802 | common = (to + pawnadv1[side]) | (to << 6) | (pawn << 12); |
| 803 | if ((side) ? to < 56 : to > 7) |
||
| 804 | *move++ = common; |
||
| 805 | else { |
||
| 806 | *move++ = common | (rook << 18); |
||
| 807 | *move++ = common | (bishop << 18); |
||
| 808 | *move++ = common | (knight << 18); |
||
| 809 | } |
||
| 810 | } |
||
| 811 | /* |
||
| 812 | ************************************************************ |
||
| 813 | * * |
||
| 108 | pmbaty | 814 | * Generate the rest of the promotions here since * |
| 815 | * GenerateCaptures() only generated captures or * |
||
| 33 | pmbaty | 816 | * promotions to a queen. * |
| 817 | * * |
||
| 818 | ************************************************************ |
||
| 819 | */ |
||
| 108 | pmbaty | 820 | target = Occupied(enemy) & rank_mask[rank8[side]]; |
| 33 | pmbaty | 821 | pcapturesl = |
| 822 | ((side) ? (Pawns(white) & mask_left_edge) << 7 : (Pawns(black) & |
||
| 823 | mask_left_edge) >> 9) & target; |
||
| 824 | for (; pcapturesl; Clear(to, pcapturesl)) { |
||
| 108 | pmbaty | 825 | to = MostAdvanced(side, pcapturesl); |
| 33 | pmbaty | 826 | common = (to + capleft[side]) | (to << 6) | (pawn << 12); |
| 827 | *move++ = common | (Abs(PcOnSq(to)) << 15) | (rook << 18); |
||
| 828 | *move++ = common | (Abs(PcOnSq(to)) << 15) | (bishop << 18); |
||
| 829 | *move++ = common | (Abs(PcOnSq(to)) << 15) | (knight << 18); |
||
| 830 | } |
||
| 831 | pcapturesr = |
||
| 832 | ((side) ? (Pawns(white) & mask_right_edge) << 9 : (Pawns(black) & |
||
| 833 | mask_right_edge) >> 7) & target; |
||
| 834 | for (; pcapturesr; Clear(to, pcapturesr)) { |
||
| 108 | pmbaty | 835 | to = MostAdvanced(side, pcapturesr); |
| 33 | pmbaty | 836 | common = (to + capright[side]) | (to << 6) | (pawn << 12); |
| 837 | *move++ = common | (Abs(PcOnSq(to)) << 15) | (rook << 18); |
||
| 838 | *move++ = common | (Abs(PcOnSq(to)) << 15) | (bishop << 18); |
||
| 839 | *move++ = common | (Abs(PcOnSq(to)) << 15) | (knight << 18); |
||
| 840 | } |
||
| 841 | return move; |
||
| 842 | } |
||
| 843 | |||
| 108 | pmbaty | 844 | /* modified 12/31/15 */ |
| 33 | pmbaty | 845 | /* |
| 846 | ******************************************************************************* |
||
| 847 | * * |
||
| 848 | * PinnedOnKing() is used to determine if the piece on <square> is pinned * |
||
| 849 | * against the king, so that it's illegal to move it. This is used to cull * |
||
| 850 | * potential moves by GenerateCheckEvasions() so that illegal moves are not * |
||
| 851 | * produced. * |
||
| 852 | * * |
||
| 853 | ******************************************************************************* |
||
| 854 | */ |
||
| 855 | int PinnedOnKing(TREE * RESTRICT tree, int side, int square) { |
||
| 108 | pmbaty | 856 | int ray, enemy = Flip(side); |
| 33 | pmbaty | 857 | |
| 858 | /* |
||
| 859 | ************************************************************ |
||
| 860 | * * |
||
| 861 | * First, determine if the piece being moved is on the * |
||
| 862 | * same diagonal, rank or file as the king. If not, then * |
||
| 863 | * it can't be pinned and we return (0). * |
||
| 864 | * * |
||
| 865 | ************************************************************ |
||
| 866 | */ |
||
| 867 | ray = directions[square][KingSQ(side)]; |
||
| 868 | if (!ray) |
||
| 869 | return 0; |
||
| 870 | /* |
||
| 871 | ************************************************************ |
||
| 872 | * * |
||
| 873 | * If they are on the same ray, then determine if the king * |
||
| 874 | * blocks a bishop attack in one direction from this * |
||
| 875 | * square and a bishop or queen blocks a bishop attack on * |
||
| 876 | * the same diagonal in the opposite direction (or the * |
||
| 877 | * same rank/file for rook/queen.) * |
||
| 878 | * * |
||
| 879 | ************************************************************ |
||
| 880 | */ |
||
| 881 | switch (Abs(ray)) { |
||
| 882 | case 1: |
||
| 883 | if (RankAttacks(square) & Kings(side)) |
||
| 884 | return (RankAttacks(square) & (Rooks(enemy) | Queens(enemy))) != 0; |
||
| 885 | else |
||
| 886 | return 0; |
||
| 887 | case 7: |
||
| 888 | if (Diagh1Attacks(square) & Kings(side)) |
||
| 889 | return (Diagh1Attacks(square) & (Bishops(enemy) | Queens(enemy))) != |
||
| 890 | 0; |
||
| 891 | else |
||
| 892 | return 0; |
||
| 893 | case 8: |
||
| 894 | if (FileAttacks(square) & Kings(side)) |
||
| 895 | return (FileAttacks(square) & (Rooks(enemy) | Queens(enemy))) != 0; |
||
| 896 | else |
||
| 897 | return 0; |
||
| 898 | case 9: |
||
| 899 | if (Diaga1Attacks(square) & Kings(side)) |
||
| 900 | return (Diaga1Attacks(square) & (Bishops(enemy) | Queens(enemy))) != |
||
| 901 | 0; |
||
| 902 | else |
||
| 903 | return 0; |
||
| 904 | } |
||
| 905 | return 0; |
||
| 906 | } |