Si estás aprendiendo a programar, la programación de juegos es una excelente manera de dominar algoritmos y estructuras de datos. En esta lección, vamos a programar un juego de tres en raya en Python. El código completo del programa con inteligencia artificial para el jugador-computadora ocupa solo 140 líneas. En la versión del juego donde una persona juega contra otra, es la mitad de líneas.
El juego de tres en raya es bueno porque sus reglas son conocidas por todos desde la infancia y son comprensibles para cualquiera. Esto te permitirá concentrarte en el proceso de programación, en lugar de en el análisis de las reglas del juego. En el proceso de trabajo en el juego de tres en raya, usaremos solo las funciones estándar del lenguaje Python sin conectar ninguna biblioteca externa.
Paso 1. Selección de la estructura de datos
La programación de cualquier juego comienza con la modelización de sus objetos mediante el lenguaje de programación. Cuando programamos el juego de tres en raya, necesitamos pensar dónde almacenar en el programa el campo de juego con los movimientos que han realizado los jugadores.
En el lenguaje de programación Python, la mejor elección será una lista de 9 valores. La llamaremos maps
. Inicialmente, esta lista estará llena de números del 1 al 9. Esto se hace para facilitar la organización del diálogo con el usuario. Al usuario le bastará con introducir un símbolo del 1 al 9 para que podamos entender dónde ha hecho su jugada. Después de que se haga la jugada, el número se reemplaza por el símbolo de un círculo o una cruz. (Se podría llenar con números del 0 al 8. En este caso, sería más fácil trabajar: el número es el índice del elemento en la lista, pero el primer cero confundirá a los jugadores).
También crearemos una segunda lista victories
en la que almacenaremos información sobre todas las combinaciones ganadoras. Y necesitaremos crear una función print_maps
que mostrará el contenido de nuestra lista maps
en la pantalla.
# Inicialización del mapa
maps = [1,2,3,
4,5,6,
7,8,9]
# Inicialización de las líneas ganadoras
victories = [[0,1,2],
[3,4,5],
[6,7,8],
[0,3,6],
[1,4,7],
[2,5,8],
[0,4,8],
[2,4,6]]
# Mostrar el mapa en la pantalla
def print_maps():
print(maps[0], end = " ")
print(maps[1], end = " ")
print(maps[2])
print(maps[3], end = " ")
print(maps[4], end = " ")
print(maps[5])
print(maps[6], end = " ")
print(maps[7], end = " ")
print(maps[8])
Hemos resuelto las estructuras de datos.
Paso 2. Realización de una jugada y verificación de la victoria
Ya tenemos el mapa para el juego y sabemos cómo mostrarlo. Ahora necesitamos crear dos funciones auxiliares antes de comenzar a programar el ciclo principal del juego.
La primera función dibujará una cruz o un círculo en el campo, dependiendo de lo que se le pase. También se le deberá pasar la posición. Insertaremos el elemento pasado por el índice. El índice lo determinaremos con la función index
(si hubiéramos numerado del 0 al 8 los elementos en maps
, el valor pasado sería el índice. Puedes intentarlo: sería una línea de código menos).
# Hacer una jugada en la casilla
def step_maps(step, symbol):
ind = maps.index(step)
maps[ind] = symbol
Después de cada jugada, debemos verificar si alguno de los jugadores ha ganado. Para ello, revisaremos todas las líneas ganadoras de la lista victories
y comprobaremos si hay una combinación de tres cruces o tres círculos.
# Obtener el resultado actual del juego
def get_result():
win = ""
for i in victories:
if maps[i[0]] == "X" and maps[i[1]] == "X" and maps[i[2]] == "X":
win = "X"
if maps[i[0]] == "O" and maps[i[1]] == "O" and maps[i[2]] == "O":
win = "O"
return win
Esta función devolverá «X» en caso de victoria de las cruces y «O» en caso de victoria de los círculos.
Paso 3. Ciclo principal del juego
Ahora nos acercamos a la creación del ciclo principal del juego. Necesitamos girar en un ciclo hasta que alguien gane. Los jugadores harán jugadas por turnos, verificaremos cada vez si alguien ha ganado y, tan pronto como alguien gane, saldremos del ciclo y finalizaremos el programa.
# Programa principal
game_over = False
player1 = True
while not game_over:
# 1. Mostrar el mapa
print_maps()
# 2. Preguntar al jugador dónde hacer la jugada
if player1:
symbol = "X"
step = int(input("Jugador 1, tu jugada: "))
else:
symbol = "O"
step = int(input("Jugador 2, tu jugada: "))
step_maps(step, symbol) # hacer la jugada en la casilla indicada
win = get_result() # determinar el ganador
if win:
game_over = True
else:
game_over = False
player1 = not player1
# El juego ha terminado. Mostrar el mapa. Anunciar al ganador.
print_maps()
print("Ganó", win)
Este es el código completo del programa de tres en raya en Python para dos jugadores:
# Inicialización del mapa
maps = [1,2,3,
4,5,6,
7,8,9]
# Inicialización de las líneas ganadoras
victories = [[0,1,2],
[3,4,5],
[6,7,8],
[0,3,6],
[1,4,7],
[2,5,8],
[0,4,8],
[2,4,6]]
# Mostrar el mapa en la pantalla
def print_maps():
print(maps[0], end = " ")
print(maps[1], end = " ")
print(maps[2])
print(maps[3], end = " ")
print(maps[4], end = " ")
print(maps[5])
print(maps[6], end = " ")
print(maps[7], end = " ")
print(maps[8])
# Hacer una jugada en la casilla
def step_maps(step, symbol):
ind = maps.index(step)
maps[ind] = symbol
# Obtener el resultado actual del juego
def get_result():
win = ""
for i in victories:
if maps[i[0]] == "X" and maps[i[1]] == "X" and maps[i[2]] == "X":
win = "X"
if maps[i[0]] == "O" and maps[i[1]] == "O" and maps[i[2]] == "O":
win = "O"
return win
# Programa principal
game_over = False
player1 = True
while not game_over:
# 1. Mostrar el mapa
print_maps()
# 2. Preguntar al jugador dónde hacer la jugada
if player1:
symbol = "X"
step = int(input("Jugador 1, tu jugada: "))
else:
symbol = "O"
step = int(input("Jugador 2, tu jugada: "))
step_maps(step, symbol) # hacer la jugada en la casilla indicada
win = get_result() # determinar el ganador
if win:
game_over = True
else:
game_over = False
player1 = not player1
# El juego ha terminado. Mostrar el mapa. Anunciar al ganador.
print_maps()
print("Ganó", win)
Así es como se ve el proceso del juego de tres en raya para 2 jugadores:
1 2 3
4 5 6
7 8 9
Jugador 1, tu jugada: 5
1 2 3
4 X 6
7 8 9
Jugador 2, tu jugada: 1
O 2 3
4 X 6
7 8 9
Jugador 1, tu jugada: 6
O 2 3
4 X X
7 8 9
Jugador 2, tu jugada: 4
O 2 3
O X X
7 8 9
Jugador 1, tu jugada: 3
O 2 X
O X X
7 8 9
Jugador 2, tu jugada: 7
O 2 X
O X X
O 8 9
Ganó O
Paso 4. Añadiendo inteligencia artificial al juego
Ahora hemos llegado al momento más interesante en la programación. Necesitamos crear una inteligencia artificial que siempre gane o empate el juego. En realidad, en el juego de tres en raya, no es tan difícil escribir un algoritmo así.
Para escribir este algoritmo, necesitaremos una función auxiliar que verifique todas las líneas ganadoras en el juego y cuente la cantidad de X y O en ellas. Si la función encuentra una línea así, devuelve la posición en esa línea donde se debe hacer el movimiento. Por ejemplo, seguiremos las líneas donde el oponente ha puesto dos X y pondremos un O para evitar que gane. Aquí está esta función:
# Inteligencia artificial: búsqueda de la línea con la cantidad necesaria de X y O en las líneas ganadoras
def check_line(sum_O, sum_X):
step = ""
for line in victories:
o = 0
x = 0
for j in range(3):
if maps[line[j]] == "O":
o += 1
if maps[line[j]] == "X":
x += 1
if o == sum_O and x == sum_X:
for j in range(3):
if maps[line[j]] != "O" and maps[line[j]] != "X":
step = maps[line[j]]
return step
Ahora escribiremos una función para buscar el siguiente mejor movimiento para la inteligencia artificial. Programaremos un algoritmo para cada movimiento (la computadora juega con O):
- Si con este movimiento podemos ganar, ganamos (ya hay 2 O en una de las líneas). De lo contrario, vamos al paso 2.
- Si podemos evitar que el humano gane, lo evitamos (el humano ya tiene 2 X en la línea, ponemos un O en ella). De lo contrario, vamos al paso 3.
- Si hay una de nuestras figuras en la línea, ponemos la segunda. Si aún no hay ninguna de nuestras figuras, vamos al paso 4.
- Ponemos un O en el centro. Si el centro está ocupado, vamos al paso 5.
- Ponemos un O en la esquina superior izquierda.
Así es como se ve todo esto en el programa en Python:
# Inteligencia artificial: elección del movimiento
def AI():
step = ""
# 1) si en alguna de las líneas ganadoras hay 2 de nuestras figuras y 0 del oponente, ponemos
step = check_line(2, 0)
# 2) si en alguna de las líneas ganadoras hay 2 figuras del oponente y 0 nuestras, ponemos
if step == "":
step = check_line(0, 2)
# 3) si hay 1 figura nuestra y 0 del oponente, ponemos
if step == "":
step = check_line(1, 0)
# 4) si el centro está vacío, ocupamos el centro
if step == "":
if maps[4] != "X" and maps[4] != "O":
step = 5
# 5) si el centro está ocupado, ocupamos la primera celda
if step == "":
if maps[0] != "X" and maps[0] != "O":
step = 1
return step
Reescribamos un poco el ciclo principal del juego. Ahora, en lugar del segundo jugador humano, será la computadora la que haga el movimiento. La computadora dirá cada vez a dónde hace el movimiento. Si la computadora no da respuesta, significa que se ha producido un empate. Finalizamos la partida y declaramos un empate. Así será el ciclo principal del juego cuando reescribamos el programa de tres en raya para jugar contra la computadora:
# Programa principal
game_over = False
human = True
while not game_over:
# 1. Mostramos el mapa
print_maps()
# 2. Preguntamos al jugador dónde hacer el movimiento
if human:
symbol = "X"
step = int(input("Humano, tu turno: "))
else:
print("La computadora hace su movimiento: ")
symbol = "O"
step = AI()
# 3. Si la computadora encuentra dónde hacer el movimiento, jugamos. Si no, es un empate.
if step != "":
step_maps(step, symbol) # hacemos el movimiento en la celda indicada
win = get_result() # determinamos el ganador
if win != "":
game_over = True
else:
game_over = False
else:
print("¡Empate!")
game_over = True
win = "la amistad"
human = not human
# El juego ha terminado. Mostramos el mapa. Anunciamos al ganador.
print_maps()
print("Ganó", win)
Programa completo para jugar tres en raya contra la computadora en Python
Aquí está el programa completo para jugar contra la inteligencia artificial:
# Inicialización del tablero
maps = [1,2,3,
4,5,6,
7,8,9]
# Inicialización de las líneas ganadoras
victories = [[0,1,2],
[3,4,5],
[6,7,8],
[0,3,6],
[1,4,7],
[2,5,8],
[0,4,8],
[2,4,6]]
# Mostrar el tablero en pantalla
def print_maps():
print(maps[0], end = " ")
print(maps[1], end = " ")
print(maps[2])
print(maps[3], end = " ")
print(maps[4], end = " ")
print(maps[5])
print(maps[6], end = " ")
print(maps[7], end = " ")
print(maps[8])
# Hacer un movimiento en una casilla
def step_maps(step, symbol):
ind = maps.index(step)
maps[ind] = symbol
# Obtener el resultado actual del juego
def get_result():
win = ""
for i in victories:
if maps[i[0]] == "X" and maps[i[1]] == "X" and maps[i[2]] == "X":
win = "X"
if maps[i[0]] == "O" and maps[i[1]] == "O" and maps[i[2]] == "O":
win = "O"
return win
# Inteligencia artificial: buscar línea con la cantidad necesaria de X y O en las líneas ganadoras
def check_line(sum_O, sum_X):
step = ""
for line in victories:
o = 0
x = 0
for j in range(0, 3):
if maps[line[j]] == "O":
o += 1
if maps[line[j]] == "X":
x += 1
if o == sum_O and x == sum_X:
for j in range(0, 3):
if maps[line[j]] != "O" and maps[line[j]] != "X":
step = maps[line[j]]
return step
# Inteligencia artificial: elegir el movimiento
def AI():
step = ""
# 1) si en alguna de las líneas ganadoras hay 2 de sus figuras y 0 del oponente, colocar en esa línea
step = check_line(2, 0)
# 2) si en alguna de las líneas ganadoras hay 2 figuras del oponente y 0 suyas, bloquear esa línea
if step == "":
step = check_line(0, 2)
# 3) si hay 1 figura suya y 0 del oponente en una línea, colocar en esa línea
if step == "":
step = check_line(1, 0)
# 4) si el centro está libre, ocupar el centro
if step == "":
if maps[4] != "X" and maps[4] != "O":
step = 5
# 5) si el centro está ocupado, ocupar la primera casilla
if step == "":
if maps[0] != "X" and maps[0] != "O":
step = 1
return step
# Programa principal
game_over = False
human = True
while not game_over:
# 1. Mostrar el tablero
print_maps()
# 2. Preguntar al jugador dónde hacer el movimiento
if human:
symbol = "X"
step = int(input("Humano, tu turno: "))
else:
print("La computadora hace su movimiento: ")
symbol = "O"
step = AI()
# 3. Si la computadora encontró dónde hacer el movimiento, jugar. Si no, es un empate.
if step != "":
step_maps(step, symbol) # hacer el movimiento en la casilla indicada
win = get_result() # determinar el ganador
if win != "":
game_over = True
else:
game_over = False
else:
print("¡Empate!")
game_over = True
win = "la amistad"
human = not human
# El juego ha terminado. Mostrar el tablero. Anunciar el ganador.
print_maps()
print("Ganó", win)
Ejemplo del proceso de juego. En este juego ganó la computadora:
1 2 3
4 5 6
7 8 9
Humano, tu turno: 1
X 2 3
4 5 6
7 8 9
La computadora hace su movimiento:
X 2 3
4 O 6
7 8 9
Humano, tu turno: 2
X X 3
4 O 6
7 8 9
La computadora hace su movimiento:
X X O
4 O 6
7 8 9
Humano, tu turno: 4
X X O
X O 6
7 8 9
La computadora hace su movimiento:
X X O
X O 6
O 8 9
Ganó O
Puedes jugar a tres en raya contra la computadora o contra otro jugador ahora mismo. Simplemente copia el texto del programa de esta página y pégalo en el campo del programa en un emulador en línea de Python.
Tarea
Nos ha salido un programa bastante implacable. Su inteligencia artificial es imposible de vencer. El humano o pierde o empata. Piensa en cómo permitir que el humano gane de vez en cuando. Tal vez quieras crear varios niveles. Por ejemplo, en el primer nivel, la inteligencia artificial es muy débil y se vuelve más fuerte en niveles posteriores. O podrías ofrecer varios modos de juego: inteligencia artificial débil, media e invencible.
En resumen, tu tarea es debilitar un poco la inteligencia artificial en nuestro juego de tres en raya. Hazlo un poco más humano.