178 lines
7.2 KiB
Python
178 lines
7.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
斗地主 Headless 浏览器测试 - 最终版
|
|
简化流程,专注验证AI对战功能
|
|
"""
|
|
import asyncio
|
|
import sys
|
|
import os
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
from playwright.async_api import async_playwright
|
|
|
|
SERVER_URL = "http://129.211.173.87:8900"
|
|
|
|
async def run_test():
|
|
print("=" * 70)
|
|
print(" 🎮 斗地主 Headless 测试 - 三方对战")
|
|
print("=" * 70)
|
|
|
|
async with async_playwright() as p:
|
|
browser = await p.chromium.launch(headless=True)
|
|
page = await browser.new_page(viewport={'width': 1280, 'height': 900})
|
|
|
|
try:
|
|
# 访问并连接
|
|
await page.goto(f"{SERVER_URL}/test_client.html")
|
|
await asyncio.sleep(1)
|
|
|
|
print("\n📡 连接服务器...")
|
|
await page.fill('input[placeholder*="服务器地址"]', SERVER_URL)
|
|
|
|
# 设置监听
|
|
await page.evaluate("""
|
|
window.testLog = [];
|
|
window.currentGame = null;
|
|
window.myPlayerId = null;
|
|
|
|
const waitSocket = setInterval(() => {
|
|
if (typeof socket !== 'undefined') {
|
|
clearInterval(waitSocket);
|
|
|
|
socket.on('connect', () => {
|
|
window.myPlayerId = socket.id;
|
|
});
|
|
|
|
socket.on('room_created', (data) => {
|
|
window.testLog.push('ROOM:' + data.room.code);
|
|
window.roomData = data.room;
|
|
});
|
|
|
|
socket.on('game_started', (data) => {
|
|
window.testLog.push('GAME_STARTED');
|
|
window.currentGame = data.room.game;
|
|
});
|
|
|
|
socket.on('state_update', (data) => {
|
|
const action = data.action;
|
|
const pid = data.player_id ? data.player_id.slice(0,8) : 'N/A';
|
|
const name = data.game_state?.players?.[data.player_id]?.name || pid;
|
|
window.testLog.push(`ACTION:${name}:${action}`);
|
|
window.currentGame = data.game_state;
|
|
});
|
|
|
|
socket.on('game_ended', (data) => {
|
|
window.testLog.push('ENDED:' + data.winner);
|
|
});
|
|
}
|
|
}, 100);
|
|
""")
|
|
|
|
await page.click('button:has-text("连接")')
|
|
await asyncio.sleep(1)
|
|
|
|
# 创建房间
|
|
await page.fill('input[placeholder*="玩家名称"]', 'Headless玩家')
|
|
await page.evaluate("""
|
|
socket.emit('create_room', {
|
|
game_type: 'doudizhu',
|
|
player_name: 'Headless玩家',
|
|
ai_config: {ai_count: 2, ai_types: ['rule', 'deepseek']}
|
|
});
|
|
""")
|
|
await asyncio.sleep(2)
|
|
|
|
# 获取房间信息
|
|
room_data = await page.evaluate("() => window.roomData")
|
|
my_id = await page.evaluate("() => window.myPlayerId")
|
|
|
|
if not room_data:
|
|
print("❌ 房间创建失败")
|
|
return
|
|
|
|
print(f"✅ 房间: {room_data.get('code')}")
|
|
players = room_data.get('players', [])
|
|
if isinstance(players, dict):
|
|
players = list(players.values())
|
|
for p in players:
|
|
icon = "🤖" if p.get('is_ai') else "👤"
|
|
pid = p.get('id', 'N/A')
|
|
print(f" {icon} {p.get('name')} ({pid[:8]})")
|
|
print(f" 我的ID: {my_id[:8] if my_id else 'N/A'}")
|
|
|
|
# 准备并开始
|
|
print("\n🚀 开始游戏...")
|
|
await page.click('button:has-text("准备")')
|
|
await asyncio.sleep(0.5)
|
|
await page.click('button:has-text("开始游戏")')
|
|
await asyncio.sleep(2)
|
|
|
|
print("\n🎲 游戏进行中...")
|
|
print("-" * 50)
|
|
|
|
turn_count = 0
|
|
game_ended = False
|
|
|
|
for i in range(100): # 100秒
|
|
# 获取日志
|
|
logs = await page.evaluate("() => { const l = window.testLog; window.testLog = []; return l; }")
|
|
|
|
for log in logs:
|
|
if log.startswith("ACTION:"):
|
|
parts = log.split(":")
|
|
if len(parts) >= 3:
|
|
turn_count += 1
|
|
print(f"{turn_count:2d}. {parts[1][:10]}: {parts[2]}")
|
|
elif log.startswith("ENDED:"):
|
|
print(f"\n🏆 游戏结束! 获胜者: {log[6:14]}")
|
|
game_ended = True
|
|
|
|
if game_ended:
|
|
break
|
|
|
|
# 检查当前回合并执行动作
|
|
game = await page.evaluate("() => window.currentGame")
|
|
if game:
|
|
current = game.get('current_turn_player_id') or game.get('current_turn')
|
|
doudizhu = game.get('doudizhu', {})
|
|
phase = doudizhu.get('phase', '')
|
|
|
|
if current == my_id:
|
|
if phase == 'calling':
|
|
print(" -> Headless叫地主")
|
|
await page.evaluate("socket.emit('game_action', {action:'call',data:{want:true}})")
|
|
await asyncio.sleep(1)
|
|
elif phase == 'playing':
|
|
# 简单策略:尝试出牌,失败就pass
|
|
print(" -> Headless出牌")
|
|
await page.evaluate("""
|
|
const cards = window.currentGame?.player_cards?.[socket.id] || [];
|
|
if (cards.length > 0) {
|
|
socket.emit('game_action', {action:'play',data:{card_ids:[cards[0].id]}});
|
|
} else {
|
|
socket.emit('game_action', {action:'pass',data:{}});
|
|
}
|
|
""")
|
|
await asyncio.sleep(1)
|
|
|
|
await asyncio.sleep(0.5)
|
|
|
|
if not game_ended:
|
|
print(f"\n⏱️ 超时 - 进行了 {turn_count} 步")
|
|
|
|
await page.screenshot(path='/tmp/doudizhu_final.png', full_page=True)
|
|
print(f"\n📸 截图: /tmp/doudizhu_final.png")
|
|
|
|
await browser.close()
|
|
print("\n✅ 测试完成!")
|
|
|
|
except Exception as e:
|
|
print(f"\n❌ 错误: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
await browser.close()
|
|
|
|
if __name__ == '__main__':
|
|
asyncio.run(run_test())
|