dataflow.api.simple_chess_ws

Simple WebSocket server for streaming chess game state.

Attributes

Functions

get_empty_board()

Create a new chess board in starting position.

get_game_state(game_id)

Get the current game state.

get_html()

Serve the HTML client.

main()

Run the WebSocket server.

make_random_move(board)

Make a random legal move.

websocket_endpoint(websocket, game_id)

WebSocket endpoint for chess games.

Module Contents

dataflow.api.simple_chess_ws.get_empty_board()

Create a new chess board in starting position.

dataflow.api.simple_chess_ws.get_game_state(game_id)

Get the current game state.

async dataflow.api.simple_chess_ws.get_html()

Serve the HTML client.

dataflow.api.simple_chess_ws.main()

Run the WebSocket server.

dataflow.api.simple_chess_ws.make_random_move(board)

Make a random legal move.

async dataflow.api.simple_chess_ws.websocket_endpoint(websocket: fastapi.WebSocket, game_id: str)

WebSocket endpoint for chess games.

dataflow.api.simple_chess_ws.active_connections: set[fastapi.WebSocket]
dataflow.api.simple_chess_ws.active_games: dict[str, dict]
dataflow.api.simple_chess_ws.app
dataflow.api.simple_chess_ws.html = Multiline-String
Show Value
"""
<!DOCTYPE html>
<html>
    <head>
        <title>Chess WebSocket Client</title>
        <style>
            body {
                font-family: Arial, sans-serif;
                max-width: 800px;
                margin: 0 auto;
                padding: 20px;
            }
            .chessboard {
                width: 400px;
                height: 400px;
                border: 1px solid #000;
                display: grid;
                grid-template-columns: repeat(8, 1fr);
                grid-template-rows: repeat(8, 1fr);
            }
            .square {
                display: flex;
                justify-content: center;
                align-items: center;
                font-size: 30px;
            }
            .white {
                background-color: #f0d9b5;
            }
            .black {
                background-color: #b58863;
            }
            .log {
                height: 200px;
                overflow-y: auto;
                border: 1px solid #ccc;
                padding: 10px;
                margin-top: 20px;
            }
        </style>
    </head>
    <body>
        <h1>Chess WebSocket Client</h1>

        <div>
            <label for="gameId">Game ID:</label>
            <input type="text" id="gameId" value="test123">
            <button onclick="connect()">Connect</button>
            <button onclick="disconnect()">Disconnect</button>
        </div>

        <div style="display: flex; margin-top: 20px;">
            <div>
                <div class="chessboard" id="board"></div>
                <div style="margin-top: 10px;">
                    <button onclick="getState()">Get State</button>
                    <button onclick="aiMove()">AI Move</button>
                </div>
            </div>

            <div style="margin-left: 20px; flex: 1;">
                <h3>Game Info</h3>
                <div id="gameInfo">
                    <p>Status: <span id="status">Disconnected</span></p>
                    <p>Turn: <span id="turn">-</span></p>
                    <p>Game Status: <span id="gameStatus">-</span></p>
                </div>

                <h3>Log</h3>
                <div class="log" id="log"></div>
            </div>
        </div>

        <script>
            // Game data
            let ws = null;
            let gameState = null;
            let boardElement = document.getElementById('board');
            let statusElement = document.getElementById('status');
            let turnElement = document.getElementById('turn');
            let gameStatusElement = document.getElementById('gameStatus');
            let logElement = document.getElementById('log');

            // Chess pieces mapping
            const pieceMap = {
                'K': '♔', 'Q': '♕', 'R': '♖', 'B': '♗', 'N': '♘', 'P': '♙',  // White pieces
                'k': '♚', 'q': '♛', 'r': '♜', 'b': '♝', 'n': '♞', 'p': '♟'   // Black pieces
            };

            // Initialize the board
            function initBoard() {
                boardElement.innerHTML = '';
                for (let row = 0; row < 8; row++) {
                    for (let col = 0; col < 8; col++) {
                        const square = document.createElement('div');
                        square.className = `square ${(row + col) % 2 === 0 ? 'white' : 'black'}`;
                        square.dataset.row = 7 - row;  // Flip for chess notation
                        square.dataset.col = col;
                        boardElement.appendChild(square);
                    }
                }
            }

            // Update board from FEN
            function updateBoard(fen) {
                if (!fen) return;

                const boardFen = fen.split(' ')[0];
                const rows = boardFen.split('/');

                for (let rowIndex = 0; rowIndex < 8; rowIndex++) {
                    let colIndex = 0;
                    const row = rows[rowIndex];

                    for (let i = 0; i < row.length; i++) {
                        const char = row[i];

                        if (isNaN(char)) {
                            // It's a piece
                            const square = document.querySelector(`.square[data-row="${rowIndex}"][data-col="${colIndex}"]`);
                            if (square) {
                                square.textContent = pieceMap[char] || char;
                            }
                            colIndex++;
                        } else {
                            // It's a number of empty squares
                            colIndex += parseInt(char);
                        }
                    }
                }
            }

            // Add to log
            function log(message) {
                const entry = document.createElement('div');
                entry.textContent = message;
                logElement.appendChild(entry);
                logElement.scrollTop = logElement.scrollHeight;
            }

            // Connect WebSocket
            function connect() {
                const gameId = document.getElementById('gameId').value || 'test123';
                const wsUrl = `ws://${window.location.host}/ws/chess/${gameId}`;

                if (ws) {
                    ws.close();
                }

                log(`Connecting to ${wsUrl}...`);
                ws = new WebSocket(wsUrl);

                ws.onopen = function(event) {
                    statusElement.textContent = 'Connected';
                    log('Connection established');
                    getState();
                };

                ws.onmessage = function(event) {
                    log(`Received: ${event.data}`);

                    try {
                        const data = JSON.parse(event.data);

                        if (data.type === 'state_update') {
                            gameState = data.state;
                            updateBoard(gameState.board_fen);
                            turnElement.textContent = gameState.current_player || '-';
                            gameStatusElement.textContent = gameState.game_status || '-';
                        } else if (data.type === 'error') {
                            log(`Error: ${data.message}`);
                        }
                    } catch (e) {
                        log(`Error parsing message: ${e.message}`);
                    }
                };

                ws.onclose = function(event) {
                    statusElement.textContent = 'Disconnected';
                    log('Connection closed');
                };

                ws.onerror = function(event) {
                    statusElement.textContent = 'Error';
                    log('WebSocket error');
                };
            }

            // Disconnect WebSocket
            function disconnect() {
                if (ws) {
                    ws.close();
                    ws = null;
                }
            }

            // Get game state
            function getState() {
                if (ws && ws.readyState === WebSocket.OPEN) {
                    const message = {
                        type: 'get_state'
                    };
                    ws.send(JSON.stringify(message));
                    log(`Sent: ${JSON.stringify(message)}`);
                } else {
                    log('WebSocket not connected');
                }
            }

            // Request AI move
            function aiMove() {
                if (ws && ws.readyState === WebSocket.OPEN) {
                    const message = {
                        type: 'ai_move'
                    };
                    ws.send(JSON.stringify(message));
                    log(`Sent: ${JSON.stringify(message)}`);
                } else {
                    log('WebSocket not connected');
                }
            }

            // Initialize
            initBoard();
        </script>
    </body>
</html>
"""
dataflow.api.simple_chess_ws.logger