import chess import chess.pgn from stockfish import Stockfish from lama2923 import clear_screen, llinput import datetime class ChessGame: def __init__(self, stockfish_path, stockfish_depth=12): self.language = self.select_language() self.messages = self.define_messages() self.stockfish = Stockfish(path=stockfish_path) self.stockfish.set_depth(stockfish_depth) self.board = None self.move_history = [] self.white_elo = self.get_elo(f" ({self.get_message('white')})") self.black_elo = self.get_elo(f" ({self.get_message('black')})") self.unicode_pieces = self.define_unicode_pieces() self.FEN = None def select_language(self): all_languages = list(self.define_messages().keys()) chars = set() for lang in all_languages: for c in lang: chars.add(c) lang_choice = llinput("Select Language: ", wend=" (" + "/".join(all_languages) + ")", choices=(all_languages, False), availablechars=r"".join(chars), forceinput=True, max_length=2, min_length=2) return lang_choice def define_messages(self): return { "en": { "white": "White", "black": "Black", "yes": "y", "no": "n", "enter_elo": "Enter ELO rating: ", "fen_prompt": "Enter FEN position: ", "use_custom_fen": "Would you like to use a custom FEN?: ", "game_over": "Game over!", "winner": "checkmate! Winner: ", "draw": "The game ended in a draw!", "white_turn": "turn: White", "black_turn": "turn: Black", "white_captured": "Captured by White: ", "black_captured": "Captured by Black: ", "white_elo": "White's ELO", "black_elo": "Black's ELO", "fen": "FEN: ", "pgn_saved": "Game history saved as PGN." }, "tr": { "white": "Beyaz", "black": "Siyah", "yes": "e", "no": "h", "enter_elo": "ELO değerini girin: ", "fen_prompt": "FEN pozisyonunu girin: ", "use_custom_fen": "Özel bir FEN kullanmak ister misiniz?: ", "game_over": "Oyun sona erdi!", "winner": "Şah Mat! Kazanan: ", "draw": "Oyun berabere bitti!", "white_turn": "Sıra: Beyaz", "black_turn": "Sıra: Siyah", "white_captured": "Beyaz tarafından alınan taşlar: ", "black_captured": "Siyah tarafından alınan taşlar: ", "white_elo": "Beyaz'ın ELO'su: ", "black_elo": "Siyah'ın ELO'su: ", "fen": "FEN: ", "pgn_saved": "Oyun geçmişi PGN olarak kaydedildi." } } def get_message(self, key): return self.messages[self.language].get(key, "") def get_elo(self, wend=""): return int(llinput(self.get_message("enter_elo"), wend=wend, forceint=True, forceinput=True, min_length=1, max_length=4)) def set_board(self): if llinput(self.get_message("use_custom_fen"), wend=f" ({self.get_message("yes")}/{self.get_message("no")})", forceinput=True, choices=([self.get_message("yes"), self.get_message("no")], False), max_length=1, min_length=1).lower() == "e": self.FEN = self.custom_fen() self.board = chess.Board(self.FEN) else: self.FEN = chess.Board().fen() self.board = chess.Board() def custom_fen(self): def check_fen(fen): try: chess.Board(fen) return True except ValueError: return False return llinput(self.get_message("fen_prompt"), forceinput=True, min_length=1, max_length=71, custom_enter_check_func=check_fen) def define_unicode_pieces(self): return { "P": "\033[1m♟︎\033[0m", "N": "\033[1m♞\033[0m", "B": "\033[1m♝\033[0m", "R": "\033[1m♜\033[0m", "Q": "\033[1m♛\033[0m", "K": "\033[1m♚\033[0m", "p": "\033[1m♙\033[0m", "n": "\033[1m♘\033[0m", "b": "\033[1m♗\033[0m", "r": "\033[1m♖\033[0m", "q": "\033[1m♕\033[0m", "k": "\033[1m♔\033[0m" } def print_board(self): """ Bütün GUI'yi konsola basar. ----------------------- Prints the whole GUI to the console. """ stockfish_evaluation = self.stockfish.get_evaluation() eval_display = "" if stockfish_evaluation["type"] == "mate": eval_display = f"# {'+' if stockfish_evaluation['value'] > 0 else '-'}{abs(stockfish_evaluation['value'])}" else: eval_score = stockfish_evaluation["value"] eval_score = max(min(eval_score, 1000), -1000) eval_display = f"{eval_score / 100:+.2f}" initial_counts = {chess.PAWN: 8, chess.KNIGHT: 2, chess.BISHOP: 2, chess.ROOK: 2, chess.QUEEN: 1} piece_values = {chess.PAWN: 1, chess.KNIGHT: 3, chess.BISHOP: 3, chess.ROOK: 5, chess.QUEEN: 9} white_captured, black_captured = [], [] material_difference = 0 for piece_type, count in initial_counts.items(): white_on_board = len(self.board.pieces(piece_type, chess.WHITE)) black_on_board = len(self.board.pieces(piece_type, chess.BLACK)) white_captured_count = count - white_on_board black_captured_count = count - black_on_board material_difference += (white_captured_count - black_captured_count) * piece_values[piece_type] white_captured.extend([self.unicode_pieces[chess.Piece(piece_type, chess.BLACK).symbol()]] * black_captured_count) black_captured.extend([self.unicode_pieces[chess.Piece(piece_type, chess.WHITE).symbol()]] * white_captured_count) white_score = abs(material_difference) if material_difference < 0 else 0 black_score = abs(material_difference) if material_difference > 0 else 0 board_lines = [ "\n a b c d e f g h", " ┌───┬───┬───┬───┬───┬───┬───┬───┐" ] for rank in range(7, -1, -1): row = f" {rank + 1} │" for file in range(8): piece = self.board.piece_at(chess.square(file, rank)) row += f" {self.unicode_pieces.get(piece.symbol(), ' ')} │" if piece else " │" board_lines.append(row) if rank > 0: board_lines.append(" ├───┼───┼───┼───┼───┼───┼───┼───┤") board_lines.append(" └───┴───┴───┴───┴───┴───┴───┴───┘\n") move_columns = [] num_moves = len(self.move_history) for start in range(0, num_moves, 32): column = [] for i in range(32): index = start + i if index >= num_moves: break move_number = index // 2 + 1 if index % 2 == 0: column.append(f"{move_number:>2}. {self.move_history[index]}") else: column[-1] += f" {self.move_history[index]}" move_columns.append(column) max_rows = max(len(board_lines), max(len(col) for col in move_columns)) clear_screen() print(f"Eval: {eval_display}") for row in range(max_rows): board_part = board_lines[row] if row < len(board_lines) else "" if row == 0: print(f"{board_part:<35}") else: move_row = row - 1 columns_part = " | ".join( move_columns[col][move_row] if move_row < len(move_columns[col]) else "" for col in range(len(move_columns)) ).strip(" |") print(f"{board_part:<35} | {columns_part}" if columns_part else board_part) print(f"{self.get_message('white_captured')} {' '.join(white_captured)} {'+{}'.format(white_score) if white_score > 0 else ''}") print(f"{self.get_message('black_captured')} {' '.join(black_captured)} {'+{}'.format(black_score) if black_score > 0 else ''}\n") print(f"{self.get_message('white_turn') if self.board.turn == chess.WHITE else self.get_message('black_turn')}") print(f"{self.get_message('white_elo')}: {self.white_elo} {self.get_message('black_elo')}: {self.black_elo}") print(f"{self.get_message('fen')}: {self.board.fen()}") def save_pgn(self): """ Oyun Rotasyonunu PGN formatında kaydeder. ----------------------- Saves the game rotation in PGN format. """ if self.board and self.move_history: game = chess.pgn.Game() game.headers["Event"] = f"Stockfish Game (Depth {self.stockfish.depth})" game.headers["White"] = f"Stockfish (ELO {self.white_elo})" game.headers["Black"] = f"Stockfish (ELO {self.black_elo})" game.headers["Result"] = self.board.result() game.headers["Date"] = datetime.datetime.now().strftime("%Y.%m.%d") board_position = chess.Board(self.FEN) node = game for move_uci in self.move_history: move = chess.Move.from_uci(move_uci) if move in board_position.legal_moves: node = node.add_variation(move) board_position.push(move) else: print(f"Illegal move: {move_uci}") with open("game_history.pgn", "w") as pgn_file: print(game, file=pgn_file) print(self.get_message("pgn_saved")) def is_playable_position(self): """ True: oynanabilir durum False: oynanamaz durum ----------------------- True: playable position False: unplayable position """ board = self.board.copy() stockfish = self.stockfish stockfish.set_fen_position(board.fen()) evaluation = stockfish.get_evaluation() if evaluation["type"] == "cp": value = evaluation["value"] if (board.turn == chess.BLACK and value >= -800) or (board.turn == chess.WHITE and value <= 800): return True # oynanabilir durum. Unplayable position. else: return False # Oynanamaz durum. Unplayable position. elif evaluation["type"] == "mate": if board.turn == chess.WHITE and evaluation["value"] < 0: return True # Oynanabilir durum. Unplayable position. elif board.turn == chess.BLACK and evaluation["value"] > 0: return True # Oynanabilir durum. Unplayable position. else: return False # Oynanamaz durum. Unplayable position. else: return False # Oynanamaz durum. Unplayable position. def is_draw(self): board = self.board return any([board.is_stalemate(), board.is_insufficient_material(), board.is_seventyfive_moves(), board.is_fivefold_repetition(), board.is_variant_draw()]) def get_skill_level(self, elo_rating): return max(0, min(20, elo_rating // 50)) def start_game(self): """ Ana oyun döngüsü. ----------------------- Main game loop. """ self.set_board() while not self.board.is_game_over(): elo_rating = self.white_elo if self.board.turn == chess.WHITE else self.black_elo self.stockfish.set_elo_rating(elo_rating) self.stockfish.set_skill_level(self.get_skill_level(elo_rating)) self.stockfish.set_fen_position(self.board.fen()) best_move = self.stockfish.get_best_move() if best_move is None: print(self.get_message("game_over")) break self.board.push_uci(best_move) self.move_history.append(best_move) self.stockfish.set_fen_position(self.board.fen()) if self.board.is_game_over() and self.is_draw(): self.board.pop() self.move_history.pop() self.stockfish.set_fen_position(self.board.fen()) if self.is_playable_position(): alternative_moves = [move['Move'] for move in self.stockfish.get_top_moves(6)] found_move = False for move in alternative_moves: if move == best_move: continue if move: self.board.push_uci(move) self.move_history.append(move) self.stockfish.set_fen_position(self.board.fen()) if self.is_playable_position(): found_move = True break else: self.board.pop() self.move_history.pop() else: print(f"İllegal move: {move}") if not found_move: self.board.push_uci(best_move) self.move_history.append(best_move) self.stockfish.set_fen_position(self.board.fen()) else: self.board.push_uci(best_move) self.move_history.append(best_move) self.stockfish.set_fen_position(self.board.fen()) self.print_board() if self.board.is_checkmate(): print(f"{self.get_message('winner')} {('Black' if self.board.turn == chess.WHITE else 'White')}") elif self.board.is_stalemate(): print(self.get_message("draw")) elif self.board.is_insufficient_material(): print(self.get_message("draw")) elif self.board.is_seventyfive_moves(): print(self.get_message("draw")) elif self.board.is_fivefold_repetition(): print(self.get_message("draw")) else: print(self.get_message("game_over")) self.save_pgn() if __name__ == "__main__": chess_game = ChessGame(stockfish_path="/usr/games/stockfish") chess_game.start_game()