ProLogicToe es una implementación del juego Tic Tac Toe, diseñada para demostrar la viabilidad del algoritmo Minimax de IA en la solución de juegos 1 vs 1

Este sistema se basa en la Teoría de Juegos para entornos de información perfecta y suma cero.
El algoritmo Minimax opera bajo la premisa de que ambos jugadores actuarán de manera óptima:
- Maximizador (IA): Busca el nodo hoja con el valor más alto (+1).
- Minimizador (Oponente): Busca el nodo hoja con el valor más bajo (-1).
El algoritmo atraviesa el árbol de decisiones de forma recursiva. Para optimizar integramos Poda Alfa-Beta. Para descartar ramas del árbol que no pueden influir en la decisión final, reduciendo el espacio de búsqueda sin comprometer la exactitud de la solución.
PySwip como puente de comunicación entre Python y Prolog
En lugar de iterar sobre matrices, definimos las condiciones de victoria como hechos lógicos dentro de rules.pl.
% Hechos que definen las 8 combinaciones ganadoras (índices de la lista).
linea_ganadora(1, 2, 3). % Horizontal 1
linea_ganadora(4, 5, 6). % Horizontal 2
linea_ganadora(7, 8, 9). % Horizontal 3
linea_ganadora(1, 4, 7). % Vertical 1
linea_ganadora(2, 5, 8). % Vertical 2
linea_ganadora(3, 6, 9). % Vertical 3
linea_ganadora(1, 5, 9). % Diagonal 1
linea_ganadora(3, 5, 7). % Diagonal 2
% ----------------------------------------------------------------------
% 2. PREDICADO DE VICTORIA (ganador/2)
% ----------------------------------------------------------------------
% ganador(Tablero, Jugador)
% Es verdadero si el Jugador ('x' o 'o') ha ganado en el Tablero dado.
% Regla: Un jugador gana si ocupa las tres posiciones de cualquier linea_ganadora.
ganador(Tablero, Jugador) :-
linea_ganadora(P1, P2, P3), % Encuentra una línea ganadora
nth1(P1, Tablero, Jugador), % Verifica que la casilla P1 es del Jugador
nth1(P2, Tablero, Jugador), % Verifica que la casilla P2 es del Jugador
nth1(P3, Tablero, Jugador). % Verifica que la casilla P3 es del JugadorEl backend delega la validación de estados a Prolog, permitiendo que Python se concentre en la estrategia de búsqueda en minimax.py.
def minimax(board_list, is_maximizing_turn, alpha, beta, depth):
"""
Núcleo del algoritmo Minimax con poda Alfa-Beta y logs de profundidad.
"""
# Prefijo para logs (usa espacios normales)
log_prefix = " " * depth
# print(f"{log_prefix}minimax(depth={depth}, maximizing={is_maximizing_turn})")
board_str = _board_to_prolog_list(board_list)
if bool(list(prolog.query(f"estado_terminal({board_str})"))):
score = evaluate_state(board_list)
# print(f"{log_prefix}--> Caso Base. Score = {score}")
return score
if is_maximizing_turn:
# Turno de MAX (IA)
best_score = -float('inf')
player = IA_PLAYER
query = f"movimientos_posibles({board_str}, {player}, ListaMovimientos)"
try:
possible_moves_bindings = list(prolog.query(query))
if possible_moves_bindings:
next_boards = possible_moves_bindings[0]['ListaMovimientos']
next_boards = [[str(atom) for atom in board] for board in next_boards]
else:
next_boards = []
except Exception as e:
print(f"Error en consulta Prolog (MAX): {e}")
next_boards = []
for next_board in next_boards:
score = minimax(next_board, False, alpha, beta, depth + 1)
best_score = max(score, best_score)
alpha = max(alpha, best_score)
if beta <= alpha:
# print(f"{log_prefix}--> Poda (MAX)")
break # Poda
# print(f"{log_prefix}--> Turno MAX retorna: {best_score}")
return best_score
else:
# Turno de MIN (Humano)
best_score = float('inf')
player = HUMAN_PLAYER
query = f"movimientos_posibles({board_str}, {player}, ListaMovimientos)"
try:
possible_moves_bindings = list(prolog.query(query))
if possible_moves_bindings:
next_boards = possible_moves_bindings[0]['ListaMovimientos']
next_boards = [[str(atom) for atom in board] for board in next_boards]
else:
next_boards = []
except Exception as e:
print(f"Error en consulta Prolog (MIN): {e}")
next_boards = []
for next_board in next_boards:
score = minimax(next_board, True, alpha, beta, depth + 1)
best_score = min(score, best_score)
beta = min(beta, best_score)
if beta <= alpha:
# print(f"{log_prefix}--> Poda (MIN)")
break # Poda
# print(f"{log_prefix}--> Turno MIN retorna: {best_score}")
return best_scoreOpción A: Docker
Requisitos previos Docker: https://www.docker.com/
recomendamos usar Docker:
git clone https://github.com/stillfreecode/ProLogicToe.git
cd ProLogicToedocker-compose up --build3. Acceder a la aplicación: Navegar a http://localhost:4321.
Opción B: Ejecución Local
Requisitos previos: Python 3.10+, Node.js, y SWI-Prolog instalado en el sistema y agregado al PATH.
cd backend/python_api
python -m venv venv
# Activar entorno virtual (Windows: venv\Scripts\activate | Unix: source venv/bin/activate)
pip install -r requirements.txt
python main.pycd frontend
npm install
npm run devLicencia: MIT
Desarrollado por: stillfreecode
Copyright (c) 2025 Rodolfo Angel Cordoba Villegas
