Files
miku-discord/readmes/UNO_FLOW_DIAGRAMS.md
koko210Serve c708770266 reorganize: consolidate all documentation into readmes/
- Moved 20 root-level markdown files to readmes/
- Includes COMMANDS.md, CONFIG_README.md, all UNO docs, all completion reports
- Added new: MEMORY_EDITOR_FEATURE.md, MEMORY_EDITOR_ESCAPING_FIX.md,
  CONFIG_SOURCES_ANALYSIS.md, MCP_TOOL_CALLING_ANALYSIS.md, and others
- Root directory is now clean of documentation clutter
2026-03-04 00:19:49 +02:00

30 KiB

🎮 Miku UNO Bot - Visual Flow Diagrams

High-Level Architecture

┌─────────────────────────────────────────────────────────────┐
│                        Discord User                         │
│                     (Types: !uno create)                    │
└──────────────────────────┬──────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                       Miku Discord Bot                      │
│                      (bot.py + commands)                    │
│                                                             │
│  ┌──────────────┐    ┌──────────────┐   ┌──────────────┐ │
│  │   bot.py     │───▶│commands/uno.py│──▶│utils/uno_game│ │
│  │ (!uno route) │    │ (cmd handler) │   │(MikuUnoPlayer│ │
│  └──────────────┘    └──────────────┘   └───────┬────────┘ │
│                                                  │           │
└──────────────────────────────────────────────────┼──────────┘
                                                   │
                    ┌──────────────────────────────┼───────────┐
                    │                              │           │
                    ▼                              ▼           ▼
         ┌──────────────────┐          ┌─────────────┐  ┌─────────┐
         │   Playwright     │          │   HTTP API  │  │   LLM   │
         │ (Browser Control)│          │ (Actions)   │  │(Strategy│
         └────────┬─────────┘          └──────┬──────┘  └────┬────┘
                  │                           │              │
                  │                           │              │
                  ▼                           ▼              │
         ┌────────────────────────────────────────────┐     │
         │         UNO Game (Frontend)                │     │
         │      http://192.168.1.2:3002              │     │
         │                                            │     │
         │  ┌──────────────────────────────────────┐ │     │
         │  │        React Components              │ │     │
         │  │  - Game.js (main game logic)         │ │     │
         │  │  - botActionExecutor.js              │ │     │
         │  └──────────────┬───────────────────────┘ │     │
         │                 │                          │     │
         │                 ▼                          │     │
         │  ┌──────────────────────────────────────┐ │     │
         │  │      WebSocket Connection            │ │     │
         │  └──────────────┬───────────────────────┘ │     │
         └─────────────────┼────────────────────────┘     │
                           │                              │
                           ▼                              │
         ┌────────────────────────────────────────────┐   │
         │         UNO Game (Backend)                 │   │
         │        http://localhost:5000              │   │
         │                                            │   │
         │  ┌──────────────────────────────────────┐ │   │
         │  │       Express Server                 │ │   │
         │  │  - WebSocket (Socket.IO)             │ │   │
         │  │  - HTTP API endpoints                │ │   │
         │  │    GET /api/game/:code/state    ────┼─┼───┘
         │  │    POST /api/game/:code/action       │ │
         │  └──────────────────────────────────────┘ │
         │                                            │
         │  ┌──────────────────────────────────────┐ │
         │  │       Game State Manager             │ │
         │  │  - rooms{} dictionary                │ │
         │  │  - player management                 │ │
         │  │  - turn logic                        │ │
         │  └──────────────────────────────────────┘ │
         └────────────────────────────────────────────┘

Command Flow: !uno create

User Types: !uno create
         │
         ▼
    ┌─────────────────┐
    │  Discord.on()   │
    │  message event  │
    └────────┬────────┘
             │
             ▼
    ┌─────────────────────────────────────┐
    │  bot.py: Check if starts with !uno  │
    └────────┬────────────────────────────┘
             │
             ▼
    ┌──────────────────────────────────────────┐
    │  commands/uno.py: handle_uno_command()   │
    │  Parse command: "create"                 │
    └────────┬───────────────────────────────┘
             │
             ▼
    ┌──────────────────────────────────────────┐
    │  utils/uno_game.py: MikuUnoPlayer        │
    │  player = MikuUnoPlayer(channel, user)   │
    └────────┬───────────────────────────────┘
             │
             ▼
    ┌──────────────────────────────────────────┐
    │  await player.create_and_join_game()     │
    └────────┬───────────────────────────────┘
             │
             ├─────────────────┐
             │                 │
             ▼                 ▼
    ┌──────────────┐   ┌───────────────────────┐
    │ Generate     │   │ Launch Playwright     │
    │ Room Code    │   │ Headless Browser      │
    │ (6 chars)    │   │ (Chromium)            │
    └──────┬───────┘   └───────┬───────────────┘
           │                   │
           │                   ▼
           │          ┌─────────────────────────┐
           │          │ Navigate to:            │
           │          │ http://192.168.1.2:3002│
           │          └───────┬─────────────────┘
           │                  │
           │                  ▼
           │          ┌─────────────────────────┐
           │          │ Click "Join Room"       │
           │          │ Enter room code         │
           │          │ Submit                  │
           │          └───────┬─────────────────┘
           │                  │
           ▼                  ▼
    ┌──────────────────────────────────────┐
    │ Send Discord Embed:                  │
    │ "🎮 Created UNO room: ABC123         │
    │  Join at: http://192.168.1.2:3002   │
    │  I'm joining now as Player 2! ✨"    │
    └──────────────────────────────────────┘
                      │
                      ▼
    ┌──────────────────────────────────────┐
    │ Start game loop (play_game())        │
    │ Poll every 2 seconds                 │
    └──────────────────────────────────────┘

Game Loop Flow

    ┌─────────────────────┐
    │  play_game() loop   │
    │  while game_active  │
    └──────────┬──────────┘
               │
               ▼
    ┌─────────────────────────────┐
    │  await asyncio.sleep(2)     │  ◄─────┐
    └──────────┬──────────────────┘        │
               │                           │
               ▼                           │
    ┌─────────────────────────────┐        │
    │  get_game_state()           │        │
    │  GET /api/game/:code/state  │        │
    └──────────┬──────────────────┘        │
               │                           │
               ▼                           │
    ┌─────────────────────────────┐        │
    │  Is it Miku's turn?         │        │
    │  (currentPlayer == "Player 2"?) │    │
    └──────┬────────────┬─────────┘        │
           │NO          │YES               │
           │            │                  │
           │            ▼                  │
           │   ┌─────────────────────┐    │
           │   │ get_miku_decision() │    │
           │   │ (Call LLM)          │    │
           │   └──────┬──────────────┘    │
           │          │                   │
           │          ▼                   │
           │   ┌─────────────────────┐    │
           │   │ Build strategy prompt│    │
           │   │ - Current hand      │    │
           │   │ - Top card          │    │
           │   │ - Opponent cards    │    │
           │   │ - Strategic tips    │    │
           │   └──────┬──────────────┘    │
           │          │                   │
           │          ▼                   │
           │   ┌─────────────────────┐    │
           │   │ Query LLM           │    │
           │   │ (utils.llm)         │    │
           │   └──────┬──────────────┘    │
           │          │                   │
           │          ▼                   │
           │   ┌─────────────────────┐    │
           │   │ Parse JSON response │    │
           │   │ {"action": "play",  │    │
           │   │  "card": "R5"}      │    │
           │   └──────┬──────────────┘    │
           │          │                   │
           │          ▼                   │
           │   ┌─────────────────────┐    │
           │   │ Validate action     │    │
           │   │ (is card in hand?)  │    │
           │   └──────┬──────────────┘    │
           │          │                   │
           │          ▼                   │
           │   ┌─────────────────────┐    │
           │   │ send_action()       │    │
           │   │ POST /api/game/...  │    │
           │   └──────┬──────────────┘    │
           │          │                   │
           │          ▼                   │
           │   ┌─────────────────────┐    │
           │   │ send_trash_talk()   │    │
           │   │ (Discord message)   │    │
           │   └──────┬──────────────┘    │
           │          │                   │
           └──────────┴───────────────────┘
                      │
                      ▼
    ┌─────────────────────────────┐
    │  Check if game ended        │
    │  (winner exists?)           │
    └──────┬───────────┬──────────┘
           │NO         │YES
           │           │
           └───────────┤
                       │
                       ▼
    ┌─────────────────────────────┐
    │  Send final message         │
    │  "Game ended! Winner: ..."  │
    └──────────┬──────────────────┘
               │
               ▼
    ┌─────────────────────────────┐
    │  cleanup()                  │
    │  - Close browser            │
    │  - Remove from active games │
    └─────────────────────────────┘

LLM Strategy Decision Flow

    ┌─────────────────────────────┐
    │  get_miku_decision()        │
    └──────────┬──────────────────┘
               │
               ▼
    ┌─────────────────────────────────────────┐
    │  build_strategy_prompt(game_state)      │
    └──────────┬──────────────────────────────┘
               │
               ▼
    ┌─────────────────────────────────────────┐
    │  Construct prompt with:                 │
    │  "You are Miku, a cheerful idol..."     │
    │                                          │
    │  Current Game State:                    │
    │  - Your hand: R5, G2, B7, WD4          │
    │  - Top card: Y3                         │
    │  - Opponent has: 4 cards                │
    │                                          │
    │  Strategic Tips:                         │
    │  - Match color or number                │
    │  - Use Wild cards strategically         │
    │  - Save action cards for impact         │
    │                                          │
    │  Output ONLY valid JSON:                │
    │  {"action":"play","card":"R5"}          │
    └──────────┬──────────────────────────────┘
               │
               ▼
    ┌─────────────────────────────────────────┐
    │  await query_llama(prompt)              │
    │  (utils.llm.query_llama)                │
    └──────────┬──────────────────────────────┘
               │
               ▼
    ┌─────────────────────────────────────────┐
    │  LLM Response:                          │
    │  "{"action":"play","card":"Y5"}"        │
    └──────────┬──────────────────────────────┘
               │
               ▼
    ┌─────────────────────────────────────────┐
    │  Try parse JSON                         │
    └──────┬───────────────┬──────────────────┘
           │ Success       │ Fail
           │               │
           ▼               ▼
    ┌──────────────┐  ┌────────────────────┐
    │ Validate:    │  │ Log error          │
    │ - action OK? │  │ Fallback: draw     │
    │ - card valid?│  └────────────────────┘
    │ - in hand?   │
    └──────┬───────┘
           │ Valid
           │
           ▼
    ┌─────────────────────────────┐
    │  Return action dict         │
    │  {"action":"play","card":..}│
    └─────────────────────────────┘

Trash Talk Selection Flow

    ┌─────────────────────────────┐
    │  send_trash_talk(action)    │
    └──────────┬──────────────────┘
               │
               ▼
    ┌─────────────────────────────┐
    │  Check card type            │
    └──┬──┬──┬──┬──┬──────────────┘
       │  │  │  │  │
       │  │  │  │  └──────────┐
       │  │  │  └─────────┐   │
       │  │  └────────┐   │   │
       │  └───────┐   │   │   │
       ▼          ▼   ▼   ▼   ▼
    ┌──────┐ ┌────┐ ┌──┐ ┌──┐ ┌────┐
    │ WD4  │ │ D  │ │S │ │W │ │REG │
    │Draw 4│ │Dr 2│ │Sk│ │Wi│ │Norm│
    └──┬───┘ └──┬─┘ └┬─┘ └┬─┘ └─┬──┘
       │        │    │    │     │
       ▼        ▼    ▼    ▼     ▼
    ┌────────────────────────────────────┐
    │ "Take four    "Draw    "Sorry~     │
    │  cards! 💙✨   two      Skipping    │
    │  I hope        cards!   your turn!  │
    │  you're        Don't    Maybe next  │
    │  ready for     worry,   time? 🎶"   │
    │  a comeback~"  I still               │
    │               believe               │
    │               in you~               │
    │               ✨"                   │
    └────────┬──────────────────────┬────┘
             │                      │
             ▼                      ▼
    ┌──────────────────┐   ┌───────────────┐
    │ Send to Discord  │   │ Random choice │
    │ channel.send()   │   │ from variants │
    └──────────────────┘   └───────────────┘

Data Flow: Game State

┌────────────────────────────────────────┐
│        UNO Backend (server.js)         │
│                                        │
│  rooms = {                             │
│    "ABC123": {                         │
│      roomId: "ABC123",                 │
│      users: ["Player 1", "Player 2"],  │
│      gameState: {                      │
│        currentPlayer: "Player 2",      │
│        topCard: "Y3",                  │
│        players: [                      │
│          {                             │
│            name: "Player 1",           │
│            hand: [...],  (hidden)      │
│            cardCount: 5                │
│          },                            │
│          {                             │
│            name: "Player 2",           │
│            hand: ["R5","G2",...],      │
│            cardCount: 7                │
│          }                             │
│        ],                              │
│        winner: null,                   │
│        direction: 1                    │
│      }                                 │
│    }                                   │
│  }                                     │
└─────────┬──────────────────────────────┘
          │
          │ HTTP GET /api/game/ABC123/state
          │
          ▼
┌────────────────────────────────────────┐
│  JSON Response (filtered for Player 2) │
│  {                                     │
│    "currentPlayer": "Player 2",        │
│    "topCard": "Y3",                    │
│    "myHand": ["R5","G2","B7",...],    │
│    "myCardCount": 7,                   │
│    "opponentCardCount": 5,             │
│    "direction": 1,                     │
│    "winner": null                      │
│  }                                     │
└─────────┬──────────────────────────────┘
          │
          ▼
┌────────────────────────────────────────┐
│  MikuUnoPlayer processes state         │
│  - Detects it's her turn               │
│  - Sees available cards                │
│  - Checks top card                     │
│  - Asks LLM for strategy               │
└─────────┬──────────────────────────────┘
          │
          ▼
┌────────────────────────────────────────┐
│  LLM returns decision                  │
│  {"action":"play","card":"R5"}         │
└─────────┬──────────────────────────────┘
          │
          │ HTTP POST /api/game/ABC123/action
          │ Body: {"action":"play","card":"R5"}
          │
          ▼
┌────────────────────────────────────────┐
│  Backend validates and executes        │
│  - Check if R5 is in Player 2's hand   │
│  - Check if R5 can be played on Y3     │
│  - Move R5 from hand to pile           │
│  - Update topCard to R5                │
│  - Switch currentPlayer to Player 1    │
│  - Emit WebSocket event to all clients │
└────────────────────────────────────────┘
          │
          ▼
┌────────────────────────────────────────┐
│  Frontend updates UI                   │
│  - Card animation                      │
│  - Update piles                        │
│  - Show turn indicator                 │
└────────────────────────────────────────┘

File Dependency Graph

bot.py
  │
  ├─> commands/uno.py
  │     │
  │     └─> utils/uno_game.py
  │           │
  │           ├─> playwright
  │           │     └─> (browser control)
  │           │
  │           ├─> utils/llm.py
  │           │     └─> query_llama()
  │           │
  │           ├─> aiohttp
  │           │     └─> (HTTP requests)
  │           │
  │           └─> discord.py
  │                 └─> (Discord messages)
  │
  └─> globals.py
        └─> (configuration)

uno-online/
  │
  ├─> server.js
  │     ├─> express
  │     ├─> socket.io (WebSocket)
  │     └─> HTTP API (/api/game/...)
  │
  └─> client/
        │
        ├─> src/App.js
        │     └─> React Router
        │
        └─> src/components/Game.js
              ├─> Socket.IO client
              └─> utils/botActionExecutor.js
                    └─> (action validation & execution)

Discord Command Hierarchy

!uno
 ├─> create
 │    └─> MikuUnoPlayer.create_and_join_game()
 │         ├─> Generate room code
 │         ├─> Launch browser
 │         ├─> Join room
 │         └─> Start game loop
 │
 ├─> join <code>
 │    └─> MikuUnoPlayer.join_game(code)
 │         ├─> Launch browser
 │         ├─> Join existing room
 │         └─> Start game loop
 │
 ├─> list
 │    └─> Show active_uno_games dict
 │         └─> Format as Discord embed
 │
 ├─> quit <code>
 │    └─> Find game by code
 │         ├─> Call cleanup()
 │         ├─> Remove from active_uno_games
 │         └─> Send confirmation
 │
 └─> help
      └─> Show command list
           └─> Format as Discord embed

Timing Diagram

Time    User           Bot            UNO Server     LLM
─────────────────────────────────────────────────────────
 0s    !uno create
                      │
 1s                   ├─> Generate ABC123
                      │
 2s                   ├─> Launch browser
                      │
 3s                   ├─> Navigate to URL
                      │
 4s                   ├─> Join room ──────> Create room
                      │                     Add Player 2
 5s                   ├─> Send embed
       Sees embed     │   "Room: ABC123"
                      │
 6s    Opens URL      │
       Joins room ─────────────────────> Add Player 1
                                          Start game
                                          Deal cards
10s                   ├─> Poll state <──── Game state
                      │   (Player 1 turn)
                      │
12s                   ├─> Poll state <──── Game state
                      │   (Player 1 turn)
                      │
15s    Plays card ─────────────────────> Update state
                                          Player 2 turn
                                          
16s                   ├─> Poll state <──── Game state
                      │   (Player 2 turn!)
                      │
17s                   ├─> Strategy? ─────────────────> LLM
                      │                                │
18s                   │                                │ Think
                      │                                │
19s                   │   <─────────────────── JSON ──┘
                      │
20s                   ├─> Play card ──────> Execute
                      │                     Validate
                      │                     Update
21s                   ├─> Trash talk
       Sees message   │   "Playing card~"
                      │
22s                   ├─> Poll state <──── Game state
                      │   (Player 1 turn)
...                  ...                 ...

These diagrams should help visualize how everything connects! 🎮