|
import gradio as gr |
|
import chess |
|
import chess.svg |
|
import os |
|
import google.generativeai as genai |
|
|
|
|
|
genai.configure(api_key=os.environ["API_KEY"]) |
|
|
|
board = chess.Board() |
|
|
|
def describe_board_position(board): |
|
""" |
|
Returns a human-readable description of the chessboard for the AI. |
|
Args: |
|
board (chess.Board): The current board position. |
|
Returns: |
|
str: A human-readable description of the chessboard. |
|
""" |
|
description = [] |
|
pieces = ['P', 'N', 'B', 'R', 'Q', 'K', 'p', 'n', 'b', 'r', 'q', 'k'] |
|
for square in chess.SQUARES: |
|
piece = board.piece_at(square) |
|
if piece: |
|
piece_description = f"{'White' if piece.color == chess.WHITE else 'Black'} {piece.symbol().upper()} on {chess.square_name(square)}" |
|
description.append(piece_description) |
|
return ", ".join(description) |
|
|
|
def get_ai_move(fen): |
|
""" |
|
Gets the AI's next move using Google Gemini via google.generativeai. |
|
Args: |
|
fen (str): The current board position in FEN notation. |
|
Returns: |
|
str or None: The AI's move in UCI format, or None if an error occurs. |
|
""" |
|
|
|
board_description = describe_board_position(board) |
|
|
|
|
|
prompt = f""" |
|
You are playing a game of chess. The current board position is described below: |
|
{board_description} |
|
|
|
In addition, here is the board's FEN notation for precise positioning: |
|
{fen} |
|
|
|
It is your turn to make a move. You should provide the best legal move following the rules of chess. |
|
The move should be in UCI format, which represents the starting and ending squares (for example, 'e2e4'). |
|
Please ensure that the move is valid for the current position.""" |
|
|
|
try: |
|
|
|
response = genai.generate_text( |
|
model="gemini-1.5-flash", |
|
prompt=prompt, |
|
temperature=0, |
|
max_output_tokens=10 |
|
) |
|
ai_move = response.result.strip() |
|
print(f"AI move: {ai_move}") |
|
|
|
|
|
legal_moves = [move.uci() for move in board.legal_moves] |
|
if ai_move in legal_moves: |
|
return ai_move |
|
else: |
|
print(f"Invalid move received from the AI: {ai_move}") |
|
return None |
|
except Exception as e: |
|
print(f"Error occurred in get_ai_move: {e}") |
|
return None |
|
|
|
def board_to_svg(board): |
|
return chess.svg.board(board=board) |
|
|
|
def make_move(user_move): |
|
global board |
|
print(f"User move input: {user_move}") |
|
try: |
|
|
|
board.push_uci(user_move) |
|
except ValueError as e_uci: |
|
try: |
|
|
|
board.push_san(user_move) |
|
except ValueError as e_san: |
|
print(f"UCI ValueError: {e_uci}, SAN ValueError: {e_san}") |
|
return gr.update(value=board_to_svg(board)), "Invalid move. Try again." |
|
except Exception as e: |
|
print(f"Unexpected error: {e}") |
|
return gr.update(value=board_to_svg(board)), "Invalid move. Try again." |
|
|
|
|
|
if board.is_game_over(): |
|
result = board.result() |
|
board_svg = board_to_svg(board) |
|
return gr.update(value=board_svg), f"Game over: {result}" |
|
|
|
|
|
ai_move = get_ai_move(board.fen()) |
|
if ai_move: |
|
try: |
|
board.push_uci(ai_move) |
|
except ValueError as e: |
|
print(f"AI made an invalid move: {ai_move}, Error: {e}") |
|
return gr.update(value=board_to_svg(board)), "AI made an invalid move. Game over." |
|
else: |
|
return gr.update(value=board_to_svg(board)), "AI failed to make a move. Game over." |
|
|
|
|
|
if board.is_game_over(): |
|
result = board.result() |
|
board_svg = board_to_svg(board) |
|
return gr.update(value=board_svg), f"Game over: {result}" |
|
|
|
|
|
return gr.update(value=board_to_svg(board)), "Your move" |
|
|
|
def reset_game(): |
|
global board |
|
board.reset() |
|
return gr.update(value=board_to_svg(board)), "Game reset. Your move" |
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown("# Chess Game with Google Gemini AI") |
|
|
|
with gr.Row(): |
|
board_output = gr.HTML(board_to_svg(board)) |
|
move_input = gr.Textbox(label="Your Move (e.g., e2e4, e4, Nf3)") |
|
message_output = gr.Textbox(value="Your move", interactive=False) |
|
|
|
with gr.Row(): |
|
move_button = gr.Button("Make Move") |
|
reset_button = gr.Button("Reset Game") |
|
|
|
move_button.click(make_move, inputs=move_input, outputs=[board_output, message_output]) |
|
reset_button.click(reset_game, outputs=[board_output, message_output]) |
|
|
|
demo.launch() |
|
|