Files
nanocode/net-games/test_doudizhu_headless.py
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

239 lines
9.6 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.
"""
斗地主 Headless 浏览器测试
三方玩家:headless人类 + 规则AI + DeepSeek 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"
print("=" * 70)
print(" 🎮 斗地主 Headless 浏览器测试")
print("=" * 70)
print(f"\n🌐 服务器: {SERVER_URL}")
print("\n👥 三方对战:")
print(" 1️⃣ Headless人类 (浏览器自动化)")
print(" 2️⃣ 规则AI (本地Minimax算法)")
print(" 3️⃣ DeepSeek AI (大模型API)")
async def run_headless_test():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
context = await browser.new_context(viewport={'width': 1280, 'height': 800})
# 创建页面
page = await context.new_page()
try:
print("\n📡 连接到游戏服务器...")
await page.goto(f"http://129.211.173.87:8900/test_client.html", timeout=30000)
# 等待页面加载
await page.wait_for_selector('#serverUrl', timeout=10000)
# 设置服务器地址
await page.fill('#serverUrl', SERVER_URL)
await page.click('button:has-text("连接")')
# 等待连接成功
await page.wait_for_selector('#connectionStatus:has-text("已连接")', timeout=10000)
print("✅ 已连接到服务器")
# 设置玩家名称
await page.fill('#playerName', 'Headless玩家')
# 创建房间(带AI配置)
print("\n🏠 创建房间(含2个AI)...")
await page.evaluate("""
() => {
socket.emit('create_room', {
game_type: 'doudizhu',
player_name: 'Headless玩家',
config: { max_players: 3 },
ai_config: {
ai_count: 2,
ai_types: ['rule', 'deepseek']
}
});
}
""")
# 等待房间创建
await asyncio.sleep(2)
# 获取房间信息
room_info = await page.evaluate("""
() => {
return {
code: document.getElementById('roomCode')?.value || 'N/A',
players: currentRoom?.players?.map(p => ({
name: p.name,
is_ai: p.is_ai,
id: p.id?.substring(0, 8)
})) || []
};
}
""")
room_code = room_info.get('code', 'N/A')
players = room_info.get('players', [])
print(f"✅ 房间创建成功: {room_code}")
print(f"\n👥 房间玩家 ({len(players)}/3):")
for p in players:
ai_tag = "🤖" if p['is_ai'] else "👤"
print(f" {ai_tag} {p['name']} ({p['id']})")
if len(players) != 3:
print("❌ 玩家数量不正确,测试中止")
await browser.close()
return
# 准备
print("\n✅ 准备游戏...")
await page.click('button:has-text("准备")')
await asyncio.sleep(0.5)
# 开始游戏
print("🚀 开始游戏...")
await page.click('button:has-text("开始游戏")')
# 监听游戏事件
print("\n🎲 游戏进行中...")
print("-" * 70)
turn_count = 0
game_ended = False
# 设置事件监听
await page.evaluate("""
() => {
window.gameEvents = [];
socket.on('game_started', (data) => {
window.gameEvents.push({type: 'started', data});
});
socket.on('state_update', (data) => {
window.gameEvents.push({type: 'update', data, time: Date.now()});
});
socket.on('game_ended', (data) => {
window.gameEvents.push({type: 'ended', data});
});
}
""")
# 等待游戏开始
await asyncio.sleep(2)
# 游戏主循环(观察模式,让人类玩家偶尔操作)
for i in range(60): # 最多60秒
# 获取事件
events = await page.evaluate("() => { const e = window.gameEvents; window.gameEvents = []; return e; }")
for event in events:
if event['type'] == 'started':
print("🎮 游戏开始!")
elif event['type'] == 'update':
data = event['data']
turn_count += 1
action = data.get('action', 'unknown')
player_id = data.get('player_id', '')[:8]
result = data.get('result', {})
game_state = data.get('game_state', {})
doudizhu = game_state.get('doudizhu', {})
# 获取玩家名称
player_name = "Unknown"
for p in players:
if p['id'] == player_id:
player_name = p['name'][:10]
break
if result.get('success'):
if action == 'play':
card_type = result.get('card_type', {})
remaining = result.get('remaining_cards', 0)
print(f"{turn_count:2d}. [{player_name:10}] 出牌: {card_type.get('name', '?'):12} 剩余: {remaining:2d}张")
elif action == 'call':
want = result.get('data', {}).get('want', False)
if result.get('lord_id'):
lord_name = "?"
for p in players:
if p['id'][:8] in str(result.get('lord_id')):
lord_name = p['name']
print(f"{turn_count:2d}. [{player_name:10}] 🎩 叫地主! 地主: {lord_name}")
else:
print(f"{turn_count:2d}. [{player_name:10}] 叫地主: {'是' if want else '否'}")
elif action == 'pass':
print(f"{turn_count:2d}. [{player_name:10}] 不出")
# 检查是否是当前玩家回合
current_turn = doudizhu.get('current_turn', '')
my_id = players[0]['id'] if players else ''
if current_turn[:8] == my_id[:8]:
# 是人类玩家的回合,执行简单操作
phase = doudizhu.get('phase', '')
if 'calling' in phase:
# 叫地主
await asyncio.sleep(0.5)
await page.evaluate("""
() => {
socket.emit('game_action', {
action: 'call',
data: { want: true }
});
}
""")
print(f" -> Headless玩家叫地主")
elif event['type'] == 'ended':
print("\n" + "=" * 70)
winner = event['data'].get('winner', 'N/A')
print(f"🏆 游戏结束! 获胜者: {winner[:8]}")
game_ended = True
break
if game_ended:
break
await asyncio.sleep(1)
if not game_ended:
print("\n" + "=" * 70)
print(f"⏱️ 测试超时 (60秒)")
print(f"📊 共进行了 {turn_count} 步")
# 截图
screenshot_path = '/tmp/doudizhu_test_result.png'
await page.screenshot(path=screenshot_path, full_page=True)
print(f"\n📸 截图已保存: {screenshot_path}")
await browser.close()
print("\n" + "=" * 70)
print("✅ Headless测试完成!")
print("=" * 70)
except Exception as e:
print(f"\n❌ 测试出错: {e}")
import traceback
traceback.print_exc()
await browser.close()
raise
# 运行测试
if __name__ == '__main__':
asyncio.run(run_headless_test())