def order_moves_by_warnsdorff_tuples(self, board, move_tuples): """ Order moves by Warnsdorff algorithm (minimum neighbors) one level :board: current board :move_tuples: sorted list of 3-tuples (number-of follow-on moves, move, list of this move's follow-on ) :returns: list with moves of decreasing number of follow-on's folow-on moves of 3-tuples (number-of follow-on folow-on's moves, move, list of this move's follow-on's follow-ons ) """ ffon_tuples = [ ] # list of (follow-on's follow-on cnt, move, ffon_list) for move_tuple in move_tuples: follow_ons = move_tuple[2] follow_board = ChessBoard(board) follow_board.set_piece('N', move_tuple[1]) follow_on_tuples = self.order_moves_by_warnsdorff_1( follow_board, follow_ons) ffon_moves = [] for follow_on_tuple in follow_on_tuples: ffon_moves.extend(follow_on_tuple[2]) ffon_tuples.append((len(ffon_moves), move_tuple[1], ffon_moves)) ffon_tuples_sorted = sorted(ffon_tuples, key=by_first) return ffon_tuples_sorted
class ChessGame: def __init__(self, setup_pieces=False): self.board = ChessBoard() self.highness = None self.p1_king = None self.p2_king = None self.player_turn = 1 self.other_player_turn = 2 self.turn_counter = 0 self.move_history = [] self.player_1_color = "yellow" self.player_2_color = "magenta" if setup_pieces: self.setup_pieces() def end_game(self): print("Game Over") print(f"Player {self.other_player_turn} wins!") exit() def run(self): # Game Process Logic while True: if self.is_checkmate(): print("Checkmate") self.end_game() self.board.display() move = input(f"Player {self.player_turn}, enter move: ") try: move = move_from_string(move) self.try_player_move(move, self.player_turn) self.move_history.append(move) self.board.get_piece(move.new).move_counter += 1 self.next_player_turn() # Error Handling except ValueError: print("Invalid Input") except error_handling.ChessException as chess_exception: print(chess_exception) # After a successful turn, switch players def next_player_turn(self): self.turn_counter += 1 self.player_turn = 2 if self.player_turn == 1 else 1 self.other_player_turn = 2 if self.player_turn == 2 else 1 # Piece placement def setup_pieces(self): # Top team for num in range(0, 8): self.board.set_piece(Vec2(num, 1), pieces.Pawn(team=2)) self.board.set_piece(Vec2(0, 0), pieces.Rook(team=2)) self.board.set_piece(Vec2(7, 0), pieces.Rook(team=2)) self.board.set_piece(Vec2(1, 0), pieces.Knight(team=2)) self.board.set_piece(Vec2(6, 0), pieces.Knight(team=2)) self.board.set_piece(Vec2(2, 0), pieces.Bishop(team=2)) self.board.set_piece(Vec2(5, 0), pieces.Bishop(team=2)) self.p2_king = self.board.set_piece(Vec2(3, 0), pieces.King(team=2)) self.board.set_piece(Vec2(4, 0), pieces.Queen(team=2)) # Bottom Team for num in range(0, 8): self.board.set_piece(Vec2(num, 6), pieces.Pawn(team=1)) self.board.set_piece(Vec2(0, 7), pieces.Rook(team=1)) self.board.set_piece(Vec2(7, 7), pieces.Rook(team=1)) self.board.set_piece(Vec2(1, 7), pieces.Knight(team=1)) self.board.set_piece(Vec2(6, 7), pieces.Knight(team=1)) self.board.set_piece(Vec2(2, 7), pieces.Bishop(team=1)) self.board.set_piece(Vec2(5, 7), pieces.Bishop(team=1)) self.p1_king = self.board.set_piece(Vec2(4, 7), pieces.King(team=1)) self.board.set_piece(Vec2(3, 7), pieces.Queen(team=1)) # cool stuff self.board.print_all_moves_for_piece(Vec2(4, 7)) def is_checkmate(self) -> bool: self.highness = self.p1_king if self.player_turn == 1 else self.p2_king king_pos = (self.board.get_piece_pos(self.highness)) # Is King in check? king_is_in_danger = not self.board.is_space_safe( king_pos, self.highness.team) # Can the King move to free himself? king_cannot_move = not self.board.can_piece_move( self.highness, king_pos) # See if a piece may free the King king_cannot_be_saved = not self.can_friendlies_uncheck_king() if king_is_in_danger: print("Check") if king_is_in_danger and king_cannot_move and not king_cannot_be_saved: print("Your King requires help from a friendly piece") return king_is_in_danger and king_cannot_move and king_cannot_be_saved # Murder checker def can_friendlies_uncheck_king(self) -> bool: friendlies = self.board.get_all_pieces_on_team(self.highness.team) checkers = self.board.get_all_pieces_checking_king( self.highness.team, self.board.get_piece_space(self.highness)) if len(checkers) > 1: return False elif len(checkers) == 0: return True else: checker = checkers[0] if friendlies: for friendly in friendlies: move_kill = Move(self.board.get_piece_pos(friendly), self.board.get_piece_pos(checker)) if friendly.can_move( move_kill, self.board) or self.can_friendlies_block_checker( friendlies, checker): print(f"Checker may be captured or blocked") if friendly.can_move( move_kill, self.board ) and self.can_friendlies_block_checker( friendlies, checker): print( f"Checker may be captured via {move_kill}, and blocked via {self.can_friendlies_block_checker(friendlies, checker)}" ) return True else: return False def can_friendlies_block_checker(self, friendlies, checker) -> bool: checker_pos = self.board.get_piece_pos(checker) checking_path = self.board.get_attacker_spaces_for_checkmate( checker, checker_pos) if len(checking_path) > 0: for friendly in friendlies: friendly_pos = self.board.get_piece_pos(friendly) for pos in checking_path: move = Move(friendly_pos, pos) if friendly.can_move(move, self.board): if not self.board.will_king_check( move, self.highness.team, self.board.get_piece_pos(self.highness)): if friendly.name != "King": print(f"Checker may be blocked via {move}") return True else: print("No check path (Knight?)") return False # For while loop in chess_game.py def try_player_move(self, move, player_team): cur, new = move.old, move.new # Bounds check if not self.board.in_board(cur) or not self.board.in_board(new): raise error_handling.OutOfBounds() piece = self.board.get_piece(cur) # Selected empty space if piece is None: raise error_handling.NoPieceInSpace() # Wrong team check if piece.team != player_team: raise error_handling.ThatsNotUrFuckinTeam() # Move puts own King in check king_pos = self.board.get_piece_pos(self.board.get_king(player_team)) # This allows Kings to free themselves if piece.name == "King": piece.is_castling_move(move, self.board) if self.board.will_king_check(move, player_team, move.new): raise error_handling.CheckingKing() elif not self.board.is_space_safe( king_pos, piece.team) and piece.is_castling: raise error_handling.CastlingWhileChecked() elif not self.board.is_castle_path_clear( move, player_team) and piece.is_castling: raise error_handling.CastlePathBlocked() # This prevents other pieces from endangering the King else: if self.board.will_king_check(move, player_team, king_pos): raise error_handling.CheckingKing() if piece.can_move(move, self.board): piece.do_move(move, self.board) print(algebraic_move(move)) if piece.name == "Pawn" and piece.team == 1: if move.new.y == 0: self.pawn_promotion(move.new) elif piece.name == "Pawn" and piece.team == 2: if move.new.y == 7: self.pawn_promotion(move.new) else: raise error_handling.IllegalMove() def pawn_promotion(self, pos): print("Promotion! - Bishop, Knight, Rook, or Queen?") promotion_choice = input() color = self.player_1_color if self.player_turn == 1 else self.player_2_color pawn = self.board.get_piece(pos) if promotion_choice == "Queen": self.board.spaces[pos.y][pos.x] = pieces.Queen(team=pawn.team) if promotion_choice == "Rook": self.board.spaces[pos.y][pos.x] = pieces.Rook(team=pawn.team) if promotion_choice == "Knight": self.board.spaces[pos.y][pos.x] = pieces.Knight(team=pawn.team) if promotion_choice == "Bishop": self.board.spaces[pos.y][pos.x] = pieces.Bishop(team=pawn.team) def get_previous_move_piece(self): previous_move_piece = self.board.get_piece( self.move_history[self.turn_counter - 1]) return previous_move_piece