1from .bitboard import bitPosArray, iterBits, clearBit, firstBit 2from .attack import isAttacked, pinnedOnKing, getAttacks 3from .ldata import fromToRay, moveArray, directions, fileBits, rankBits,\ 4 ray45, attack45, ray135, attack135, ray90, attack90, ray00, attack00, FILE, rays 5from pychess.Utils.const import EMPTY, PAWN,\ 6 QUEEN, KNIGHT, BISHOP, ROOK, KING, WHITE, BLACK,\ 7 SITTUYINCHESS, FISCHERRANDOMCHESS, SUICIDECHESS, GIVEAWAYCHESS, CAMBODIANCHESS,\ 8 ATOMICCHESS, WILDCASTLECHESS, WILDCASTLESHUFFLECHESS, CRAZYHOUSECHESS, ASEAN_VARIANTS,\ 9 HORDECHESS, PLACEMENTCHESS, BPAWN, sliders,\ 10 A8, A6, G6, F6, H1, C3, B2, B3, A3, D6, D8, E3, E1, E8, C7, F2, D1, E6, H3, D3, H2, G7, H6, H7,\ 11 ASEAN_QUEEN, ASEAN_BBISHOP, ASEAN_WBISHOP, NORMAL_MOVE, QUEEN_CASTLE, KING_CASTLE, ENPASSANT,\ 12 KNIGHT_PROMOTION, BISHOP_PROMOTION, ROOK_PROMOTION, QUEEN_PROMOTION, KING_PROMOTION, NULL_MOVE,\ 13 DROP_VARIANTS, DROP, B_OOO, B_OO, W_OOO, W_OO 14 15# The format of a move is as follows - from left: 16# 4 bits: Descriping the type of the move 17# 6 bits: cord to move from 18# 6 bits: cord to move to 19 20shiftedFromCords = [] 21for i in range(64): 22 shiftedFromCords.append(i << 6) 23 24shiftedFlags = [] 25for i in NORMAL_MOVE, QUEEN_CASTLE, KING_CASTLE, ENPASSANT, \ 26 KNIGHT_PROMOTION, BISHOP_PROMOTION, ROOK_PROMOTION, QUEEN_PROMOTION, KING_PROMOTION, NULL_MOVE, DROP: 27 shiftedFlags.append(i << 12) 28 29 30def newMove(fromcord, tocord, flag=NORMAL_MOVE): 31 return shiftedFlags[flag] + shiftedFromCords[fromcord] + tocord 32 33# Generate all moves 34 35 36def genCastles(board): 37 def generateOne(color, side, king_after, rook_after): 38 if side == 0: 39 castle = QUEEN_CASTLE 40 else: 41 castle = KING_CASTLE 42 king = board.ini_kings[color] 43 rook = board.ini_rooks[color][side] 44 blocker = clearBit(clearBit(board.blocker, king), rook) 45 stepover = fromToRay[king][king_after] | fromToRay[rook][rook_after] 46 if not stepover & blocker: 47 for cord in range( 48 min(king, king_after), max(king, king_after) + 1): 49 if isAttacked(board, cord, 1 - color): 50 return 51 if FILE(king) == 3 and board.variant in (WILDCASTLECHESS, 52 WILDCASTLESHUFFLECHESS): 53 castle = QUEEN_CASTLE if castle == KING_CASTLE else KING_CASTLE 54 if board.variant == FISCHERRANDOMCHESS: 55 return newMove(king, rook, castle) 56 else: 57 return newMove(king, king_after, castle) 58 59 king = board.ini_kings[board.color] 60 wildcastle = FILE(king) == 3 and board.variant in (WILDCASTLECHESS, 61 WILDCASTLESHUFFLECHESS) 62 if board.color == WHITE: 63 if board.castling & W_OO: 64 side = 0 if wildcastle else 1 65 move = generateOne(WHITE, side, board.fin_kings[WHITE][side], 66 board.fin_rooks[WHITE][side]) 67 if move: 68 yield move 69 70 if board.castling & W_OOO: 71 side = 1 if wildcastle else 0 72 move = generateOne(WHITE, side, board.fin_kings[WHITE][side], 73 board.fin_rooks[WHITE][side]) 74 if move: 75 yield move 76 else: 77 if board.castling & B_OO: 78 side = 0 if wildcastle else 1 79 move = generateOne(BLACK, side, board.fin_kings[BLACK][side], 80 board.fin_rooks[BLACK][side]) 81 if move: 82 yield move 83 84 if board.castling & B_OOO: 85 side = 1 if wildcastle else 0 86 move = generateOne(BLACK, side, board.fin_kings[BLACK][side], 87 board.fin_rooks[BLACK][side]) 88 if move: 89 yield move 90 91 92def genPieceMoves(board, piece, tcord): 93 """" 94 Used by parseSAN only to accelerate it a bit 95 """ 96 moves = set() 97 friends = board.friends[board.color] 98 notfriends = ~friends 99 if piece == KNIGHT: 100 knights = board.boards[board.color][KNIGHT] 101 knightMoves = moveArray[KNIGHT] 102 for fcord in iterBits(knights): 103 if tcord in iterBits(knightMoves[fcord] & notfriends): 104 moves.add(newMove(fcord, tcord)) 105 return moves 106 107 if piece == BISHOP: 108 bishops = board.boards[board.color][BISHOP] 109 if board.variant in ASEAN_VARIANTS: 110 bishopMoves = moveArray[ASEAN_WBISHOP if board.color == WHITE else 111 ASEAN_BBISHOP] 112 for fcord in iterBits(bishops): 113 if tcord in iterBits(bishopMoves[fcord] & notfriends): 114 moves.add(newMove(fcord, tcord)) 115 return moves 116 else: 117 blocker = board.blocker 118 for fcord in iterBits(bishops): 119 try: 120 attackBoard = attack45[fcord][ray45[fcord] & blocker] | \ 121 attack135[fcord][ray135[fcord] & blocker] 122 except KeyError: 123 attackBoard = 0 124 if tcord in iterBits(attackBoard & notfriends): 125 moves.add(newMove(fcord, tcord)) 126 return moves 127 128 if piece == ROOK: 129 blocker = board.blocker 130 rooks = board.boards[board.color][ROOK] 131 for fcord in iterBits(rooks): 132 try: 133 attackBoard = attack00[fcord][ray00[fcord] & blocker] | \ 134 attack90[fcord][ray90[fcord] & blocker] 135 except KeyError: 136 attackBoard = 0 137 if tcord in iterBits(attackBoard & notfriends): 138 moves.add(newMove(fcord, tcord)) 139 return moves 140 141 if piece == QUEEN: 142 queens = board.boards[board.color][QUEEN] 143 if board.variant in ASEAN_VARIANTS: 144 queenMoves = moveArray[ASEAN_QUEEN] 145 for fcord in iterBits(queens): 146 if tcord in iterBits(queenMoves[fcord] & notfriends): 147 moves.add(newMove(fcord, tcord)) 148 # Cambodian extra first move 149 if board.variant == CAMBODIANCHESS: 150 if board.is_first_move[QUEEN][board.color]: 151 if board.color == WHITE: 152 if not board.arBoard[E3]: 153 moves.add(newMove(E1, E3)) 154 else: 155 if not board.arBoard[D6]: 156 moves.add(newMove(D8, D6)) 157 return moves 158 else: 159 blocker = board.blocker 160 for fcord in iterBits(queens): 161 try: 162 attackBoard = attack45[fcord][ray45[fcord] & blocker] | \ 163 attack135[fcord][ray135[fcord] & blocker] 164 except KeyError: 165 attackBoard = 0 166 if tcord in iterBits(attackBoard & notfriends): 167 moves.add(newMove(fcord, tcord)) 168 169 try: 170 attackBoard = attack00[fcord][ray00[fcord] & blocker] | \ 171 attack90[fcord][ray90[fcord] & blocker] 172 except KeyError: 173 attackBoard = 0 174 if tcord in iterBits(attackBoard & notfriends): 175 moves.add(newMove(fcord, tcord)) 176 return moves 177 178 if (board.variant == SUICIDECHESS or board.variant == GIVEAWAYCHESS) and piece == KING: 179 kings = board.boards[board.color][KING] 180 if kings: 181 kingMoves = moveArray[KING] 182 for fcord in iterBits(kings): 183 for tc in iterBits(kingMoves[fcord] & notfriends): 184 if tc == tcord: 185 moves.add(newMove(fcord, tcord)) 186 return moves 187 188 return moves 189 190 191def gen_sittuyin_promotions(board): 192 from pychess.Variants import variants 193 blocker = board.blocker 194 notblocker = ~blocker 195 196 pawns = board.boards[board.color][PAWN] 197 198 queenMoves = moveArray[ASEAN_QUEEN] 199 200 def willDirectAttack(board, move, cord): 201 board_clone = board.clone() 202 board_clone.applyMove(move) 203 return board.friends[1 - board.color] & moveArray[ASEAN_QUEEN][cord] 204 205 promotion_zone = variants[SITTUYINCHESS].PROMOTION_ZONE[board.color] 206 for cord in iterBits(pawns): 207 if board.pieceCount[board.color][PAWN] == 1 or cord in promotion_zone: 208 # in place promotions 209 move = newMove(cord, cord, QUEEN_PROMOTION) 210 if not board.willGiveCheck(move) and not willDirectAttack(board, move, cord): 211 yield move 212 213 # queen move promotion 214 for c in iterBits(queenMoves[cord] & notblocker): 215 move = newMove(cord, c, QUEEN_PROMOTION) 216 if not board.willGiveCheck(move) and not willDirectAttack(board, move, c): 217 yield move 218 219 220def genAllMoves(board, drops=True): 221 from pychess.Variants import variants 222 if drops and board.variant in DROP_VARIANTS: 223 for move in genDrops(board): 224 yield move 225 226 # In sittuyin you have to place your pieces before any real move 227 if board.variant == SITTUYINCHESS or board.variant == PLACEMENTCHESS: 228 if board.plyCount < 16: 229 return 230 231 blocker = board.blocker 232 notblocker = ~blocker 233 enpassant = board.enpassant 234 235 friends = board.friends[board.color] 236 notfriends = ~friends 237 enemies = board.friends[1 - board.color] 238 239 pawns = board.boards[board.color][PAWN] 240 knights = board.boards[board.color][KNIGHT] 241 bishops = board.boards[board.color][BISHOP] 242 rooks = board.boards[board.color][ROOK] 243 queens = board.boards[board.color][QUEEN] 244 kings = board.boards[board.color][KING] 245 246 PROMOTIONS = variants[board.variant].PROMOTIONS 247 # In sittuyin only one queen allowed to exist any time per side 248 if board.variant == SITTUYINCHESS and queens: 249 PROMOTIONS = (NORMAL_MOVE, ) 250 251 # Knights 252 knightMoves = moveArray[KNIGHT] 253 for cord in iterBits(knights): 254 for c in iterBits(knightMoves[cord] & notfriends): 255 yield newMove(cord, c) 256 257 # King 258 if kings: 259 kingMoves = moveArray[KING] 260 # cord = firstBit(kings) 261 for cord in iterBits(kings): 262 for c in iterBits(kingMoves[cord] & notfriends): 263 if board.variant == ATOMICCHESS: 264 if not board.arBoard[c]: 265 yield newMove(cord, c) 266 else: 267 yield newMove(cord, c) 268 269 if board.variant in ASEAN_VARIANTS: 270 # Rooks 271 for cord in iterBits(rooks): 272 try: 273 attackBoard = attack00[cord][ray00[cord] & blocker] | \ 274 attack90[cord][ray90[cord] & blocker] 275 except KeyError: 276 attackBoard = 0 277 for c in iterBits(attackBoard & notfriends): 278 yield newMove(cord, c) 279 280 # Queens 281 queenMoves = moveArray[ASEAN_QUEEN] 282 for cord in iterBits(queens): 283 for c in iterBits(queenMoves[cord] & notfriends): 284 yield newMove(cord, c) 285 286 # Bishops 287 bishopMoves = moveArray[ASEAN_WBISHOP if board.color == WHITE else 288 ASEAN_BBISHOP] 289 for cord in iterBits(bishops): 290 for c in iterBits(bishopMoves[cord] & notfriends): 291 yield newMove(cord, c) 292 293 else: 294 # Rooks and Queens 295 for cord in iterBits(rooks | queens): 296 try: 297 attackBoard = attack00[cord][ray00[cord] & blocker] | \ 298 attack90[cord][ray90[cord] & blocker] 299 except KeyError: 300 attackBoard = 0 301 for c in iterBits(attackBoard & notfriends): 302 yield newMove(cord, c) 303 304 # Bishops and Queens 305 for cord in iterBits(bishops | queens): 306 try: 307 attackBoard = attack45[cord][ray45[cord] & blocker] | \ 308 attack135[cord][ray135[cord] & blocker] 309 except KeyError: 310 attackBoard = 0 311 for c in iterBits(attackBoard & notfriends): 312 yield newMove(cord, c) 313 314 # White pawns 315 pawnEnemies = enemies | (enpassant is not None and bitPosArray[enpassant] or 0) 316 if board.color == WHITE: 317 318 # One step 319 320 if board.variant == SITTUYINCHESS: 321 promotion_zone = [] 322 else: 323 promotion_zone = variants[board.variant].PROMOTION_ZONE[WHITE] 324 movedpawns = (pawns >> 325 8) & notblocker # Move all pawns one step forward 326 for cord in iterBits(movedpawns): 327 if cord in promotion_zone: 328 for p in PROMOTIONS: 329 yield newMove(cord - 8, cord, p) 330 else: 331 yield newMove(cord - 8, cord) 332 333 # Two steps 334 335 seccondrow = pawns & rankBits[1] # Get seccond row pawns 336 movedpawns = (seccondrow >> 337 8) & notblocker # Move two steps forward, while 338 movedpawns = (movedpawns >> 339 8) & notblocker # ensuring middle cord is clear 340 for cord in iterBits(movedpawns): 341 yield newMove(cord - 16, cord) 342 343 # In horde white pawns on first rank may move two squares also 344 if board.variant == HORDECHESS: 345 firstrow = pawns & rankBits[0] # Get first row pawns 346 movedpawns = (firstrow >> 347 8) & notblocker # Move two steps forward, while 348 movedpawns = (movedpawns >> 349 8) & notblocker # ensuring middle cord is clear 350 for cord in iterBits(movedpawns): 351 yield newMove(cord - 16, cord) 352 353 # Capture left 354 355 capLeftPawns = pawns & ~fileBits[0] 356 capLeftPawns = (capLeftPawns >> 7) & pawnEnemies 357 for cord in iterBits(capLeftPawns): 358 if cord in promotion_zone: 359 for p in PROMOTIONS: 360 yield newMove(cord - 7, cord, p) 361 elif cord == enpassant: 362 yield newMove(cord - 7, cord, ENPASSANT) 363 else: 364 yield newMove(cord - 7, cord) 365 366 # Capture right 367 368 capRightPawns = pawns & ~fileBits[7] 369 capRightPawns = (capRightPawns >> 9) & pawnEnemies 370 for cord in iterBits(capRightPawns): 371 if cord in promotion_zone: 372 for p in PROMOTIONS: 373 yield newMove(cord - 9, cord, p) 374 elif cord == enpassant: 375 yield newMove(cord - 9, cord, ENPASSANT) 376 else: 377 yield newMove(cord - 9, cord) 378 379 # Black pawns 380 else: 381 382 # One step 383 384 if board.variant == SITTUYINCHESS: 385 promotion_zone = [] 386 else: 387 promotion_zone = variants[board.variant].PROMOTION_ZONE[BLACK] 388 movedpawns = (pawns << 8) & notblocker 389 movedpawns &= 0xffffffffffffffff # contrain to 64 bits 390 for cord in iterBits(movedpawns): 391 if cord in promotion_zone: 392 for p in PROMOTIONS: 393 yield newMove(cord + 8, cord, p) 394 else: 395 yield newMove(cord + 8, cord) 396 397 # Two steps 398 399 seccondrow = pawns & rankBits[6] # Get seventh row pawns 400 # Move two steps forward, while ensuring middle cord is clear 401 movedpawns = seccondrow << 8 & notblocker 402 movedpawns = movedpawns << 8 & notblocker 403 for cord in iterBits(movedpawns): 404 yield newMove(cord + 16, cord) 405 406 # Capture left 407 408 capLeftPawns = pawns & ~fileBits[7] 409 capLeftPawns = capLeftPawns << 7 & pawnEnemies 410 for cord in iterBits(capLeftPawns): 411 if cord in promotion_zone: 412 for p in PROMOTIONS: 413 yield newMove(cord + 7, cord, p) 414 elif cord == enpassant: 415 yield newMove(cord + 7, cord, ENPASSANT) 416 else: 417 yield newMove(cord + 7, cord) 418 419 # Capture right 420 421 capRightPawns = pawns & ~fileBits[0] 422 capRightPawns = capRightPawns << 9 & pawnEnemies 423 for cord in iterBits(capRightPawns): 424 if cord in promotion_zone: 425 for p in PROMOTIONS: 426 yield newMove(cord + 9, cord, p) 427 elif cord == enpassant: 428 yield newMove(cord + 9, cord, ENPASSANT) 429 else: 430 yield newMove(cord + 9, cord) 431 432 # Sittuyin promotions 433 if board.variant == SITTUYINCHESS and pawns and not queens: 434 for move in gen_sittuyin_promotions(board): 435 yield move 436 437 # Cambodian extra first moves for king and queen 438 if board.variant == CAMBODIANCHESS: 439 if board.arBoard[board.ini_kings[board.color]] == KING and \ 440 board.is_first_move[KING][board.color]: 441 if board.color == WHITE: 442 if not board.arBoard[B2]: 443 yield newMove(D1, B2) 444 if not board.arBoard[F2]: 445 yield newMove(D1, F2) 446 else: 447 if not board.arBoard[C7]: 448 yield newMove(E8, C7) 449 if not board.arBoard[G7]: 450 yield newMove(E8, G7) 451 if board.arBoard[board.ini_queens[board.color]] == QUEEN and \ 452 board.is_first_move[QUEEN][board.color]: 453 if board.color == WHITE: 454 if not board.arBoard[E3]: 455 yield newMove(E1, E3) 456 else: 457 if not board.arBoard[D6]: 458 yield newMove(D8, D6) 459 460 # Castling 461 if kings: 462 for move in genCastles(board): 463 yield move 464 465################################################################################ 466# Generate capturing moves # 467################################################################################ 468 469 470def genCaptures(board): 471 from pychess.Variants import variants 472 473 blocker = board.blocker 474 enpassant = board.enpassant 475 476 enemies = board.friends[1 - board.color] 477 478 pawns = board.boards[board.color][PAWN] 479 knights = board.boards[board.color][KNIGHT] 480 bishops = board.boards[board.color][BISHOP] 481 rooks = board.boards[board.color][ROOK] 482 queens = board.boards[board.color][QUEEN] 483 kings = board.boards[board.color][KING] 484 485 PROMOTIONS = variants[board.variant].PROMOTIONS 486 # In sittuyin promotion can't give capture 487 if board.variant == SITTUYINCHESS: 488 PROMOTIONS = (NORMAL_MOVE, ) 489 490 # Knights 491 knightMoves = moveArray[KNIGHT] 492 for cord in iterBits(knights): 493 for c in iterBits(knightMoves[cord] & enemies): 494 yield newMove(cord, c) 495 496 # King 497 if kings: 498 kingMoves = moveArray[KING] 499 # cord = firstBit(kings) 500 for cord in iterBits(kings): 501 for c in iterBits(kingMoves[cord] & enemies): 502 if board.variant != ATOMICCHESS: 503 yield newMove(cord, c) 504 505 # Rooks and Queens 506 if board.variant in ASEAN_VARIANTS: 507 for cord in iterBits(rooks): 508 try: 509 attackBoard = attack00[cord][ray00[cord] & blocker] | \ 510 attack90[cord][ray90[cord] & blocker] 511 except KeyError: 512 attackBoard = 0 513 for c in iterBits(attackBoard & enemies): 514 yield newMove(cord, c) 515 else: 516 for cord in iterBits(rooks | queens): 517 try: 518 attackBoard = attack00[cord][ray00[cord] & blocker] | \ 519 attack90[cord][ray90[cord] & blocker] 520 except KeyError: 521 attackBoard = 0 522 for c in iterBits(attackBoard & enemies): 523 yield newMove(cord, c) 524 525 # Bishops and Queens 526 if board.variant in ASEAN_VARIANTS: 527 bishopMoves = moveArray[ASEAN_WBISHOP if board.color == WHITE else 528 ASEAN_BBISHOP] 529 for cord in iterBits(bishops): 530 for c in iterBits(bishopMoves[cord] & enemies): 531 yield newMove(cord, c) 532 queenMoves = moveArray[ASEAN_QUEEN] 533 for cord in iterBits(queens): 534 for c in iterBits(queenMoves[cord] & enemies): 535 yield newMove(cord, c) 536 else: 537 for cord in iterBits(bishops | queens): 538 try: 539 attackBoard = attack45[cord][ray45[cord] & blocker] | \ 540 attack135[cord][ray135[cord] & blocker] 541 except KeyError: 542 attackBoard = 0 543 for c in iterBits(attackBoard & enemies): 544 yield newMove(cord, c) 545 546 # White pawns 547 pawnEnemies = enemies | (enpassant is not None and bitPosArray[enpassant] or 0) 548 549 if board.color == WHITE: 550 promotion_zone = variants[board.variant].PROMOTION_ZONE[WHITE] 551 552 # Promotes 553 554 # Capture left 555 556 capLeftPawns = pawns & ~fileBits[0] 557 capLeftPawns = (capLeftPawns >> 7) & pawnEnemies 558 for cord in iterBits(capLeftPawns): 559 if cord in promotion_zone: 560 for p in PROMOTIONS: 561 yield newMove(cord - 7, cord, p) 562 elif cord == enpassant: 563 yield newMove(cord - 7, cord, ENPASSANT) 564 else: 565 yield newMove(cord - 7, cord) 566 567 # Capture right 568 569 capRightPawns = pawns & ~fileBits[7] 570 capRightPawns = (capRightPawns >> 9) & pawnEnemies 571 for cord in iterBits(capRightPawns): 572 if cord in promotion_zone: 573 for p in PROMOTIONS: 574 yield newMove(cord - 9, cord, p) 575 elif cord == enpassant: 576 yield newMove(cord - 9, cord, ENPASSANT) 577 else: 578 yield newMove(cord - 9, cord) 579 580 # Black pawns 581 else: 582 promotion_zone = variants[board.variant].PROMOTION_ZONE[BLACK] 583 584 # One step 585 586 # Capture left 587 588 capLeftPawns = pawns & ~fileBits[7] 589 capLeftPawns = capLeftPawns << 7 & pawnEnemies 590 for cord in iterBits(capLeftPawns): 591 if cord in promotion_zone: 592 for p in PROMOTIONS: 593 yield newMove(cord + 7, cord, p) 594 elif cord == enpassant: 595 yield newMove(cord + 7, cord, ENPASSANT) 596 else: 597 yield newMove(cord + 7, cord) 598 599 # Capture right 600 601 capRightPawns = pawns & ~fileBits[0] 602 capRightPawns = capRightPawns << 9 & pawnEnemies 603 for cord in iterBits(capRightPawns): 604 if cord in promotion_zone: 605 for p in PROMOTIONS: 606 yield newMove(cord + 9, cord, p) 607 elif cord == enpassant: 608 yield newMove(cord + 9, cord, ENPASSANT) 609 else: 610 yield newMove(cord + 9, cord) 611 612################################################################################ 613# Generate escapes from check # 614################################################################################ 615 616 617def genCheckEvasions(board): 618 from pychess.Variants import variants 619 color = board.color 620 opcolor = 1 - color 621 622 kcord = board.kings[color] 623 kings = board.boards[color][KING] 624 pawns = board.boards[color][PAWN] 625 queens = board.boards[board.color][QUEEN] 626 checkers = getAttacks(board, kcord, opcolor) 627 628 arBoard = board.arBoard 629 if bin(checkers).count("1") == 1: 630 631 PROMOTIONS = variants[board.variant].PROMOTIONS 632 # In sittuyin promotion move not allowed to capture opponent pieces 633 if board.variant == SITTUYINCHESS and board.boards[board.color][QUEEN]: 634 PROMOTIONS = (NORMAL_MOVE, ) 635 promotion_zone = variants[board.variant].PROMOTION_ZONE[color] 636 637 # Captures of checking pieces (except by king, which we will test later) 638 chkcord = firstBit(checkers) 639 b = getAttacks(board, chkcord, color) & ~kings 640 for cord in iterBits(b): 641 if not pinnedOnKing(board, cord, color): 642 if arBoard[cord] == PAWN and chkcord in promotion_zone and board.variant != SITTUYINCHESS: 643 for p in PROMOTIONS: 644 yield newMove(cord, chkcord, p) 645 else: 646 yield newMove(cord, chkcord) 647 648 # Maybe enpassant can help 649 if board.enpassant: 650 ep = board.enpassant 651 if ep + (color == WHITE and -8 or 8) == chkcord: 652 bits = moveArray[color == WHITE and BPAWN or PAWN][ep] & pawns 653 for cord in iterBits(bits): 654 if not pinnedOnKing(board, cord, color): 655 yield newMove(cord, ep, ENPASSANT) 656 657 # Lets block/capture the checking piece 658 if sliders[arBoard[chkcord]]: 659 bits = clearBit(fromToRay[kcord][chkcord], chkcord) 660 661 for cord in iterBits(bits): 662 b = getAttacks(board, cord, color) 663 b &= ~(kings | pawns) 664 665 # Add in pawn advances 666 if color == WHITE and cord > H2: 667 if bitPosArray[cord - 8] & pawns: 668 b |= bitPosArray[cord - 8] 669 if cord >> 3 == 3 and arBoard[cord - 8] == EMPTY and \ 670 bitPosArray[cord - 16] & pawns: 671 b |= bitPosArray[cord - 16] 672 673 elif color == BLACK and cord < H7: 674 if bitPosArray[cord + 8] & pawns: 675 b |= bitPosArray[cord + 8] 676 if cord >> 3 == 4 and arBoard[cord + 8] == EMPTY and \ 677 bitPosArray[cord + 16] & pawns: 678 b |= bitPosArray[cord + 16] 679 680 for fcord in iterBits(b): 681 # If the piece is blocking another attack, we cannot move it 682 if pinnedOnKing(board, fcord, color): 683 continue 684 if arBoard[fcord] == PAWN and cord in promotion_zone: 685 for p in PROMOTIONS: 686 yield newMove(fcord, cord, p) 687 else: 688 yield newMove(fcord, cord) 689 690 if board.variant == CRAZYHOUSECHESS: 691 holding = board.holding[color] 692 for piece in holding: 693 if holding[piece] > 0: 694 if piece == PAWN: 695 if cord >= 56 or cord <= 7: 696 continue 697 yield newMove(piece, cord, DROP) 698 699 if board.variant == SITTUYINCHESS and pawns and not queens: 700 from .lmove import TCORD 701 for move in gen_sittuyin_promotions(board): 702 if TCORD(move) == cord: 703 yield move 704 705 # If more than one checkers, move king to get out of check 706 if checkers: 707 escapes = moveArray[KING][kcord] & ~board.friends[color] 708 else: 709 escapes = 0 710 711 for chkcord in iterBits(checkers): 712 dir = directions[chkcord][kcord] 713 if sliders[arBoard[chkcord]]: 714 escapes &= ~rays[chkcord][dir] 715 716 for cord in iterBits(escapes): 717 if not isAttacked(board, cord, opcolor): 718 yield newMove(kcord, cord) 719 720 721def genDrops(board): 722 color = board.color 723 arBoard = board.arBoard 724 holding = board.holding[color] 725 for piece in holding: 726 if holding[piece] > 0: 727 for cord, elem in enumerate(arBoard): 728 if elem == EMPTY: 729 # forbidden drop moves 730 if board.variant == SITTUYINCHESS: 731 if color == WHITE: 732 if cord in (A3, B3, C3, D3) or cord > H3: 733 continue 734 if piece == ROOK and cord > H1: 735 continue 736 else: 737 if cord in (E6, F6, G6, H6) or cord < A6: 738 continue 739 if piece == ROOK and cord < A8: 740 continue 741 742 elif board.variant == PLACEMENTCHESS: 743 # drop pieces enabled on base line only 744 if color == WHITE: 745 if cord > H1: 746 continue 747 else: 748 if cord < A8: 749 continue 750 751 # bishops must be on opposite colour squares 752 base_line = arBoard[0:8] if color == WHITE else arBoard[56:64] 753 occupied_colors = [0, 0] 754 occupied_colors[cord % 2] += 1 755 for i, baseline_piece in enumerate(base_line): 756 if baseline_piece != EMPTY: 757 occupied_colors[i % 2] += 1 758 759 if holding[BISHOP] == 2 and piece != BISHOP: 760 # occupying all same colored fields before any bishop dropped is no-no 761 if occupied_colors[WHITE] == 4 or occupied_colors[BLACK] == 4: 762 continue 763 elif holding[BISHOP] == 1: 764 for i, baseline_piece in enumerate(base_line): 765 if baseline_piece == BISHOP: 766 first_bishop_cord = i 767 break 768 # occupying all possible place of opp colored bishop is no-no 769 if piece != BISHOP and occupied_colors[1 - first_bishop_cord % 2] == 4: 770 continue 771 # same colored bishop is no-no 772 elif piece == BISHOP and first_bishop_cord % 2 == cord % 2: 773 continue 774 775 if piece == PAWN: 776 if cord >= 56 or cord <= 7: 777 continue 778 779 yield newMove(piece, cord, DROP) 780