# Bot Action Specification for UNO Game ## Overview The bot (Miku) can interact with the UNO game by sending JSON action commands. The game state is provided in a structured JSON format, and the bot responds with action commands. ## Action Types ### 1. Play a Card ```json { "action": "play", "card": "4R", "color": null } ``` - `action`: Must be `"play"` - `card`: The card code to play (e.g., "4R", "D2G", "skipB", "W", "D4W") - `color`: Optional. Only required for wild cards ("W" or "D4W"). Values: "R", "G", "B", or "Y" **Examples:** ```json // Play a number card {"action": "play", "card": "4R", "color": null} // Play a Draw 2 card {"action": "play", "card": "D2G", "color": null} // Play a Skip card {"action": "play", "card": "skipB", "color": null} // Play a Wild card (must specify color) {"action": "play", "card": "W", "color": "R"} // Play a Wild Draw 4 (must specify color) {"action": "play", "card": "D4W", "color": "B"} ``` ### 2. Draw a Card ```json { "action": "draw" } ``` - `action`: Must be `"draw"` - No other parameters needed ### 3. Call UNO ```json { "action": "uno" } ``` - `action`: Must be `"uno"` - Call this when you have exactly 2 cards in hand and are about to play one - **Important:** Call UNO *before* playing your second-to-last card, or call it as a separate action ### 4. Combined Actions (Play + UNO) ```json { "action": "play", "card": "4R", "color": null, "callUno": true } ``` - Add `"callUno": true` when playing a card that will leave you with 1 card ## Card Code Reference ### Number Cards - Format: `{number}{color}` - Numbers: 0-9 - Colors: R (Red), G (Green), B (Blue), Y (Yellow) - Examples: `0R`, `5G`, `9B`, `3Y` ### Action Cards - **Skip**: `skipR`, `skipG`, `skipB`, `skipY` - **Reverse**: `_R`, `_G`, `_B`, `_Y` - **Draw 2**: `D2R`, `D2G`, `D2B`, `D2Y` - **Wild**: `W` - **Wild Draw 4**: `D4W` ## Color Codes - `R` - Red - `G` - Green - `B` - Blue - `Y` - Yellow ## Strategy Tips for Bot ### When to Play Cards 1. Check `botContext.canPlay` - if false, you must draw 2. Look at `player2.playableCards` for available moves 3. Match by color or number with `currentCard` ### Priority Strategy 1. **Action cards first** (Skip, Draw 2, Wild Draw 4) to disrupt opponent 2. **Match color** if opponent has few cards (to block them) 3. **Match number** to change color advantageously 4. **Save wild cards** for critical moments ### When to Call UNO - When you have exactly 2 cards and are about to play one - **Must call UNO** or you'll get 2 penalty cards! ### When to Use Wild Cards - When you have no other playable cards - To change to a color you have many of - Wild Draw 4: When opponent has 1-2 cards (aggressive) ## HTTP API Endpoint ### Get Game State ``` GET http://localhost:5000/api/game/\{roomCode\}/state ``` **Response:** ```json { "success": true, "gameState": { /* full game state */ }, "timestamp": "2026-01-27T..." } ``` ### Submit Bot Action ``` POST http://localhost:5000/api/game/\{roomCode\}/action Content-Type: application/json { "action": "play", "card": "4R", "color": null } ``` **Response:** ```json { "success": true, "message": "Action received and forwarded to game" } ``` ## Error Handling ### Invalid Actions The game will ignore invalid actions: - Playing a card not in your hand - Playing an unplayable card - Not specifying color for wild cards - Playing out of turn ### Validation Before sending an action: 1. Verify it's Player 2's turn (`game.currentTurn === "Player 2"`) 2. Check card is in `player2.cards` array 3. Verify card is in `player2.playableCards` array 4. For wild cards, always specify a valid color ## Example Bot Decision Flow ```python def make_move(game_state): # Check if it's our turn if game_state['game']['currentTurn'] != 'Player 2': return None # Check if we can play if not game_state['botContext']['canPlay']: return {"action": "draw"} # Get playable cards playable = game_state['player2']['playableCards'] if not playable: return {"action": "draw"} # Check if we need to call UNO our_cards = game_state['player2']['cardCount'] call_uno = (our_cards == 2) # Priority: Draw 2 or Draw 4 for card in playable: if card['type'] in ['draw2', 'draw4']: action = {"action": "play", "card": card['code']} if card['type'] == 'draw4': action['color'] = choose_best_color(game_state) if call_uno: action['callUno'] = True return action # Priority: Skip or Reverse for card in playable: if card['type'] in ['skip', 'reverse']: if call_uno: return {"action": "play", "card": card['code'], "callUno": True} return {"action": "play", "card": card['code']} # Play any available card card = playable[0] action = {"action": "play", "card": card['code']} if card['type'] == 'wild': action['color'] = choose_best_color(game_state) if call_uno: action['callUno'] = True return action ``` ## WebSocket Events (Alternative to HTTP) If the bot maintains a WebSocket connection: ### Emit bot action: ```javascript socket.emit('botAction', { action: 'play', card: '4R', color: null }) ``` ### Receive game state updates: ```javascript socket.on('updateGameState', (state) => { // Process new game state }) ```