- server.py: zero-dependency stdlib backend (HTTP + WebSocket /ws), 大话骰 rule engine, server-driven bots - live.html: real MVP frontend wired to the backend over WebSocket - index.html/app.js/style.css: older static prototype - deploy/: systemd unit + Nginx reverse proxy + Let's Encrypt setup.sh - test_*.py: standalone HTTP / in-process test scripts Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
54 lines
2.6 KiB
Python
54 lines
2.6 KiB
Python
import json, urllib.request
|
||
base='http://127.0.0.1:8765'
|
||
def post(path, data):
|
||
req=urllib.request.Request(base+path, data=json.dumps(data).encode(), headers={'Content-Type':'application/json'})
|
||
try:
|
||
return json.loads(urllib.request.urlopen(req, timeout=5).read())
|
||
except Exception as e:
|
||
body=e.read().decode() if hasattr(e,'read') else str(e)
|
||
return json.loads(body) if body.startswith('{') else {'ok':False,'error':body}
|
||
def get_room(code):
|
||
return json.loads(urllib.request.urlopen(base+'/api/room?code='+code).read())['room']
|
||
|
||
def actor_id(p):
|
||
if p['type'] in ('open2','split2'):
|
||
idx=p.get('currentIndex',0); targets=p.get('targets',[])
|
||
return targets[idx]['playerId'] if (p['stage']=='wait_target' and idx<len(targets)) else p['initiatorId']
|
||
return p['targetId'] if p['stage'] in ('wait_caller_counter','wait_caller_accept') else p['initiatorId']
|
||
|
||
# 房主(真人) + 2 机器人
|
||
r=post('/api/create', {'game':'dice','name':'小鱼','playerId':'p-host'})
|
||
code=r['room']['code']
|
||
post('/api/add-bot', {'code':code,'playerId':'p-host'})
|
||
post('/api/add-bot', {'code':code,'playerId':'p-host'})
|
||
post('/api/start', {'code':code})
|
||
|
||
# 房主先叫 3 个 1,再让两个机器人各叫一手
|
||
post('/api/call', {'code':code,'playerId':'p-host','count':3,'point':1})
|
||
post('/api/bot-turn', {'code':code,'playerId':'p-host'}) # bot1 叫
|
||
post('/api/bot-turn', {'code':code,'playerId':'p-host'}) # bot2 叫
|
||
rm=get_room(code)
|
||
print('before open2: turn=', rm['turnPlayerName'], 'calls=', len([1 for h in rm['history'] if h['type']=='call']))
|
||
|
||
# 房主发起开两家
|
||
op=post('/api/multi-open2', {'code':code,'playerId':'p-host'})
|
||
assert op['ok'], '发起开两家失败: '+str(op.get('error'))
|
||
print('open2 start: type=', op['room']['pendingAction']['type'])
|
||
|
||
# 模拟前端 maybeBotTurn:应战者是机器人就触发 bot-turn;轮到真人则代答
|
||
room=op['room']
|
||
for _ in range(10):
|
||
p=room.get('pendingAction')
|
||
if not p: break
|
||
actor=next((x for x in room['players'] if x['id']==actor_id(p)), None)
|
||
if actor and actor.get('bot'):
|
||
room=post('/api/bot-turn', {'code':code,'playerId':'p-host'})['room']
|
||
else:
|
||
resp='accept' if p['stage']=='wait_initiator' else 'no_counter'
|
||
room=post('/api/respond-multi', {'code':code,'playerId':'p-host','response':resp})['room']
|
||
|
||
print('after responses: status=', room['status'])
|
||
print('result:', room.get('lastResult',{}).get('text'))
|
||
assert room['status']=='result', '开两家未结算——机器人未自动应战'
|
||
print('PASS: 机器人在开两家中自动应战并完成结算')
|