Cómo crear un juego de tres en raya con Python

Publicado el: 11/07/2026
Tempo de leitura: 4 minutos
Projeto de jogo da velha desenvolvido em Python como exercício de lógica de programação

El tres en raya, también conocido como tic-tac-toe o juego de la vieja, es un proyecto ideal para practicar lógica, listas, funciones, bucles y validación de entradas. Aunque sus reglas son sencillas, construir una versión completa obliga a representar el tablero, alternar jugadores, detectar victorias y controlar movimientos inválidos. El resultado es un programa pequeño, pero con una estructura muy parecida a la de proyectos mayores.

Antes de empezar, conviene repasar las listas en Python, las funciones, los bucles, la función input() y el manejo de errores.

La documentación oficial de estructuras de datos explica listas y recorridos. El tutorial oficial de control de flujo describe condiciones, bucles y funciones.

Representar el tablero

Usaremos una lista con nueve posiciones. Cada elemento corresponde a una casilla:

tablero = [" "] * 9

Los índices van de cero a ocho. Para el jugador resulta más natural elegir del 1 al 9, así que convertiremos su elección restando uno.

Mostrar el tablero

def mostrar_tablero(tablero):
    print()
    print(f" {tablero[0]} | {tablero[1]} | {tablero[2]} ")
    print("---+---+---")
    print(f" {tablero[3]} | {tablero[4]} | {tablero[5]} ")
    print("---+---+---")
    print(f" {tablero[6]} | {tablero[7]} | {tablero[8]} ")
    print()

Durante las primeras partidas puede ser útil mostrar un tablero de referencia:

def mostrar_referencia():
    print(" 1 | 2 | 3 ")
    print("---+---+---")
    print(" 4 | 5 | 6 ")
    print("---+---+---")
    print(" 7 | 8 | 9 ")

Definir las combinaciones ganadoras

COMBINACIONES = (
    (0, 1, 2),
    (3, 4, 5),
    (6, 7, 8),
    (0, 3, 6),
    (1, 4, 7),
    (2, 5, 8),
    (0, 4, 8),
    (2, 4, 6),
)

Una tupla es adecuada porque estas combinaciones no cambian durante la partida.

Comprobar si alguien ganó

def hay_ganador(tablero, simbolo):
    return any(
        tablero[a] == tablero[b] == tablero[c] == simbolo
        for a, b, c in COMBINACIONES
    )

any() devuelve verdadero cuando al menos una combinación está completa. Esta función no imprime nada, por lo que resulta sencilla de probar.

Detectar el empate

def tablero_lleno(tablero):
    return all(casilla != " " for casilla in tablero)

Solo existe empate si el tablero está lleno y ningún jugador ganó.

Leer una jugada válida

def pedir_jugada(tablero, jugador):
    while True:
        texto = input(f"Jugador {jugador}, elige una casilla (1-9): ").strip()

        if not texto.isdigit():
            print("Debes escribir un número.")
            continue

        posicion = int(texto)
        if posicion < 1 or posicion > 9:
            print("La posición debe estar entre 1 y 9.")
            continue

        indice = posicion - 1
        if tablero[indice] != " ":
            print("Esa casilla ya está ocupada.")
            continue

        return indice

La validación se hace paso a paso. Así el programa puede explicar exactamente qué entrada fue incorrecta.

Alternar jugadores

def siguiente_jugador(actual):
    return "O" if actual == "X" else "X"

Esta función evita repetir condiciones dentro del bucle principal.

Crear la partida completa

def jugar():
    tablero = [" "] * 9
    jugador = "X"

    mostrar_referencia()

    while True:
        mostrar_tablero(tablero)
        indice = pedir_jugada(tablero, jugador)
        tablero[indice] = jugador

        if hay_ganador(tablero, jugador):
            mostrar_tablero(tablero)
            print(f"¡El jugador {jugador} ganó!")
            return jugador

        if tablero_lleno(tablero):
            mostrar_tablero(tablero)
            print("La partida terminó en empate.")
            return None

        jugador = siguiente_jugador(jugador)

El orden de las comprobaciones importa. Primero revisamos la victoria y después el empate. En la última jugada, el tablero puede quedar lleno y al mismo tiempo producir una victoria.

Permitir varias partidas

def preguntar_repeticion():
    while True:
        respuesta = input("¿Jugar otra vez? (s/n): ").strip().lower()
        if respuesta in {"s", "si", "sí"}:
            return True
        if respuesta == "n":
            return False
        print("Respuesta no válida.")


def main():
    victorias = {"X": 0, "O": 0, "empates": 0}

    while True:
        resultado = jugar()
        if resultado is None:
            victorias["empates"] += 1
        else:
            victorias[resultado] += 1

        print("Marcador:", victorias)
        if not preguntar_repeticion():
            break


if __name__ == "__main__":
    main()

Elegir símbolos

Puedes permitir que el primer jugador elija:

def elegir_simbolo():
    while True:
        simbolo = input("Elige X u O: ").strip().upper()
        if simbolo in {"X", "O"}:
            return simbolo
        print("Elige únicamente X u O.")

El segundo recibe el símbolo restante. No permitas cadenas vacías ni símbolos que dificulten la lectura.

Crear un oponente básico

Una inteligencia artificial sencilla puede escoger una casilla libre al azar:

import random


def jugada_aleatoria(tablero):
    libres = [
        indice
        for indice, casilla in enumerate(tablero)
        if casilla == " "
    ]
    return random.choice(libres)

Después puedes mejorarla con tres prioridades: ganar si existe una jugada ganadora, bloquear una victoria del usuario y, en caso contrario, elegir centro, esquina o una casilla aleatoria.

Simular una jugada sin modificar el tablero

def seria_ganadora(tablero, indice, simbolo):
    copia = tablero.copy()
    copia[indice] = simbolo
    return hay_ganador(copia, simbolo)

Crear una copia evita alterar accidentalmente la partida mientras la IA evalúa opciones.

Pruebas unitarias

def test_fila_ganadora():
    tablero = ["X", "X", "X", " ", "O", " ", "O", " ", " "]
    assert hay_ganador(tablero, "X") is True


def test_tablero_no_lleno():
    tablero = ["X", "O", " ", "X", "O", "X", "O", "X", "O"]
    assert tablero_lleno(tablero) is False

Prueba las tres filas, columnas, diagonales, empate y ausencia de ganador. También conviene comprobar que una jugada simulada no modifica la lista original.

Separar lógica e interfaz

Funciones como hay_ganador y tablero_lleno no dependen del terminal. Por eso pueden reutilizarse en una interfaz gráfica con Tkinter, una página web o una API. Mantener input() y print() fuera de la lógica principal facilita esa evolución.

Mejoras posibles

Puedes añadir nombres de jugadores, historial de movimientos, opción para deshacer, colores del terminal, tablero gráfico, dificultad de IA y algoritmo minimax. Antes de implementar minimax, asegúrate de que las reglas básicas estén cubiertas por pruebas.

Errores frecuentes

Los fallos más comunes son confundir posiciones del 1 al 9 con índices del 0 al 8, permitir sobrescribir una casilla, comprobar empate antes de victoria y modificar el tablero real durante una simulación. También es habitual mezclar toda la lógica en un único bucle difícil de probar.

Conclusión

El tres en raya enseña a convertir reglas en funciones pequeñas y verificables. Representa el tablero con una lista, guarda las combinaciones ganadoras, valida cada jugada y separa la interfaz de la lógica. Con esta base puedes añadir marcador, partidas repetidas, un oponente automático o una interfaz gráfica sin reescribir el núcleo del juego.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Quiz interativo no terminal desenvolvido com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un quiz interactivo en Python

    Crea un quiz interactivo en Python con preguntas, opciones, validación, puntuación, JSON, categorías, mezcla aleatoria y pruebas.

    Ler mais

    Tempo de leitura: 3 minutos
    11/07/2026
    Jogo de adivinhação de números desenvolvido com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un juego de adivinar números con Python

    Crea un juego de adivinar números con Python usando random, validación, intentos, niveles, pistas, puntuación, récords y pruebas.

    Ler mais

    Tempo de leitura: 3 minutos
    11/07/2026
    texto Tkinter com uma interface gráfica dele ao lado
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear tu primera aplicación con Tkinter

    Crea tu primera aplicación con Tkinter: ventanas, ttk, formularios, grid, eventos, archivos, threads, estilos y separación de lógica.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Sistema de lembretes e alarmes desenvolvido com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un sistema de recordatorios con alarma en Python

    Crea recordatorios con alarma en Python usando datetime, JSON, threads, zonas horarias, sonidos, recurrencia y pruebas controladas.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Foto de uma pessoa usando uma calculadora
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear una calculadora en Python paso a paso

    Crea una calculadora en Python con funciones, menú, validación, Decimal, historial, pruebas y una base segura para añadir Tkinter.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Conversor de moedas desenvolvido com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un conversor de monedas con Python

    Crea un conversor de monedas con Python, Requests, Decimal, validación, caché, manejo de errores y tasas de referencia confiables.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026