1from pychess.Utils.Cord import Cord 2from pychess.Utils.const import DROP, NORMAL_MOVE, PAWN, SITTUYINCHESS, QUEEN, KING, \ 3 NULL_MOVE, WHITE, BLACK, W_OOO, W_OO, B_OOO, B_OO, QUEEN_CASTLE, FISCHERRANDOMCHESS,\ 4 KING_CASTLE, CAMBODIANCHESS, ENPASSANT, PROMOTIONS, CASTLE_SAN, C1, G1, reprSign 5from pychess.Utils.lutils.lmovegen import newMove 6from .lutils import lmove 7 8 9class Move: 10 11 def __init__(self, cord0, cord1=None, board=None, promotion=None): 12 """ Inits a new highlevel Move object. 13 The object can be initialized in the follow ways: 14 Move(cord0, cord1, board, [promotionPiece]) 15 Move(lovLevelMoveInt) """ 16 17 if not cord1: 18 self.move = cord0 19 self.flag = self.move >> 12 20 self.cord0 = None if self.flag == DROP else Cord(lmove.FCORD( 21 self.move)) 22 self.cord1 = Cord(lmove.TCORD(self.move)) 23 24 else: 25 assert cord0 is not None and cord1 is not None, "cord0=%s, cord1=%s, board=%s" % ( 26 cord0, cord1, board) 27 assert board[cord0] is not None, "cord0=%s, cord1=%s, board=%s" % ( 28 cord0, cord1, board) 29 self.cord0 = cord0 30 self.cord1 = cord1 31 if not board: 32 raise ValueError( 33 "Move needs a Board object in order to investigate flags") 34 35 self.flag = NORMAL_MOVE 36 if board[self.cord0].piece == PAWN and \ 37 self.cord1.cord in board.PROMOTION_ZONE[board.board.color] and \ 38 board.variant != SITTUYINCHESS: 39 if promotion is None: 40 self.flag = lmove.FLAG_PIECE(QUEEN) 41 else: 42 self.flag = lmove.FLAG_PIECE(promotion) 43 44 elif board[self.cord0].piece == PAWN and board.variant == SITTUYINCHESS: 45 if cord0 == cord1: 46 # in place promotion 47 self.flag = lmove.FLAG_PIECE(QUEEN) 48 elif board[self.cord1] is None and \ 49 (self.cord0.cord + self.cord1.cord) % 2 == 1 and \ 50 (self.cord0.cord in board.PROMOTION_ZONE[board.board.color] or board.board.pieceCount[board.color][PAWN] == 1): 51 # queen move promotion 52 self.flag = lmove.FLAG_PIECE(QUEEN) 53 54 elif board[self.cord0].piece == KING: 55 if self.cord0 == self.cord1: 56 self.flag = NULL_MOVE 57 58 if self.cord0.x - self.cord1.x == 2 and board.variant not in (CAMBODIANCHESS, FISCHERRANDOMCHESS): 59 self.flag = QUEEN_CASTLE if self.cord0.x == 4 else KING_CASTLE 60 elif self.cord0.x - self.cord1.x == -2 and board.variant not in (CAMBODIANCHESS, FISCHERRANDOMCHESS): 61 self.flag = KING_CASTLE if self.cord0.x == 4 else QUEEN_CASTLE 62 elif board.variant != CAMBODIANCHESS: 63 if (abs(self.cord0.x - self.cord1.x) > 1 and self.cord1.x == C1) or ( 64 board.board.ini_rooks[board.color][0] == self.cord1.cord and ( 65 (board.board.color == WHITE and board.board.castling & W_OOO) or ( 66 board.board.color == BLACK and board.board.castling & B_OOO))): 67 self.flag = QUEEN_CASTLE 68 elif (abs(self.cord0.x - self.cord1.x) > 1 and self.cord1.x == G1) or ( 69 board.board.ini_rooks[board.color][1] == self.cord1.cord and ( 70 (board.board.color == WHITE and board.board.castling & W_OO) or ( 71 board.board.color == BLACK and board.board.castling & B_OO))): 72 self.flag = KING_CASTLE 73 elif board[self.cord0].piece == PAWN and \ 74 board[self.cord1] is None and \ 75 self.cord0.x != self.cord1.x and \ 76 self.cord0.y != self.cord1.y: 77 self.flag = ENPASSANT 78 79 self.move = newMove(self.cord0.cord, self.cord1.cord, self.flag) 80 81 def _get_cords(self): 82 return (self.cord0, self.cord1) 83 84 cords = property(_get_cords) 85 86 def _get_promotion(self): 87 if self.flag in PROMOTIONS: 88 return lmove.PROMOTE_PIECE(self.flag) 89 return None 90 91 promotion = property(_get_promotion) 92 93 def __repr__(self): 94 promotion = "=" + reprSign[lmove.PROMOTE_PIECE(self.flag)] \ 95 if self.flag in PROMOTIONS else "" 96 97 if self.flag == DROP: 98 piece = reprSign[lmove.FCORD(self.move)] 99 return piece + "@" + str(self.cord1) + promotion 100 else: 101 return str(self.cord0) + str(self.cord1) + promotion 102 103 def __eq__(self, other): 104 if isinstance(other, Move): 105 return self.move == other.move 106 107 def __hash__(self): 108 return hash(self.cords) 109 110 def is_capture(self, board): 111 return self.flag == ENPASSANT or \ 112 board[self.cord1] is not None and \ 113 self.flag != QUEEN_CASTLE and self.flag != KING_CASTLE 114 115 def as_uci(self): 116 move = "%s%s%s%s" % (self.cord0.cx, self.cord0.cy, self.cord1.cx, self.cord1.cy) 117 if self.flag in PROMOTIONS: 118 move += reprSign[lmove.PROMOTE_PIECE(self.flag)].lower() 119 return move 120 121# Parsers 122 123 124def listToMoves(board, mstrs, type=None, validate=False, ignoreErrors=False): 125 return [Move(move) 126 for move in lmove.listToMoves(board.board, mstrs, type, validate, 127 ignoreErrors)] 128 129 130def parseAny(board, algnot): 131 return Move(lmove.parseAny(board.board, algnot)) 132 133 134def parseSAN(board, san): 135 """ Parse a Short/Abbreviated Algebraic Notation string """ 136 137 return Move(lmove.parseSAN(board.board, san)) 138 139 140def parseLAN(board, lan): 141 """ Parse a Long/Expanded Algebraic Notation string """ 142 143 return Move(lmove.parseLAN(board.board, lan)) 144 145 146def parseFAN(board, lan): 147 """ Parse a Long/Expanded Algebraic Notation string """ 148 149 return Move(lmove.parseFAN(board.board, lan)) 150 151 152def parseAN(board, an): 153 """ Parse an Algebraic Notation string """ 154 155 return Move(lmove.parseAN(board.board, an)) 156 157# Exporters 158 159 160def listToSan(board, moves): 161 return lmove.listToSan(board.board, (m.move for m in moves)) 162 163 164def toAN(board, move, short=False, castleNotation=CASTLE_SAN): 165 """ Returns a Algebraic Notation string of a move 166 board should be prior to the move """ 167 168 return lmove.toAN(board.board, 169 move.move, 170 short=short, 171 castleNotation=castleNotation) 172 173 174def toSAN(board, move, localRepr=False): 175 """ Returns a Short/Abbreviated Algebraic Notation string of a move 176 The board should be prior to the move, board2 past. 177 If not board2, toSAN will not test mate """ 178 179 return lmove.toSAN(board.board, move.move, localRepr) 180 181 182def toLAN(board, move): 183 """ Returns a Long/Expanded Algebraic Notation string of a move 184 board should be prior to the move """ 185 186 return lmove.toLAN(board.board, move.move) 187 188 189def toFAN(board, move): 190 """ Returns a Figurine Algebraic Notation string of a move """ 191 192 return lmove.toFAN(board.board, move.move) 193