El Día 007 del reto 100 Días de Python construye un juego del Ahorcado con temática de Dragon Ball. El programa elige el nombre de un personaje, oculta sus letras y le da al jugador seis vidas para revelar la palabra.

Este es el primer proyecto de la serie que divide el código en varios archivos en lugar de mantener todo en un solo script. Es un paso pequeño pero importante hacia escribir programas más grandes: a medida que un proyecto crece, separar las listas de palabras y el arte ASCII de la lógica del juego mantiene cada archivo enfocado y más fácil de leer.

Esta guía recorre el código fuente completo del Día 007, incluyendo cómo está organizado entre archivos, y explica la lógica detrás de reconstruir la pantalla de la palabra adivinada en cada turno.

Descripción del Proyecto

El proyecto separa los recursos reutilizables en módulos: hangman_words.py aporta la lista de palabras, mientras que hangman_art.py aporta el logo, los dibujos del ahorcado y el arte del trofeo. El archivo principal importa esos valores y controla el juego en sí.

day007/
├── main.py           # lógica del juego
├── hangman_words.py   # word_list
└── hangman_art.py     # HANGMANART, LOGO, TROPHY

Al inicio del juego se elige una palabra al azar. La pantalla se reconstruye en cada turno comparando cada letra de la palabra con las letras que el jugador ha acertado hasta el momento. Las suposiciones incorrectas se guardan por separado y reducen el contador de vidas.

Código Fuente

La lógica del juego del Día 007 está en day007/main.py, dentro del repositorio 100daysofpython, que importa su lista de palabras y su arte de los dos módulos de apoyo mostrados arriba:

import random
from hangman_words import word_list
from hangman_art import HANGMANART, LOGO, TROPHY

def hangman():
    print(LOGO)

    lives = 6
    chosen_word = random.choice(word_list)
    word_length = len(chosen_word)

    game_over = False
    correct_letters = []
    wrong_letters = []

    print("*******************************************")
    print("Welcome to the Dragon Ball Hangman Game!")
    print("*******************************************")
    print("Guess the name of a Dragon Ball character.\nYou have 6 chances before you lose.")
    print(f"Hint: The name you are looking for has {word_length} letters.")

    while not game_over:
        print(f"******************************** {lives}/6 LIVES LEFT ********************************")
        guess = input("\nGuess a letter: ").lower()

        if guess in correct_letters or guess in wrong_letters:
            print(f"You have already guessed '{guess}', try a different letter.")
            continue

        display = ""
        for letter in chosen_word:
            if letter == guess or letter in correct_letters:
                display += letter
            else:
                display += " _ "

        print("Word to guess: " + display)

        if guess in chosen_word:
            correct_letters.append(guess)
        else:
            wrong_letters.append(guess)
            lives -= 1
            print(f"You guessed '{guess}', that is not in the word. You lose a life.")

        if lives == 0:
            game_over = True
            print(HANGMANART[lives])
            print("******************************** GAME OVER ********************************")
            print(f"You lose! The word was: {chosen_word}")
        elif " _ " not in display:
            game_over = True
            print("******************************** YOU WIN! ********************************")
            print(f"You Win! The word was: {chosen_word}")
            print(TROPHY)
        else:
            print(HANGMANART[lives])
            print(f"Wrong guesses: {wrong_letters}")

if __name__ == "__main__":
    hangman()

Cómo Funciona el Programa

Dividir el Código en Módulos

from hangman_words import word_list
from hangman_art import HANGMANART, LOGO, TROPHY

En lugar de definir la lista de palabras y el arte ASCII directamente en main.py, este proyecto los importa desde archivos separados. Esto mantiene a main.py enfocado por completo en la lógica del juego, mientras que el contenido que no tiene nada que ver con cómo funciona el juego (solo con su apariencia y las palabras que usa) vive en otro lugar. Es el mismo principio detrás de la organización de cualquier código más grande: separar lo que cambia con frecuencia (el contenido) de lo que se mantiene estable (la lógica).

Reconstruir la Pantalla en Cada Turno

display = ""
for letter in chosen_word:
    if letter == guess or letter in correct_letters:
        display += letter
    else:
        display += " _ "

En lugar de rastrear qué posiciones ya se revelaron, este ciclo reconstruye desde cero toda la cadena de la pantalla en cada intento. Para cada letra de la palabra secreta, verifica dos cosas: ¿es esta la letra que se acaba de adivinar (letter == guess), o ya se había acertado en un turno anterior (letter in correct_letters)? En cualquiera de los dos casos se muestra la letra real; de lo contrario, se usa un espacio en blanco.

Observa que guess se verifica aquí antes de agregarse a correct_letters unas líneas más abajo; eso es intencional, y es lo que permite que la pantalla refleje el intento actual de inmediato, sin tener que actualizar primero correct_letters.

Llevar las Vidas y Revisar Victoria o Derrota

if lives == 0:
    game_over = True
    ...
elif " _ " not in display:
    game_over = True
    ...

El juego termina de una de dos maneras: lives llega a cero, o la cadena de la pantalla ya no contiene ningún marcador " _ ", lo que significa que se reveló cada letra. Usar game_over como una bandera booleana, revisada en la condición del ciclo while not game_over:, es una forma limpia de permitir que cualquiera de los dos finales salga del ciclo de manera natural.

Qué Enseña Este Proyecto

El Día 007 practica:

  • Dividir un proyecto en varios archivos con import
  • Selección aleatoria de una lista con random.choice()
  • Reconstruir una cadena de pantalla desde cero en cada iteración en lugar de rastrear posiciones
  • Usar una bandera booleana (game_over) para controlar la condición de salida de un ciclo while
  • Detectar y rechazar intentos repetidos con continue

Ejecutar el Proyecto

git clone https://github.com/victorhugo81/100daysofpython.git
cd 100daysofpython/day007
python main.py

Los archivos de apoyo hangman_words.py y hangman_art.py deben permanecer en la misma carpeta que main.py, ya que el juego importa directamente de ellos.

Posibles Siguientes Pasos

Cuando entiendas el código existente, intenta ampliarlo:

  • Agrega un ajuste de dificultad que cambie el número inicial de vidas
  • Registra y muestra el número de intentos usados, no solo las vidas restantes
  • Deja que el jugador elija una categoría (por ejemplo, solo Saiyajin) antes de elegir una palabra
  • Agrega un ciclo de repetición para que el juego se reinicie automáticamente tras una victoria o una derrota

Conclusión

El Día 007 del reto 100 Días de Python introduce los proyectos de Python con varios archivos, mostrando cómo dividir las listas de palabras y el arte ASCII en sus propios módulos mantiene la lógica central del juego en main.py enfocada y legible. El enfoque de reconstruir la pantalla en cada turno también es un patrón útil de reconocer: a veces recalcular algo desde cero cada vez es más simple y menos propenso a errores que intentar rastrear los cambios incrementales.

Consulta el código fuente del Día 007 en GitHub y sigue explorando el índice de proyectos del repositorio mientras construyes más programas en Python, un día y un proyecto pequeño a la vez.