μ€λ²ν€λ μΉ΄λ©λΌ κΈ°λ° μ€μκ° κ°μ²΄μΈμκ³Ό λ©ν°μμ΄μ νΈλ₯Ό νμ©ν 보λκ²μ μ§ν μμ€ν
νλ μ΄μ΄λ μ€λ¬Ό 보λκ²μμ κ·Έλλ‘ μ¦κΈ°κ³ , μμ΄μ νΈκ° μ§νμ(λλ¬)λ₯Ό λμ ν΄ μΈμ Β· μ¬ν Β· μ§ν Β· ν΄μ€μ μννλ€.
ν μ΄λΈ μμ μ€μΉλ μΉ΄λ©λΌ ν λκ° μ£Όμ¬μ Β· μΉ΄λ Β· μλμμ μ€μκ°μΌλ‘ μΈμνκ³ , κ²μ κ·μΉ μμ§(FSM)κ³Ό λ€ κ°μ μμ΄μ νΈκ° νλ ₯νμ¬ μ¬λ μ§νμ μμ΄ λ³΄λκ²μμ μ²μλΆν° λκΉμ§ μ§ννλ€. νλ μ΄μ΄λ νλΈλ¦Ώ νλ©΄κ³Ό μμ± μλ΄λ§ λ°λΌκ°λ©΄ λλ©°, νμ¬ μνΈλ€μ΄μ€μ νλ°€μ λλμΈκ°μ μ§μνλ€.
보λκ²μμ κ·μΉ μ€λͺ Β· μ°¨λ‘ κ΄λ¦¬ Β· μ μ κ³μ° Β· νμ μ μ§νμλ₯Ό νμλ‘ νκ³ , κ·μΉμ λͺ¨λ₯΄λ©΄ μμ μμ²΄κ° μ΄λ ΅λ€. λ³Έ μμ€ν μ ν μ΄λΈμ κ΄μ°°νκ³ , κ·μΉμ μ μ©νκ³ , μμ±μΌλ‘ μλ΄νλ AI μ§νμλ₯Ό ꡬννμ¬ μ΄ μ§μ μ₯λ²½μ ν΄μνλ©°, νλ μ΄μ΄ κ²½νμ μ€λ¬Ό κ·Έλλ‘ μ μ§νλ Analog-first μ€κ³λ₯Ό λ°λ₯Έλ€.
| νλͺ© | λ΄μ© |
|---|---|
| μ§μ κ²μ | μνΈλ€μ΄μ€(Yacht Dice) Β· νλ°€μ λλμΈκ°(One Night Werewolf) |
| μΈμ | YOLO(μ£Όμ¬μ Β· μΉ΄λ) + MediaPipe(μ) + OpenCV(μ£Όμ¬μ λ νλ ) |
| μ§ν | μ¬ν Β· ν ν¬ Β· μ§ν Β· μ λ΅ λ€ μμ΄μ νΈμ μ°μ μμ νλ ₯ + LLM μ λ΅ μ½μΉ |
| μμ± | Google Cloud TTS Β· 3-κ³μΈ΅ μΊμ Β· μ°μ μμ ν(λΌμ΄λ€κΈ° Β· νμ΄λ) |
| νλ©΄ | React κΈ°λ° νλΈλ¦Ώ UI Β· WebSocket μ€μκ° λκΈ°ν |
μμ€ν κ΅¬μ± β μ€λ²ν€λ μΉ΄λ©λΌ + ν μ΄λΈ + νλΈλ¦Ώ
λ‘λΉ Β· μ’μ λ±λ‘ νλ©΄
μνΈλ€μ΄μ€ μ§ν νλ©΄
νλ°€μ λλμΈκ° μ§ν νλ©΄
λΉμ (μΉ΄λ©λΌ)κ³Ό κ²μ κ·μΉμ μλ‘μ μ½λλ₯Ό μ§μ νΈμΆνμ§ μκ³ λ μ’ λ₯μ λ©μμ§λ‘λ§ ν΅μ νλ€.
GameEvent(λΉμ β κ·μΉ): "νΉμ μ¬κ±΄μ΄ λ°μνλ€" β μ: μ£Όμ¬μλ₯Ό κ΅΄λ Έλ€, μΉ΄λλ₯Ό νμΈνλ€.FusionContext(κ·μΉ β λΉμ ): "νμ¬ λ¨κ³μμ κΈ°λνλ μ λ ₯" β μ: νμ¬ μ°¨λ‘ Β· νμ© νλ Β· κΈ°λ μ΄λ²€νΈ.
κ·μΉ μμ§μ΄ λ¨κ³λ§λ€ κΈ°λ μ΄λ²€νΈλ₯Ό νμ ν΄ μ λ¬νλ©΄ λΉμ μ κ·Έ μΈμ μ¬κ±΄μ λ°ννμ§ μλλ€. μ΄ μν κΈ°λ° κ²μ΄ν μ μ€μΈμμ μ€μ΄λ λμμ μ κ²μμ μΆκ°νκΈ° μ¬μ΄ νμ₯μ±μ μ 곡νλ€.
- ν λ°©ν₯ κΈ°λ° μ’μ λ§€μΉ β μμμ λ΄λ €λ€λ³΄λ μμ μμλ μΌκ΅΄μ΄ 보μ΄μ§ μμΌλ―λ‘, νμ΄ λ»μ΄ λ€μ΄μ€λ κ°λμ μΆμ ν λͺΈ μμΉλ‘ μμ μ£ΌμΈμ μλ³νλ€. μ΄λ₯Ό ν΅ν΄ μ°¨λ‘κ° μλ μ¬λμ νλμ μλμΌλ‘ κ°μ§νλ€.
- κ΅΄λ¦Ό κ·μ(RollAttributor) β μνΈ μ£Όμ¬μλ κ΅΄λ¦Όν΅μ μμ΄ κ±°μ ꡬλ₯΄μ§ μμΌλ―λ‘, μμ§μ λμ μμ νΈλ μ΄ μ μ Β· κ΅΄λ¦Όν΅ μ¬μ© Β· μ£Όμ¬μ λ λΆν¬ λ³νλ₯Ό μ’ ν©ν΄ μ€μ κ΅΄λ¦Όμ νμ νλ€.
- μμμ²λ¦¬ κΈ°λ° μ£Όμ¬μ λ νλ β OpenCVλ‘ λ°κΈ°λ₯Ό 보μ (CLAHE)ν λ€ μν κ²μΆ(HoughCircles)λ‘ μ£Όμ¬μ λ 1~6μ μ½λλ€.
νλμ κ±°λν λͺ¨λΈ λμ μν μ΄ κ΅¬λΆλ λ€ κ°μ κ²½λ μμ΄μ νΈκ° μ°μ μμμ λ°λΌ νλ ₯νλ€. μ¬νμ μ¦μ κ°μ νκ³ , μ§νκ³Ό μ λ΅ μλ΄λ κ²μ νλ¦μ λ°©ν΄νμ§ μλλ€.
| μ°μ μμ | μμ΄μ νΈ | μν | μμ± μ°μ μμ |
|---|---|---|---|
| 1 | Rules (μ¬ν) | μ°¨λ‘ μλ° Β· κΈμ§ νλ μ¦μ κ°μ , νμ μ΅μ | CRITICAL |
| 2 | Tempo (ν ν¬) | ν΄ νμ΄λ¨Έ κ²½κ³Ό Β· μ’ λ£ μλ° κ²½κ³ | HIGH |
| 3 | Progress (μ§ν) | λ¨κ³ μ ν μλ΄ λ° ν΄μ€ | NORMAL |
| 4 | Strategy (μ λ΅) | (μ ν) LLM κΈ°λ° μ λ΅ μΆμ², κ·μΉ ν΄λ°± | LOW |
Google Cloud TTSμ 3-κ³μΈ΅ λμ€ν¬ μΊμλ‘ ν©μ± λΉμ©μ μ΅μννκ³ , μ°μ μμ νλ‘ μλ΄κ° κ²ΉμΉμ§ μλλ‘ μ§λ ¬ννλ€. κΈ΄κΈ μλ΄(CRITICAL)λ μ§ν μ€μΈ λ©νΈλ₯Ό νμ΄λμμνλ©° μ¦μ λΌμ΄λ λ€.
νλ μ΄μ΄ λ±λ‘ β μνΈλ€μ΄μ€ β νλ°€μ λλμΈκ°μ νλμ μΈμ μΌλ‘ μ°μ μ§ννλ©° μΈ‘μ νμλ€. μλ΅μκ°μ End-to-End(νλ μ΄μ΄μ 물리μ νλλΆν° νλ©΄ Β· μμ± λ°μκΉμ§)λ₯Ό κΈ°μ€μΌλ‘ νλ€.
| μ§ν | κ° |
|---|---|
| ν΅ν© μΈμ μ 체 μΈμ μ νλ | 93.5% |
| κ²μ λμΌ κ°μ€ κΈ°ννκ· | 86.6% |
νλ³Έ: 4μΈ νλ μ΄ 10ν. μνΈ μ΄ 800ν μ£Όμ¬μ κ΅΄λ¦Ό, νλ°€ μ΄ 40ν μν λ±λ‘ μΈμμΌλ‘ μ°μΆ.
| νλͺ© | νκ· | νμ€νΈμ°¨ | νλ³Έ |
|---|---|---|---|
| μ£Όμ¬μ κ΅΄λ¦Ό μΈμ | μ½ 1.14μ΄ | 121 ms | n = 30 |
| μ’μ/μν λ±λ‘ μΈμ | 208.5 ms | 21 ms | n = 30 |
| νλ°€ μν μΉ΄λ μΈμ | 430.7 ms | 63.6 ms | n = 30 |
| μμ€ν μ 체 | 0.47μ΄ (κΈ°ννκ· ) | β | β |
| μ§ν | κ° |
|---|---|
| λΉμ μ²λ¦¬ μλ | νκ· 25.1 fps (λͺ©ν 30), νλ μ λλλ₯ 16.4% |
| RAM μ¬μ©λ | νκ· 1,061 MB Β· μ΅λ 1,066 MB (νμ€νΈμ°¨ Β±21 MB, λμ μμ) |
| κ²μ μμ£Όμ¨ | 100% (μ΄μμ κ°μ μμ΄ μμ£Ό) |
| TTS μΊμ μ μ€λ₯ | 64.6% (κ³ μ λ©νΈ 100% Β· λμ λ©νΈ 54.5%) |
μΈ‘μ νκ²½ β Apple M4 Pro (12-core) Β· RAM 48 GB Β· macOS Β· Python 3.13. RAMμ 26λΆ λ΄λ΄ νννκ² μ μ§λμ΄ μ₯μκ° κ΅¬λμλ λμκ° μμμ νμΈνμλ€.
[μ€λ²ν€λ μΉ΄λ©λΌ]
β λ¨μΌ μΉ΄λ©λΌ β μ¬λ¬ μΈμκΈ°λ‘ νλ μ λΆλ°° (drop-oldest)
βββββββββββββΌβββββββββββββββββ¬ββββββββββββββββββ
βΌ βΌ βΌ (κ°κ° λ³λ μ€λ λ, νμ± 1κ°λ§ μ°μ°)
λ‘λΉ μνΈ λλμΈκ° β λΉμ νμ΄νλΌμΈ
(μ/μ μ€μ²) (μ£Όμ¬μ/νΈλ μ΄) (μΉ΄λ/μ/ν¬ν)
βββββββββββββ΄βββββ GameEvent β΄ββββββββββββ
βΌ
Bridge (λΉμ β κ·μΉ ν΅μ κ³μΈ΅)
β² FusionContext β GameEvent
βββββββββββββββββ βΌ
λ‘λΉ μ€μΌμ€νΈλ μ΄ν° κ²μλ³ Runner β Session β FSM (κ·μΉ μμ§)
(νλ μ΄μ΄ Β· μ’μ λ±λ‘) β
λ©ν°μμ΄μ νΈ (μ¬ν Β· ν
ν¬ Β· μ§ν Β· μ λ΅)
β
μ€λμ€ λ§€λμ (TTS Β· ν¨κ³Όμ Β· BGM ν)
β
WebSocket: /ws/tablet Β· /ws/yacht Β· /ws/werewolf
βΌ
[νλΈλ¦Ώ β React UI]
- λ¨μΌ νλ‘μΈμ€μμ FastAPI μλ²μ λΉμ νμ΄νλΌμΈμ΄ ν¨κ» λμνλ©° μΈνλ‘μΈμ€λ‘ μ§μ ν΅μ νλ€.
- ν΅μ μ λ΄λΆ(Bridge:
GameEvent/FusionContext)μ μΈλΆ(WebSocket: νλ©΄ Β· μμ± Β· μ λ ₯) λ νλ©΄μΌλ‘ λλλ€. - λͺ¨λ μν λ³νμ λ²μ λ²νΈ(
state_version)λ₯Ό λΆμ¬ν΄ νλ©΄ μΌκ΄μ±κ³Ό μ±λ₯ μΈ‘μ μ κΈ°μ€μ μΌλ‘ νμ©νλ€.
| μμ | μ€ν |
|---|---|
| μΈμ΄ / λ°νμ | Python 3.11+ Β· asyncio |
| 물체 μΈμ | YOLO26s (Ultralytics) 컀μ€ν νμ΅ Β· μΆλ‘ ν΄μλ 640 |
| μ μΈμ | MediaPipe HandLandmarker (Tasks API, mediapipe 0.10+) Β· μ΅λ 8μ |
| μμμ²λ¦¬ | OpenCV (HoughCircles Β· CLAHE Β· SimpleBlobDetector) Β· NumPy |
| μΆμ | ByteTrack(μ체 κ²½λ ꡬν) + Hungarian λ§€μΉ(lap/lapjv) |
| λ°±μλ | FastAPI Β· uvicorn Β· websockets |
| κ²μ λ‘μ§ | μμ Python FSM (μΈλΆ μμ‘΄μ± μμ, StrEnum μνλ¨Έμ ) |
| μμ΄μ νΈ | μ°μ μμ μ€μ¬ + OpenAI gpt-5.4-mini(μ λ΅) Β· κ·μΉ κΈ°λ° ν΄λ°± |
| μ€λμ€ | Google Cloud TTS (ko-KR Neural2) Β· 3-κ³μΈ΅ λμ€ν¬ μΊμ Β· μ°μ μμ ν |
| νλ‘ νΈμλ | React 18.3 Β· Vite 5.4 Β· zustand 4.5 Β· WebSocket |
| νμ§ κ΄λ¦¬ | pytest Β· ruff Β· black Β· mypy(strict) Β· GitHub Actions CI |
μΈμ λͺ¨λΈ β μνΈ YOLO 4μ’
(trayΒ·tray_innerΒ·roll_trayΒ·dice, yacht_v4.pt) Β·
λλ YOLO 13μ’
(μν μΉ΄λ 12μ’
+ Card_Back, werewolf_v8.pt) Β· μ λλλ§ν¬ 21 keypoints(hand_landmarker.task).
# 1) μ€μΉ
cd boardgame-ai
pip install -e ".[dev]"
pytest tests/test_contracts.py -v # λμ νμΈ
# 2) λ°±μλ (λΉμ νμ΄νλΌμΈμ μμ μ μλ μ€ν)
uvicorn backend.server:app --host 127.0.0.1 --port 8000
# 3) νλ‘ νΈμλ (Vite κ°λ° μλ²)
cd frontend && npm install && npm run dev- YOLO κ°μ€μΉ(
weights/*.pt)λ μ μ₯μμ ν¬ν¨λμ§ μμΌλ―λ‘ Google Driveμμ λ°μweights/μ λλ€(μμΌλ©΄ ν΄λΉ μΈμλ§ λΉνμ±). - μμ±μ μ¬μ©νλ €λ©΄
.envμGOOGLE_APPLICATION_CREDENTIALS(Google Cloud TTS μλΉμ€ κ³μ ν€ κ²½λ‘)λ₯Ό μ€μ νλ€. - μΉ΄λ©λΌ μΈμ κ³Όμ μ λ¨λ
μκ°ννλ μμ° μ€ν¬λ¦½νΈλ
boardgame-ai/demos/μ°Έκ³ .
boardgame-ai/
βββ core/ 곡μ νμ
Β· μμ (μμ Python β μΈλΆ λΌμ΄λΈλ¬λ¦¬ Β· κ²μ μ’
μ κΈμ§)
βββ bridge/ λΉμ β κ·μΉ ν΅μ (LocalBridge / WebSocketBridge)
βββ vision/ λΉμ νμ΄νλΌμΈ (detectors Β· tracking Β· attribution Β· fusion Β· κ²μλ³ pipeline)
βββ games/ κ²μ κ·μΉ FSM (yacht Β· werewolf)
βββ agents/ λ©ν°μμ΄μ νΈ (rules Β· tempo Β· progress Β· strategy)
βββ audio/ Google TTS Β· 3-κ³μΈ΅ μΊμ Β· μ°μ μμ ν
βββ backend/ FastAPI μλ² Β· κ²μλ³ runner/session Β· WebSocket
βββ frontend/ React νλΈλ¦Ώ UI (Vite)
βββ benchmarks/ μ±λ₯ μΈ‘μ (μ νλ Β· μλ΅μκ° Β· FPS Β· μμ)
βββ demos/ λΉμ μκ°ν μμ° μ€ν¬λ¦½νΈ
βββ weights/ YOLO κ°μ€μΉ (git μ μΈ, Drive 곡μ )
βββ tests/ κ³μ½ Β· FSM Β· μ΅ν© Β· μΆμ ν
μ€νΈ
βββ docs/ μ€κ³ λ¬Έμ
| μ΄λ¦ | λ΄λΉ |
|---|---|
| μμΉκ²½ (νμ₯) | νλ°€μ λλμΈκ° λΉμ Β· λ©ν°μμ΄μ νΈ Β· νλ‘μ νΈ μ΄κ΄ |
| κΉμ±λ―Ό | μνΈλ€μ΄μ€ λΉμ Β· νλ μ΄μ΄ λ±λ‘ λ° λ§€μΉ Β· λ‘λΉ UI Β· μ€λμ€/TTS Β· μ±λ₯ μΈ‘μ |
| κ°λ³μ§ | μνΈλ€μ΄μ€ FSM Β· μνΈλ€μ΄μ€ UI Β· κ³΅ν΅ νμ (core) |
| μ νμΉ | νλ°€μ λλμΈκ° FSM Β· νλ°€μ λλμΈκ° UI Β· λΉμ βFSM λΈλ¦Ώμ§/λ°±μλ |
- μ€κ³ β FSM μ€κ³ Β· WebSocket λͺ μΈ Β· λ°μ΄ν° νλ¦ λͺ μΈ
- μ κ²μ μΆκ° κ°μ΄λ β κ°λ λΆν° λ¨κ³λ³ μλ΄
- μΈν°νμ΄μ€ κ³μ½ Β· μ€λμ€ λͺ μΈ Β· ν μν¬νλ‘μ°



