201 lines
6.6 KiB
Python
201 lines
6.6 KiB
Python
"""
|
|
斗地主直接API测试 - 三方对战
|
|
人类 + 规则AI + DeepSeek AI
|
|
"""
|
|
import asyncio
|
|
import sys
|
|
import os
|
|
import time
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
from engine import RoomManager, HumanPlayer, AIPlayer
|
|
from doudizhu import DoudizhuGame
|
|
from doudizhu.ai_adapters import DoudizhuRuleAI, DoudizhuDeepSeekAI
|
|
from config import DEEPSEEK_API_KEY
|
|
|
|
print("=" * 70)
|
|
print(" 🎮 斗地主直接API测试")
|
|
print("=" * 70)
|
|
print("\n👥 三方对战:")
|
|
print(" 1️⃣ 人类玩家 (API模拟)")
|
|
print(" 2️⃣ 规则AI (本地算法)")
|
|
print(" 3️⃣ DeepSeek AI (大模型API)" if DEEPSEEK_API_KEY else " 3️⃣ DeepSeek AI (回退到规则AI - 未配置API)")
|
|
|
|
# 重置RoomManager
|
|
RoomManager._instance = None
|
|
RoomManager._initialized = False
|
|
manager = RoomManager()
|
|
manager.register_game('doudizhu', DoudizhuGame)
|
|
|
|
# 创建房间
|
|
print("\n📋 创建房间...")
|
|
room = manager.create_room('doudizhu', 3, {})
|
|
print(f" 房间号: {room.code}")
|
|
|
|
# 添加玩家
|
|
human = HumanPlayer("人类玩家")
|
|
room.add_player(human)
|
|
|
|
ai1 = AIPlayer("规则AI", "rule")
|
|
ai1.ai_type = "rule"
|
|
room.add_player(ai1)
|
|
|
|
ai2 = AIPlayer("DeepSeekAI", "deepseek")
|
|
ai2.ai_type = "deepseek"
|
|
room.add_player(ai2)
|
|
|
|
print(f"\n 玩家列表:")
|
|
for pid, p in room.players.items():
|
|
ai_tag = "🤖" if p.is_ai else "👤"
|
|
ai_type = getattr(p, 'ai_type', 'human')
|
|
print(f" {ai_tag} {p.name} ({ai_type})")
|
|
|
|
# 创建AI实例
|
|
ai_instances = {
|
|
ai1.id: DoudizhuRuleAI(),
|
|
}
|
|
|
|
if DEEPSEEK_API_KEY:
|
|
ai_instances[ai2.id] = DoudizhuDeepSeekAI(api_key=DEEPSEEK_API_KEY)
|
|
else:
|
|
ai_instances[ai2.id] = DoudizhuRuleAI()
|
|
|
|
async def run_ai_turn(game, player_id):
|
|
"""运行AI回合"""
|
|
player = game.players[player_id]
|
|
ai = ai_instances.get(player_id)
|
|
|
|
if not ai:
|
|
return None
|
|
|
|
# 准备上下文
|
|
cards = game.player_cards.get(player_id, [])
|
|
is_lord = game.lord_id == player_id
|
|
|
|
# 计算队友手牌数
|
|
teammate_cards = 17
|
|
if not is_lord and game.lord_id:
|
|
for pid in game.players:
|
|
if pid != player_id and pid != game.lord_id:
|
|
teammate_cards = len(game.player_cards.get(pid, []))
|
|
break
|
|
|
|
player_context = {
|
|
'cards': [c.to_dict() for c in cards],
|
|
'is_lord': is_lord,
|
|
'teammate_cards': teammate_cards
|
|
}
|
|
|
|
game_state = game.to_dict()
|
|
available_actions = game.get_valid_actions(player_id)
|
|
|
|
# AI决策
|
|
try:
|
|
decision = await ai.make_decision(game_state, available_actions, player_context)
|
|
return decision
|
|
except Exception as e:
|
|
print(f" ❌ AI错误: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return {'action': 'pass', 'data': {}}
|
|
|
|
# 开始游戏
|
|
print(f"\n🚀 开始游戏")
|
|
manager.start_game(room.id)
|
|
game = room.game
|
|
|
|
print(f"\n🎲 游戏进行中...")
|
|
print("-" * 70)
|
|
|
|
turn_count = 0
|
|
max_turns = 50
|
|
|
|
while turn_count < max_turns:
|
|
current_player_id = game.state.current_turn_player_id
|
|
current_player = game.players[current_player_id]
|
|
|
|
# 检查是否是AI
|
|
if current_player.is_ai:
|
|
# 运行AI
|
|
decision = asyncio.run(run_ai_turn(game, current_player_id))
|
|
|
|
if decision:
|
|
action = decision['action']
|
|
action_data = decision.get('data', {})
|
|
|
|
result = game.handle_action(current_player_id, action, action_data)
|
|
|
|
turn_count += 1
|
|
ai_name = current_player.name[:10]
|
|
|
|
if result.get('success'):
|
|
if action == 'play':
|
|
card_type = result.get('card_type', {})
|
|
print(f"{turn_count:2d}. [{ai_name:10}] 出牌: {card_type.get('name', 'Unknown'):12} "
|
|
f"剩余: {result.get('remaining_cards', 0):2d}张")
|
|
elif action == 'call':
|
|
want = action_data.get('want', False)
|
|
if result.get('lord_id'):
|
|
lord_name = game.players[result['lord_id']].name
|
|
print(f"{turn_count:2d}. [{ai_name:10}] 🎩 叫地主! 地主: {lord_name}")
|
|
else:
|
|
print(f"{turn_count:2d}. [{ai_name:10}] 叫地主: {'是' if want else '否'}")
|
|
elif action == 'pass':
|
|
print(f"{turn_count:2d}. [{ai_name:10}] 不出")
|
|
else:
|
|
print(f"{turn_count:2d}. [{ai_name:10}] ❌ 失败: {result.get('message', 'Unknown')}")
|
|
print(f" 可用动作: {game.get_valid_actions(current_player_id)}")
|
|
print(f" 决策: {decision}")
|
|
else:
|
|
# 人类玩家回合 - 简单策略
|
|
cards = game.player_cards.get(current_player_id, [])
|
|
|
|
if game.doudizhu_phase.value == 'calling':
|
|
# 叫地主
|
|
result = game.handle_action(current_player_id, 'call', {'want': True})
|
|
turn_count += 1
|
|
if result.get('lord_id'):
|
|
print(f"{turn_count:2d}. [人类玩家 ] 🎩 叫地主! 成为地主: {game.players[result['lord_id']].name}")
|
|
else:
|
|
# 出牌阶段 - 简化:出最小单张
|
|
if cards:
|
|
result = game.handle_action(current_player_id, 'play', {'card_ids': [cards[0].id]})
|
|
turn_count += 1
|
|
if result.get('success'):
|
|
card_type = result.get('card_type', {})
|
|
print(f"{turn_count:2d}. [人类玩家 ] 出牌: {card_type.get('name', 'Unknown'):12} "
|
|
f"剩余: {result.get('remaining_cards', 0):2d}张")
|
|
else:
|
|
# 如果无法出牌,尝试pass
|
|
result = game.handle_action(current_player_id, 'pass', {})
|
|
if result.get('success'):
|
|
print(f"{turn_count:2d}. [人类玩家 ] 不出")
|
|
|
|
# 检查游戏结束
|
|
winner = game.check_winner()
|
|
if winner:
|
|
winner_name = game.players[winner].name
|
|
print(f"\n{'=' * 70}")
|
|
print(f"🏆 游戏结束! 获胜者: {winner_name}")
|
|
print(f"📊 总回合数: {turn_count}")
|
|
print(f"{'=' * 70}")
|
|
break
|
|
|
|
# 小延迟
|
|
time.sleep(0.1)
|
|
|
|
else:
|
|
print(f"\n{'=' * 70}")
|
|
print(f"⏱️ 达到最大回合数 ({max_turns})")
|
|
print(f"{'=' * 70}")
|
|
|
|
# 最终状态
|
|
print(f"\n📋 最终状态:")
|
|
for pid, p in game.players.items():
|
|
cards = game.player_cards.get(pid, [])
|
|
is_lord = "🎩" if game.lord_id == pid else " "
|
|
print(f" {is_lord} {p.name:12}: {len(cards):2d}张牌剩余")
|
|
|
|
print(f"\n✅ 三方对战测试完成!")
|