-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathengine.py
More file actions
167 lines (142 loc) · 7.73 KB
/
Copy pathengine.py
File metadata and controls
167 lines (142 loc) · 7.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import time
import json
from typing import Tuple, List, Dict, Literal
import random
from models import TabuleiroDeXadrez, Jogada
from game import criar_tabuleiro_inicial
from llm_player import JogadorLLM
from reporting import gerar_relatorio_markdown, salvar_relatorio
class MotorJogo:
"""Classe que gerencia o fluxo do jogo de damas entre dois modelos LLM"""
def __init__(self, modelo_brancas: str, modelo_pretas: str, max_jogadas: int = 30):
self.modelo_brancas = modelo_brancas
self.modelo_pretas = modelo_pretas
self.max_jogadas = max_jogadas
# Inicializa o tabuleiro e jogadores
self.tabuleiro = criar_tabuleiro_inicial()
self.jogador_brancas = JogadorLLM(modelo_brancas, "branca")
self.jogador_pretas = JogadorLLM(modelo_pretas, "preta")
# Estado do jogo
self.turno_atual = "branca" # Começa com as brancas
self.contador_jogadas = 0
self.sem_capturas = 0 # Contador para detectar empate
self.historico_jogadas = []
self.resultado = ""
self.finalizado = False
def iniciar_jogo(self): # -> None (não retorna mais tudo, apenas inicializa)
"""
Prepara o jogo para começar, mas não executa o loop.
Usado principalmente para log inicial no console.
"""
print(f"=== NOVO JOGO PREPARADO: {self.modelo_brancas} (BRANCAS) VS {self.modelo_pretas} (PRETAS) ===\n")
print("Tabuleiro inicial:")
print(self.tabuleiro.criar_representacao_visual())
# Não executa o loop aqui, a web controlará as chamadas a _executar_jogada
def _executar_jogada(self) -> str | None:
"""Executa uma única jogada completa do jogador atual e retorna o raciocínio da IA."""
# Verifica se o jogo já terminou ou excedeu o limite
if self.finalizado:
print("Tentativa de jogar com jogo já finalizado.")
return None # Retorna None se o jogo acabou
if self.contador_jogadas >= self.max_jogadas:
if not self.finalizado:
print(f"\nLimite de {self.max_jogadas} jogadas atingido. Jogo encerrado em empate.")
self.resultado = f"Empate por limite de {self.max_jogadas} jogadas atingido."
self.finalizado = True
return None # Retorna None se o jogo acabou
self.contador_jogadas += 1
print(f"\n--- Executando Jogada {self.contador_jogadas} - Turno: {self.turno_atual.upper()} --- ({'Brancas' if self.turno_atual == 'branca' else 'Pretas'}: {self.modelo_brancas if self.turno_atual == 'branca' else self.modelo_pretas})")
# Determina o jogador atual
jogador_atual = self.jogador_brancas if self.turno_atual == "branca" else self.jogador_pretas
modelo_atual = self.modelo_brancas if self.turno_atual == "branca" else self.modelo_pretas
# Obtém movimentos válidos
movimentos_validos = self.tabuleiro.obter_movimentos_validos(self.turno_atual)
# Verifica se há movimentos válidos
if not movimentos_validos:
print(f"Jogador {self.turno_atual} não possui movimentos válidos. Fim de jogo!")
vencedor = "preta" if self.turno_atual == "branca" else "branca"
modelo_vencedor = self.modelo_pretas if vencedor == "preta" else self.modelo_brancas
print(f"Vencedor: {vencedor.upper()} ({modelo_vencedor})")
self.resultado = f"Vitória de {vencedor.upper()} ({modelo_vencedor}). Jogador {self.turno_atual} sem movimentos válidos."
self.finalizado = True
self._salvar_relatorio_final() # Salva relatório ao finalizar
return None # Retorna None se o jogo acabou
# Jogador escolhe um movimento
try:
movimento, resposta_llm, duracao = jogador_atual.escolher_movimento(
self.tabuleiro,
movimentos_validos,
self.contador_jogadas
)
# Descreve o movimento
de_linha, de_coluna = movimento["de"]
para_linha, para_coluna = movimento["para"]
tipo = "CAPTURA" if movimento["captura"] else "movimento simples"
print(f"Jogador {self.turno_atual} ({modelo_atual}) escolheu: ({de_linha},{de_coluna}) → ({para_linha},{para_coluna}) - {tipo}")
# Imprime os dados Pydantic do movimento (opcional no console, útil para debug)
# print("\nDados Pydantic do movimento escolhido:")
# print(json.dumps(movimento, indent=2))
# Realiza o movimento
self.tabuleiro = self.tabuleiro.realizar_movimento(movimento)
print("Tabuleiro após jogada:")
print(self.tabuleiro.criar_representacao_visual())
# Registra a jogada no histórico
jogada = Jogada(
numero=self.contador_jogadas,
cor=self.turno_atual,
modelo=modelo_atual,
de=movimento["de"],
para=movimento["para"],
captura=movimento["captura"],
captura_posicao=movimento.get("captura_posicao"),
tabuleiro_apos=self.tabuleiro.model_dump(),
resposta_llm=resposta_llm,
movimento_escolhido=movimento,
duracao=duracao
)
self.historico_jogadas.append(jogada)
# Atualiza contador de capturas para verificar empate
if movimento["captura"]:
self.sem_capturas = 0
else:
self.sem_capturas += 1
# Verifica empate por falta de capturas
if self.sem_capturas >= 40: # 20 jogadas = 40 turnos
print("Empate: 20 jogadas sem capturas.")
self.resultado = "Empate por 20 jogadas sem capturas."
self.finalizado = True
self._salvar_relatorio_final() # Salva relatório ao finalizar
return None # Retorna None se o jogo acabou
# Verifica se atingiu o limite de jogadas nesta jogada
if self.contador_jogadas >= self.max_jogadas:
print(f"\nLimite de {self.max_jogadas} jogadas atingido após esta jogada. Jogo encerrado em empate.")
self.resultado = f"Empate por limite de {self.max_jogadas} jogadas atingido."
self.finalizado = True
self._salvar_relatorio_final() # Salva relatório ao finalizar
return None # Retorna None se o jogo acabou
# Muda o turno apenas se o jogo não terminou
if not self.finalizado:
self.turno_atual = "preta" if self.turno_atual == "branca" else "branca"
else:
self._salvar_relatorio_final() # Salva o relatório se o jogo terminou aqui
return resposta_llm # Retorna o raciocínio bruto da IA
except Exception as e:
print(f"Erro durante a jogada {self.contador_jogadas}: {e}")
self.resultado = f"Jogo interrompido por erro na jogada {self.contador_jogadas}: {str(e)}"
self.finalizado = True
self._salvar_relatorio_final() # Salva relatório ao finalizar
return None # Retorna None em caso de erro
def _salvar_relatorio_final(self):
"""Gera e salva o relatório final do jogo."""
if not self.historico_jogadas: # Só salva se houve alguma jogada
print("Nenhuma jogada realizada, relatório não será salvo.")
return
print("\nGerando relatório final...")
relatorio = gerar_relatorio_markdown(
self.historico_jogadas,
self.modelo_brancas,
self.modelo_pretas,
self.resultado
)
caminho_relatorio = salvar_relatorio(relatorio)
print(f"Relatório final salvo em: {caminho_relatorio}")