Files
miku-discord/uno-online/BOT_INTEGRATION_COMPLETE.md
koko210Serve 34b184a05a add: absorb uno-online as regular subdirectory
UNO card game web app (Node.js/React) with Miku bot integration.
Previously an independent git repo (fork of mizanxali/uno-online).
Removed .git/ and absorbed into main repo for unified tracking.

Includes bot integration code: botActionExecutor, cardParser,
gameStateBuilder, and server-side bot action support.
37 files, node_modules excluded via local .gitignore.
2026-03-04 00:21:38 +02:00

7.2 KiB
Raw Blame History

🤖 Bot Integration Complete Guide

Overview

The UNO game now supports bot players (Miku) making moves via JSON API. The bot can play cards, draw cards, and call UNO by sending structured JSON commands.

Quick Start

1. Start a game with 2 players

  • Player 1: Create a room (e.g., room code "ABC123")
  • Player 2: Join the same room
  • Game will auto-start when both players are present

2. Get the current game state

curl http://localhost:5000/api/game/ABC123/state

3. Send a bot action (when it's Player 2's turn)

# Draw a card
curl -X POST http://localhost:5000/api/game/ABC123/action \
  -H "Content-Type: application/json" \
  -d '{"action":"draw"}'

# Play a card
curl -X POST http://localhost:5000/api/game/ABC123/action \
  -H "Content-Type: application/json" \
  -d '{"action":"play","card":"4R"}'

# Play a wild card with color choice
curl -X POST http://localhost:5000/api/game/ABC123/action \
  -H "Content-Type: application/json" \
  -d '{"action":"play","card":"W","color":"R"}'

# Call UNO
curl -X POST http://localhost:5000/api/game/ABC123/action \
  -H "Content-Type: application/json" \
  -d '{"action":"uno"}'

Testing Bot Actions

Use the included test script:

# Test drawing a card
node test-bot-action.js ABC123 '{"action":"draw"}'

# Test playing a card
node test-bot-action.js ABC123 '{"action":"play","card":"4R"}'

# Test playing a wild card
node test-bot-action.js ABC123 '{"action":"play","card":"W","color":"B"}'

Action Format Specification

Play a Card

{
  "action": "play",
  "card": "4R",
  "color": null,
  "callUno": false
}

Parameters:

  • action (string, required): Must be "play"
  • card (string, required): Card code (e.g., "4R", "D2G", "skipB", "W", "D4W")
  • color (string, optional): Required for wild cards ("W", "D4W"). Values: "R", "G", "B", "Y"
  • callUno (boolean, optional): Set to true to call UNO with this play

Draw a Card

{
  "action": "draw"
}

Call UNO

{
  "action": "uno"
}

Card Codes Reference

Number Cards

  • 0R, 1R, ..., 9R - Red numbers
  • 0G, 1G, ..., 9G - Green numbers
  • 0B, 1B, ..., 9B - Blue numbers
  • 0Y, 1Y, ..., 9Y - Yellow numbers

Action Cards

  • skipR, skipG, skipB, skipY - Skip cards
  • _R, _G, _B, _Y - Reverse cards
  • D2R, D2G, D2B, D2Y - Draw 2 cards

Wild Cards

  • W - Wild (change color)
  • D4W - Wild Draw 4 (change color + opponent draws 4)

Game State Structure

The game state JSON includes:

  • game: Overall game status (isOver, winner, currentTurn, turnNumber)
  • currentCard: The card on top of the discard pile
  • player1: Player 1's info and cards (hidden from bot)
  • player2: Player 2's (bot's) info and cards (visible)
  • player2.playableCards: Array of cards the bot can currently play
  • botContext: Helper info (canPlay, mustDraw, hasUno, actions)

Validation Rules

The game validates bot actions:

  1. Turn validation: Must be Player 2's turn
  2. Card validation: Card must be in Player 2's hand
  3. Playability: Card must be playable on current card
  4. Wild cards: Must specify color for "W" and "D4W"
  5. UNO: Can only call with exactly 2 cards in hand

Integration with Miku Bot

From Python (Miku bot)

import requests
import json

def get_game_state(room_code):
    response = requests.get(f'http://localhost:5000/api/game/{room_code}/state')
    return response.json()['gameState']

def send_bot_action(room_code, action):
    response = requests.post(
        f'http://localhost:5000/api/game/{room_code}/action',
        headers={'Content-Type': 'application/json'},
        data=json.dumps(action)
    )
    return response.json()

# Example: Make a strategic move
state = get_game_state('ABC123')

if state['game']['currentTurn'] == 'Player 2':
    playable = state['player2']['playableCards']
    
    if playable:
        # Play first playable card
        card = playable[0]
        action = {'action': 'play', 'card': card['code']}
        
        # Handle wild cards
        if card['type'] in ['wild', 'draw4']:
            action['color'] = 'R'  # Choose a color
        
        # Call UNO if needed
        if state['player2']['cardCount'] == 2:
            action['callUno'] = True
        
        result = send_bot_action('ABC123', action)
        print(f"Played {card['displayName']}: {result}")
    else:
        # Must draw
        result = send_bot_action('ABC123', {'action': 'draw'})
        print(f"Drew a card: {result}")

LLM Integration Example

def miku_make_move(game_state):
    """Use LLM to decide Miku's move"""
    
    # Build prompt for LLM
    prompt = f"""
You are playing UNO. It's your turn.

Current card on table: {game_state['currentCard']['displayName']}
Your cards: {[c['displayName'] for c in game_state['player2']['cards']]}
Playable cards: {[c['displayName'] for c in game_state['player2']['playableCards']]}

Opponent has {game_state['player1']['cardCount']} cards.
You have {game_state['player2']['cardCount']} cards.

Choose your move as JSON:
{{"action": "play", "card": "CODE"}} or {{"action": "draw"}}
"""
    
    # Get LLM response
    llm_response = query_llama(prompt)
    
    # Parse JSON from response
    action = json.loads(llm_response)
    
    # Send action
    return send_bot_action(game_state['room'], action)

Debugging

Console Logs

The game client logs bot actions:

  • 🤖 Received bot action: - Action received from HTTP API
  • 🤖 Bot action result: - Result of executing the action
  • <EFBFBD><EFBFBD> Bot playing card: - Card being played
  • 🌈 Bot chose color: - Color chosen for wild card
  • 🔥 Bot called UNO! - UNO was called
  • 📥 Bot drawing a card - Card was drawn

Error Messages

  • ❌ Bot action rejected: Not Player 2's turn - Wrong turn
  • ❌ Bot play action rejected: Card not in hand - Invalid card
  • ❌ Bot play action rejected: Wild card without color - Missing color
  • ❌ Bot UNO rejected - Invalid UNO call

Files Added/Modified

New Files

  • BOT_ACTION_SPEC.md - Detailed API specification
  • BOT_INTEGRATION_COMPLETE.md - This file
  • client/src/utils/botActionExecutor.js - Bot action executor
  • test-bot-action.js - Test script

Modified Files

  • server.js - HTTP API endpoints for bot actions
  • client/src/components/Game.js - Bot action listener and integration

Next Steps

  1. Test the integration: Use test-bot-action.js to verify actions work
  2. Integrate with Miku: Add UNO game support to Miku bot
  3. Add LLM strategy: Use Miku's LLM to make strategic decisions
  4. Add personality: Make Miku trash talk and celebrate!

Example Full Game Flow

# Terminal 1: Start server
cd /home/koko210Serve/docker/uno-online
npm start

# Terminal 2: Start client dev server
cd /home/koko210Serve/docker/uno-online/client
npm start

# Browser 1: Create game as Player 1
# Open http://localhost:3000
# Create room "MIKU01"

# Browser 2: Join as Player 2
# Open http://localhost:3000
# Join room "MIKU01"

# Terminal 3: Control Player 2 (bot) via API
# Get state
curl http://localhost:5000/api/game/MIKU01/state | jq

# Make a move (when it's Player 2's turn)
node test-bot-action.js MIKU01 '{"action":"play","card":"4R"}'

🎉 The bot integration is complete and ready to use!