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