Files
liars-bar-game/scripts/smoke_test_python.py
T

96 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Python 引擎冒煙測試(不連網、不呼叫真實 LLM)。
以「模擬 LLM」取代 API 呼叫,跑完整場騙子酒館遊戲,驗證
game.py / player.py / game_record.py 主流程可正常完成並產生記錄。
使用方式:
.venv\\Scripts\\python.exe scripts\\smoke_test_python.py
(若主控台遇到簡體中文編碼錯誤,請先設定 $env:PYTHONIOENCODING="utf-8"
"""
import os
import sys
import random
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, REPO_ROOT)
from game import Game
class MockChat:
"""附著在某位玩家身上的假 LLM:依提示內容回傳格式正確的 JSON。
注意:chat() 統一回傳 (content, reasoning_content) 二元素 tuple。
"""
def __init__(self, player):
self.player = player
self.decision_count = 0
def chat(self, messages, model=None):
prompt = messages[0]["content"] if messages else ""
if "played_cards" in prompt:
return self._play_reply(), ""
if "was_challenged" in prompt:
return self._challenge_reply(), ""
return "mock opinion: \u8a72\u73a9\u5bb6\u76ee\u524d\u7121\u660e\u986f\u50be\u5411\u3002", ""
def _play_reply(self):
"""\u7d66\u4e86\u81ea\u5df1\u7684\u624b\u724c\uff1a\u540c\u9ede\u6578 >=2 \u51fa\u6700\u591a 3 \u5f35\uff0c\u5426\u5247\u51fa 1 \u5f35\u3002"""
hand = sorted(self.player.hand)
cards = [hand[0]]
for c in hand[1:3]:
if c == cards[0]:
cards.append(c)
cards_json = ",".join('"%s"' % c for c in cards)
return ('{"played_cards": [%s], "behavior": "\u7a69\u5065", '
'"play_reason": "mock heuristic"}' % cards_json)
def _challenge_reply(self):
"""\u6bcf 4 \u6b21\u8cea\u7591\u6c7a\u7b56\u5c31\u8cea\u7591\u4e00\u6b21\uff0c\u8986\u84cb\u6210\u529f/\u5931\u6557\u5169\u689d\u8def\u5f91\u3002"""
self.decision_count += 1
do_challenge = (self.decision_count % 4 == 0)
return ('{"was_challenged": %s, "challenge_reason": "mock trigger"}' %
("true" if do_challenge else "false"))
def main():
random.seed(20260803)
player_configs = [
{"name": "DeepSeek", "model": "mock"},
{"name": "GPT", "model": "mock"},
{"name": "Claude", "model": "mock"},
{"name": "Gemini", "model": "mock"},
]
game = Game(player_configs)
for p in game.players:
p.llm_client = MockChat(p)
max_plays = 400
for step in range(max_plays):
if game.game_over:
break
game.play_round()
if game.game_over:
print("[OK] \u904a\u6232\u7d50\u675f\uff0c\u4e3b\u6d41\u7a0b\u53ef\u6b63\u5e38\u5b8c\u6210\u3002")
else:
print(f"[FAIL] \u8dd1\u4e86 {max_plays} \u6b65\u4ecd\u672a\u7d50\u675f\uff08\u53ef\u80fd\u89c4\u5247\u6709\u6b7b\u7d50\uff09\u3002 rounds={game.round_count}")
return 1
rec = game.game_record
rounds = len(rec.rounds)
alive = [p.name for p in game.players if p.alive]
print(f"[OK] \u7372\u52dd\u8005={rec.winner} | \u5b58\u6d3b\u73a9\u5bb6={alive}")
print(f"[OK] \u8a18\u9304\u56de\u5408\u6578={rounds}")
import glob
files = glob.glob(os.path.join(REPO_ROOT, "game_records", "*.json"))
print(f"[OK] game_records \u7522\u51fa {len(files)} \u500b JSON \u8a18\u9304\u6a94")
if files:
newest = max(files, key=os.path.getmtime)
print(f" \u6700\u65b0\u8a18\u9304: {os.path.basename(newest)}")
return 0
if __name__ == "__main__":
sys.exit(main())