def get_piece_from_properties(self, allegiance, name, move, ambg=None): """ Return a specific piece that matches the given properties. If more than one piece matches the properties and ambg doesn't differentiate then an error is thrown """ candidates = [] unique_piece = [] for piece in self.pieces(): if (piece.get_char().lower() == name.lower() and piece.allegiance == allegiance and move in piece.legal_moves): candidates.append(piece) if len(candidates) == 1: return candidates[0] if len(candidates) > 1: for candidate in candidates: if ambg in utils.idx_to_algebra(candidate.pos_idx): unique_piece.append(candidate) if not unique_piece or len(unique_piece) > 1: candidate_pos = [ utils.idx_to_algebra(x.pos_idx) for x in candidates ] raise Exception( 'Found candidates: %s by the ambiguity string %s does' 'not differentiate them' % (candidate_pos, ambg)) return unique_piece[0] return None
def _get_knight_moves(self, pos_idx=False): """Get the knights available moves""" moves = [self.pos_idx + m for m in KNIGHT_MOVES if not clipped(self.pos_idx, self.pos_idx + m)] if pos_idx: return moves return utils.idx_to_algebra(*moves)
def get_overview(self): """Return a string describing this piece""" dict_ = { 'Name': str(self), 'Position': utils.idx_to_algebra(self.pos_idx), 'Allegiance': self.allegiance } return str(dict_)
def get_legal_moves(self, idx, pos_idx=False): """Given the board state get the legal moves of a piece""" if not self.is_occupied(idx): return None legal_moves = self.get_piece(idx).legal_moves if pos_idx: return legal_moves algs = utils.idx_to_algebra(*legal_moves) return algs if isinstance(algs, list) else [algs]
def get_check_attackers(self, allegiance, pos_idx=False): """ Return a list of piece positions that are currently placing the king with the given allegiance in check """ attackers = [] king_loc = self.pieces.get_king(allegiance).pos_idx z = ALLEGIANCES.index(allegiance) for piece in self.pieces.get_pieces_by_allegiance(ALLEGIANCES[not z]): if king_loc in piece.legal_moves: attackers.append(piece.pos_idx) if pos_idx: return attackers return utils.idx_to_algebra(*attackers)
def left(self, *args, pos_idx=False): """Return idx for left moves""" direction = self.get_direction() indexes = [] if not args: args = range(1, 8) for arg in args: idx = self.pos_idx + (arg * direction) if idx // 8 == self.pos_idx // 8: indexes.append(idx) if pos_idx: return indexes algs = utils.idx_to_algebra(*indexes) return algs if isinstance(algs, list) else [algs]
def bkwd(self, *args, pos_idx=False): """Return idx for backward moves""" direction = self.get_direction() indexes = [] if not args: args = range(1, 8) for arg in args: idx = self.pos_idx - (8 * arg * direction) if idx in range(64): indexes.append(idx) if pos_idx: return indexes algs = utils.idx_to_algebra(*indexes) return algs if isinstance(algs, list) else [algs]
def dgbr(self, *args, pos_idx=False): """Return idx for backward diagonal right moves""" direction = self.get_direction() indexes = [] if not args: args = range(1, 8) if self.pos_idx not in RIGHT_EDGE[direction]: for arg in args: idx = self.pos_idx - (8 * arg * direction + 1 * arg * direction) if idx in range(64): indexes.append(idx) if idx in RIGHT_EDGE[direction]: break if pos_idx: return indexes algs = utils.idx_to_algebra(*indexes) return algs if isinstance(algs, list) else [algs]
def turn(self, piece, end_idx, promotion_choice=None): """Move the given piece to the given positional index""" if end_idx not in piece.legal_moves: raise utils.InvalidMoveException( '%s is not a legal move for the piece %s' % (utils.idx_to_algebra(end_idx), piece.get_overview())) self.pieces.reset_promotion() promotion_piece = self._create_promotion_piece(promotion_choice) move = Move(self.positions, piece, end_idx, promotion_piece=promotion_piece) self.pieces.mask(*move.pieces_to_remove) self.update() self.pieces.masked_pieces.clear() if self.is_in_check(self.players.current_player.allegiance): self.last_move_info['success'] = False self.last_move_info['check_attackers'] = self.get_check_attackers( self.players.current_player.allegiance, pos_idx=True) move.revert() self.update() else: self.last_move_info['success'] = True self.last_move_info['check_attackers'] = [] move.do_post_move() self.pieces.remove(*move.pieces_to_remove) self.pieces.add(*move.pieces_to_add) self.pieces.reset_enpassant() move.check_double_pawn_move() if move.switch_players: self.players.switch_player() if self.players.current_player.allegiance == 'white': self.fullmove_num += 1 if move.capture or move.pawn_advance: self.halfmove_clk = 0 else: self.halfmove_clk += 1 self.update() self.turn_clock = not self.turn_clock
def get_file(self): """Get the file of the current piece""" alg = utils.idx_to_algebra(self.pos_idx) return alg[0]
def get_rank(self): """Get the rank of the current piece""" alg = utils.idx_to_algebra(self.pos_idx) return alg[1]
def _build_enpassant_sq(self): """Construct the algebraic enpassant square""" double_move_pawn = self.pieces.get_double_move_pawn() if double_move_pawn is None: return '-' return utils.idx_to_algebra(double_move_pawn.enpassant_sq)
def test_idx_to_algebra(self): """Check positional index to algebra conversion works""" self.assertEqual(utils.idx_to_algebra(56), 'a1') self.assertEqual(utils.idx_to_algebra(0), 'a8') self.assertEqual(utils.idx_to_algebra(63), 'h1') self.assertEqual(utils.idx_to_algebra(28), 'e5') with self.assertRaises(utils.InvalidPosIdxException): utils.idx_to_algebra('e') with self.assertRaises(utils.InvalidPosIdxException): utils.idx_to_algebra('5') with self.assertRaises(utils.InvalidPosIdxException): utils.idx_to_algebra(67) with self.assertRaises(utils.InvalidPosIdxException): utils.idx_to_algebra('k2') with self.assertRaises(utils.InvalidPosIdxException): utils.idx_to_algebra(utils)