import gradio as gr import os import pandas as pd from PIL import Image, ImageSequence import io ####################################################### # Red Baron Game HTML ####################################################### test_html = """ Simple Test Page

Gradio HTML Test

This is a simple HTML test page to verify that HTML rendering works in your Gradio application.

Interactive Elements

Button not clicked yet.

Canvas Test

HTML Elements

""" game_html = """

Controls: Arrow keys to move, Space to shoot

""" ####################################################### # Dictionary of game -> directory paths ####################################################### GAMES = { "Super Mario Bros": "assets/super_mario_bros", "Sokoban": "assets/sokoban", "Tetris": "assets/tetris", "2048": "assets/2048", "Candy Crash": "assets/candy" } # Ensure each directory exists for path in GAMES.values(): os.makedirs(path, exist_ok=True) ####################################################### # Scoreboard data for each game ####################################################### # TODO (lanxiang): read actual data here mario_scores = [ ["Alice", 9000, "3/5", "00:35"], ["Bob", 2500, "2/5", "00:12"], ["Carol", 500, "1/5", "00:05"] ] sokoban_scores = [ ["Alice", 100, 3], ["Bob", 350, 2], ["Carol", 500, 1] ] tetris_scores = [ ["Alice", 15000, 120], ["Bob", 8000, 60], ["Carol", 4000, 45] ] candy_scores = [ ["Alice", 12000, 10], ["Bob", 9500, 8], ["Carol", 3000, 5] ] # 2048 columns: [Player, Scores, #Steps] game_2048_scores = [ ["Alice", 8192, 300], ["Bob", 4096, 200], ["Carol", 2048, 150] ] ####################################################### # Functions to return the scoreboard as DataFrames ####################################################### def get_mario_leaderboard(): return pd.DataFrame( mario_scores, columns=["Player", "Progress (current/total)", "Score", "Time"] ) def get_sokoban_leaderboard(): return pd.DataFrame( sokoban_scores, columns=["Player", "Levels Cracked", "Steps"] ) def get_tetris_leaderboard(): return pd.DataFrame( tetris_scores, columns=["Player", "Scores", "Steps"] ) def get_candy_leaderboard(): return pd.DataFrame( candy_scores, columns=["Player", "Levels Cracked", "Scores"] ) def get_2048_leaderboard(): return pd.DataFrame( game_2048_scores, columns=["Player", "Scores", "Steps"] ) ####################################################### # GIF Handling ####################################################### def create_or_update_resized_gif(original_path, max_dim=600): base, ext = os.path.splitext(original_path) resized_path = f"{base}_resized{ext}" if os.path.exists(resized_path): return resized_path with Image.open(original_path) as im: w, h = im.size needs_resize = (w > max_dim or h > max_dim) frames = [] for frame in ImageSequence.Iterator(im): frame_rgba = frame.convert("RGBA") if needs_resize: ratio = min(max_dim / w, max_dim / h) new_w, new_h = int(w * ratio), int(h * ratio) frame_rgba = frame_rgba.resize((new_w, new_h), Image.LANCZOS) frames.append(frame_rgba.convert("P")) output_bytes = io.BytesIO() frames[0].save( output_bytes, format="GIF", save_all=True, append_images=frames[1:], loop=0, disposal=2, optimize=False ) output_bytes.seek(0) with open(resized_path, "wb") as f_out: f_out.write(output_bytes.read()) return resized_path def list_gifs(game_name): gif_dir = GAMES[game_name] all_gifs = [ os.path.join(gif_dir, f) for f in os.listdir(gif_dir) if f.lower().endswith(".gif") and not f.lower().endswith("_resized.gif") ] resized_paths = [] for gif_path in all_gifs: resized_gif_path = create_or_update_resized_gif(gif_path, max_dim=600) resized_paths.append(resized_gif_path) previously_resized = [ os.path.join(gif_dir, f) for f in os.listdir(gif_dir) if f.lower().endswith("_resized.gif") ] all_resized = list(set(resized_paths + previously_resized)) return sorted(all_resized) ####################################################### # Custom CSS ####################################################### fancy_css = """ body { font-family: 'Trebuchet MS', sans-serif; background: #f0f8ff; color: #333333; } h1 { color: #4b9cd3; text-align: center; margin-top: 20px; } .gradio-container { max-width: 800px; margin: 0 auto; padding: 20px; } """ ####################################################### # Build the App ####################################################### def build_app(): with gr.Blocks(css=fancy_css) as demo: gr.Markdown("# Game Arena: Gaming Agent") with gr.Tabs(): # tab: "Gallery" with gr.Tab("Gallery"): with gr.Tabs(): for game_name in GAMES: with gr.Tab(game_name): gr.Markdown(f"### {game_name} Gallery") gr.Gallery( label="GIFs", value=list_gifs(game_name) ) # tab: "Leaderboard" with gr.Tab("Leaderboard"): gr.Markdown("## Game Leaderboards") # Sub-tabs for each game with gr.Tabs(): with gr.Tab("Mario"): gr.Markdown("### Mario Leaderboard") gr.DataFrame(value=get_mario_leaderboard(), interactive=False) with gr.Tab("Sokoban"): gr.Markdown("### Sokoban Leaderboard") gr.DataFrame(value=get_sokoban_leaderboard(), interactive=False) with gr.Tab("Tetris"): gr.Markdown("### Tetris Leaderboard") gr.DataFrame(value=get_tetris_leaderboard(), interactive=False) with gr.Tab("2048"): gr.Markdown("### 2048 Leaderboard") gr.DataFrame(value=get_2048_leaderboard(), interactive=False) with gr.Tab("Candy Crash"): gr.Markdown("### Candy Crash Leaderboard") gr.DataFrame(value=get_candy_leaderboard(), interactive=False) # Top-level tab: "Red Baron" game demo with gr.Tab("Red Baron"): gr.Markdown("## Red Baron Game Demo") gr.HTML(game_html) return demo if __name__ == "__main__": demo_app = build_app() # demo_app.launch(server_name="0.0.0.0", server_port=7860) demo_app.launch(server_name="127.0.0.1", server_port=7860, debug=True)