Tres en raya con Python: lógica y validación

Actualizado el: 21/08/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

    Búsqueda en PDF con Python y RAG
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Guía PDF con Python y RAG

    Aprende a consultar PDF con Python y RAG, recuperación semántica, evaluación y seguridad.

    Ler mais

    Tempo de leitura: 7 minutos
    23/07/2026
    Integração do ChatGPT com código Python em projeto prático
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    OpenAI API con Python: integración y seguridad

    Integra la API de OpenAI con Python usando Responses API, variables de entorno, validación, reintentos, control de costes, pruebas y

    Ler mais

    Tempo de leitura: 5 minutos
    12/07/2026
    Calendário mensal gerado automaticamente com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Calendario mensual en Python con calendar

    Genera un calendario mensual con Python usando calendar y datetime, valida fechas, añade eventos y exporta a TXT, HTML o

    Ler mais

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

    Tkinter en Python: crea una app de escritorio

    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

    Recordatorios con alarma en Python: datetime y sonido

    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

    Calculadora en Python: funciones, menú y validación

    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