""" 斗地主 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())