import gradio as gr
import altair as alt
import pandas as pd
from models.registry import models
from ui.bindings import bind_events
from game.stats import get_leaderboard_data, get_total_games, get_last_10_games
model_choices = [model["name"] for model in models]
def create_leaderboard_chart():
data = get_leaderboard_data()
if not data:
return None
df = pd.DataFrame(data, columns=["Model", "Wins"])
chart = (
alt.Chart(df)
.mark_bar(color="#4c78a8")
.encode(
x=alt.X("Wins:Q", title="Total Wins"),
y=alt.Y("Model:N", sort="-x", title="Model"),
tooltip=["Model:N", "Wins:Q"],
)
.properties(title="Model Wins Leaderboard", width=400, height=200)
)
return chart
def format_total_games():
total = get_total_games()
return f"
Total Games: {total}
"
def format_last_games():
games = get_last_10_games()
if not games:
return "No games played yet
"
html = ""
for i, game in enumerate(games, 1):
html += f"
{i}. {game}
"
html += "
"
return html
def refresh_leaderboard():
return format_total_games(), format_last_games(), create_leaderboard_chart()
def create_ui():
with gr.Blocks(css=open("ui/styles.css").read()) as demo:
gr.Markdown("# 🎲 Tic-Tac-Toe Game")
leaderboard_btn = gr.Button("🏆 Leaderboard", variant="secondary", size="sm")
with gr.Row(visible=False) as leaderboard_row:
with gr.Column(scale=1):
total_games_html = gr.HTML(value=format_total_games)
gr.Markdown("### 🏅 Last 10 Games")
last_games_html = gr.HTML(value=format_last_games)
with gr.Column(scale=1):
gr.Markdown("### 📊 Wins Leaderboard")
leaderboard_plot = gr.Plot(value=create_leaderboard_chart)
def toggle_leaderboard(visible):
return gr.Row(visible=not visible)
with gr.Row():
with gr.Column(scale=1):
model_1_dropdown = gr.Dropdown(
choices=model_choices,
value=models[0]["name"],
label="Select Model for Player 1 (X)",
interactive=True,
)
model_1_comment = gr.Textbox(
label="Model 1 Comment",
value="Waiting for game to start...",
interactive=False,
lines=3,
)
with gr.Column(scale=2):
board_buttons = []
board_state = gr.State([None] * 9)
current_player_move = gr.State("X")
for r in range(3):
row_buttons = []
with gr.Row(elem_classes="tic-row"):
for c in range(3):
btn = gr.Button(
value=" ",
elem_classes=["tic-cell", "tic-btn"],
elem_id=f"cell-{r}-{c}",
interactive=False,
)
row_buttons.append(btn)
board_buttons.append(row_buttons)
status_text = gr.Textbox(
label="Game Status",
value="Click 'Start Game' to begin the battle!",
interactive=False,
)
start_button = gr.Button("Start Game", variant="primary")
reset_button = gr.Button("Reset Game", variant="stop")
with gr.Column(scale=1):
model_2_dropdown = gr.Dropdown(
choices=model_choices,
value=models[0]["name"],
label="Select Model for Player 2 (O)",
interactive=True,
)
model_2_comment = gr.Textbox(
label="Model 2 Comment",
value="Waiting for game to start...",
interactive=False,
lines=3,
)
leaderboard_state = gr.State(False)
leaderboard_btn.click(
fn=toggle_leaderboard, inputs=[leaderboard_state], outputs=[leaderboard_row]
).then(
fn=lambda x: not x, inputs=[leaderboard_state], outputs=[leaderboard_state]
)
bind_events(
start_button,
reset_button,
model_1_dropdown,
model_2_dropdown,
status_text,
board_state,
current_player_move,
board_buttons,
model_1_comment,
model_2_comment,
total_games_html,
last_games_html,
leaderboard_plot,
refresh_leaderboard,
)
return demo