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

255 lines
11 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.
#!/usr/bin/env python3
"""
斗地主 Headless 浏览器测试 V3
使用Socket.IO事件监听获取状态
"""
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_headless_test():
"""运行 Headless 浏览器测试"""
print("=" * 70)
print(" 🎮 斗地主 Headless 浏览器测试 V3")
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.testState = {
room: null,
game: null,
myId: null,
myCards: [],
events: [],
connected: false
};
// 等待socket就绪
const waitForSocket = setInterval(() => {
if (typeof socket !== 'undefined') {
clearInterval(waitForSocket);
socket.on('connect', () => {
window.testState.connected = true;
window.testState.myId = socket.id;
});
socket.on('room_created', (data) => {
window.testState.room = data.room;
window.testState.events.push({type: 'room_created', data});
});
socket.on('room_updated', (data) => {
window.testState.room = data.room;
window.testState.events.push({type: 'room_updated', data});
});
socket.on('game_started', (data) => {
window.testState.game = data.room.game;
window.testState.events.push({type: 'game_started', data});
});
socket.on('state_update', (data) => {
window.testState.game = data.game_state;
if (data.game_state && data.game_state.player_cards) {
const myId = window.testState.myId;
if (myId && data.game_state.player_cards[myId]) {
window.testState.myCards = data.game_state.player_cards[myId];
}
}
window.testState.events.push({type: 'state_update', data});
});
socket.on('game_ended', (data) => {
window.testState.events.push({type: 'game_ended', data});
});
}
}, 100);
}
""")
await page.click('button:has-text("连接")')
await asyncio.sleep(1.5)
# 设置玩家名称并创建房间
await page.fill('input[placeholder*="玩家名称"]', 'Headless玩家')
print("🏠 创建房间(含2个AI)...")
await page.evaluate("""
() => {
socket.emit('create_room', {
game_type: 'doudizhu',
player_name: 'Headless玩家',
ai_config: {ai_count: 2, ai_types: ['rule', 'deepseek']}
});
}
""")
# 等待房间创建
for _ in range(10):
await asyncio.sleep(0.5)
room = await page.evaluate("() => window.testState.room")
if room and room.get('code'):
break
room = await page.evaluate("() => window.testState.room")
if not room:
print("❌ 房间创建失败")
await browser.close()
return
room_code = room.get('code', 'UNKNOWN')
players = room.get('players', {})
player_list = list(players.values()) if isinstance(players, dict) else players
print(f"✅ 房间创建成功: {room_code}")
print(f"\n👥 房间玩家 ({len(player_list)}/3):")
for p in player_list:
ai_tag = "🤖" if p.get('is_ai') else "👤"
print(f" {ai_tag} {p.get('name', 'Unknown')} ({p.get('id', 'N/A')[:8]})")
my_id = await page.evaluate("() => window.testState.myId")
print(f"\n 我的ID: {my_id[:8] if my_id else 'N/A'}")
# 准备并开始游戏
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
for i in range(120):
# 获取游戏状态
state = await page.evaluate("() => window.testState")
game = state.get('game', {})
events = state.get('events', [])
# 清空事件
if events:
await page.evaluate("() => { window.testState.events = []; }")
# 处理事件
for event in events:
if event.get('type') == 'state_update':
data = event.get('data', {})
action = data.get('action', 'unknown')
player_id = data.get('player_id', '')
result = data.get('result', {})
game_state = data.get('game_state', {})
doudizhu = game_state.get('doudizhu', {})
players_map = game_state.get('players', {})
player_info = players_map.get(player_id, {})
player_name = player_info.get('name', 'Unknown')[:10]
if result.get('success'):
turn_count += 1
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':
if result.get('lord_id'):
print(f"{turn_count:2d}. [{player_name:10}] 🎩 叫地主!")
else:
print(f"{turn_count:2d}. [{player_name:10}] 叫地主")
elif action == 'pass':
print(f"{turn_count:2d}. [{player_name:10}] 不出")
elif event.get('type') == 'game_ended':
winner = event.get('data', {}).get('winner', 'N/A')
print(f"\n🏆 游戏结束! 获胜者: {winner[:8] if winner else 'N/A'}")
game_ended = True
if game_ended:
break
# 检查当前回合并执行动作
current_turn = game.get('current_turn_player_id') or game.get('current_turn')
doudizhu = game.get('doudizhu', {})
phase = doudizhu.get('phase', '')
if current_turn == my_id and not game_ended:
my_cards = state.get('myCards', [])
if phase == 'calling':
print(f" -> Headless玩家叫地主")
await page.evaluate("""
() => socket.emit('game_action', {action: 'call', data: {want: true}})
""")
await asyncio.sleep(0.8)
elif phase == 'playing':
if my_cards:
card_id = my_cards[0].get('id')
print(f" -> Headless玩家出牌")
await page.evaluate(f"""
() => socket.emit('game_action', {{action: 'play', data: {{card_ids: ['{card_id}']}}}})
""")
else:
await page.evaluate("""
() => socket.emit('game_action', {action: 'pass', data: {}})
""")
await asyncio.sleep(0.8)
# 检查游戏结束
winner = game.get('winner_id')
if winner:
print(f"\n🏆 游戏结束! 获胜者: {winner[:8]}")
game_ended = True
break
await asyncio.sleep(0.3)
if not game_ended:
print("\n" + "=" * 70)
print(f"⏱️ 测试超时 (120秒)")
print(f"📊 共进行了 {turn_count} 步")
# 截图
screenshot_path = '/tmp/doudizhu_test_result_v3.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())