Spaces:
Runtime error
Runtime error
| import bitbully as bb | |
| import gradio as gr | |
| import json | |
| import hashlib | |
| ROWS = 6 | |
| COLS = 7 | |
| board = bb.Board() | |
| agent = bb.BitBully() | |
| move_history = [] | |
| confirm_reset_flag = False | |
| PASSWORD_HASH = hashlib.sha256("bitbully".encode()).hexdigest() | |
| def get_board(): | |
| grid = [["⚪" for _ in range(COLS)] for _ in range(ROWS)] | |
| turn = 1 | |
| for m in move_history: | |
| for r in range(ROWS - 1, -1, -1): | |
| if grid[r][m] == "⚪": | |
| grid[r][m] = "🔴" if turn == 1 else "🟡" | |
| break | |
| turn = 2 if turn == 1 else 1 | |
| return "\n".join([" ".join(row) for row in grid]) | |
| def export_game(): | |
| return json.dumps({"moves": "".join(str(x) for x in move_history)}, indent=2) | |
| def col_full(col): | |
| count = sum(1 for m in move_history if m == col) | |
| return count >= ROWS | |
| def play(col): | |
| global board, move_history | |
| if board.is_game_over(): | |
| return get_board(), "Game already finished", export_game() | |
| if col_full(col): | |
| return get_board(), "Column full", export_game() | |
| try: | |
| board.play(col) | |
| move_history.append(col) | |
| except: | |
| return get_board(), "Invalid move", export_game() | |
| if board.is_game_over(): | |
| return get_board(), "Game over", export_game() | |
| ai = agent.best_move(board) | |
| try: | |
| board.play(ai) | |
| move_history.append(ai) | |
| except: | |
| return get_board(), "AI move failed", export_game() | |
| if board.is_game_over(): | |
| return get_board(), f"AI played {ai} - game over", export_game() | |
| return get_board(), f"AI played {ai}", export_game() | |
| def undo(): | |
| global board, move_history | |
| if len(move_history) >= 2: | |
| move_history = move_history[:-2] | |
| board = bb.Board("".join(str(x) for x in move_history)) | |
| return get_board(), "Undone", export_game() | |
| def reset_request(): | |
| global confirm_reset_flag | |
| if not confirm_reset_flag: | |
| confirm_reset_flag = True | |
| return get_board(), "Click reset again to confirm", export_game() | |
| return reset() | |
| def reset(): | |
| global board, move_history, confirm_reset_flag | |
| board = bb.Board() | |
| move_history = [] | |
| confirm_reset_flag = False | |
| return get_board(), "Reset complete", export_game() | |
| def import_game(data): | |
| global board, move_history | |
| try: | |
| parsed = json.loads(data) | |
| moves = parsed["moves"] | |
| temp = bb.Board() | |
| validated = [] | |
| for c in moves: | |
| col = int(c) | |
| temp.play(col) | |
| validated.append(col) | |
| move_history = validated | |
| board = temp | |
| return get_board(), "Imported safely", export_game() | |
| except: | |
| return get_board(), "Import failed", export_game() | |
| with gr.Blocks() as app: | |
| gr.Markdown("# BitBully Connect 4 Admin GUI") | |
| board_display = gr.Textbox(value=get_board(), lines=8, label="Board") | |
| status = gr.Textbox(value="Ready") | |
| export_box = gr.Textbox(value=export_game(), lines=5, label="Import / Export") | |
| with gr.Row(): | |
| for i in range(7): | |
| gr.Button(f"Drop {i}").click( | |
| lambda x=i: play(x), | |
| outputs=[board_display, status, export_box] | |
| ) | |
| with gr.Row(): | |
| gr.Button("Undo").click(undo, outputs=[board_display, status, export_box]) | |
| gr.Button("Reset").click(reset_request, outputs=[board_display, status, export_box]) | |
| gr.Button("Import").click(import_game, inputs=[export_box], outputs=[board_display, status, export_box]) | |
| app.launch() |