Tutorial: Haciendo un “Ahorcado” con Python

En este post voy a escribir un pequeño juego para la CLI en Python, solo necesitas tener instalado Python3 y un editor de texto como VSCode.

El juego del ahorcado consiste en adivinar una palabra, la cual solo se conoce el numero de letras, cada intento fallido ira agregando “extremidades” a un “mono”, el juego termina cuando adivinaste la palabra correctamente o cuando el “mono” esta completo con todas sus extremidades y técnicamente es “ahorcado”.

Para iniciar veamos la estructura de lo que necesitamos hacer:

  • Desplegar una interface donde el usuario pueda ver su avance
  • Obtener una palabra
  • Desplegar la palabra “oculta”
  • Desplegar una interface donde el usuario pueda adivinando letras
  • Mostrar al usuario mensajes informativos en caso de ganar o perder

Desplegar una interface donde el usuario pueda ver su avance

Necesitamos que cuando el juego empiece el usuario sepa que esta haciendo, así que le estaremos desplegando una especie de titulo con un mensaje y una visualización muy bonita y mórbida a la ASCII art de una horca, la forma mas sencilla de crear la “horca” fue literalmente metiendo en una lista los 7 posibles escenarios:

IMAGES = ['''
    
    +----+
    |    |
         |
         |
         |
         |
         ==========''', '''

    +----+
    |    |
    O    |
         |
         |
         |
         ==========''', '''

    +----+
    |    |
    O    |
    |    |
         |
         |
         ==========''', '''

    +----+
    |    |
    O    |
   /|    |
         |
         |
         ==========''', '''

    +----+
    |    |
    O    |
   /|\   |
         |
         |
         ==========''', '''

    +----+
    |    |
    O    |
   /|\   |
    |    |
         |
         ==========''', '''

    +----+
    |    |
    O    |
   /|\   |
    |    |
   /     |
         ==========''', '''

    +----+
    |    |
    O    |
   /|\   |
    |    |
   / \   |
         ==========''', '''

''']

Esta primitiva técnica nos va a permitir de un modo bastante sencillo y tomando ventaja del hecho de que no hay estado adicionales en el juego y la progresión es siempre linear, a determinar que tan “ahorcado” esta nuestro ahorcado.

Ahora para poder obtener una palabra, en este caso también de manera “hardcoded” y bastante sencilla, agregue otra lista de “palabras”:

WORDS = [
    'can',
    'you',
    'feel',
    'the',
    'love',
    'tonight',
    'pinche',
    'pendejo'
]

Ya teniendo la lista de palabras (nótese la fuerte influencia de Elton John en mi lista, y después mi auto burla), lo que seguiría sería desplegarlo de tal modo que el usuario no sepa que palabra es pero si sepa el numero de letras que contiene, esto lo logro generando una palabra aleatoria y luego imprimiendo una lista con otros caracteres basándome en el numero de caracteres de la lista original:

def random_word():
    idx = random.randint(0,len(WORDS) - 1)
    return WORDS[idx]

Aquí lo único que le estamos diciendo a Python es que se cree de manera aleatoria un numero de entre 0 y el tamaño de la lista WORDS, ese numero lo vamos a utilizar como el indice de la misma lista lo cual “eligiría” una palabra de la lista y eso es lo que va a regresar la función.

Para desplegar la “palabra oculta”, esencialmente tenemos que obtener la dimensión de la palabra y sustituir las letras por algún caracter que la oculte:

word = random_word()
hidden_word = ['-'] * len(word)

Lo que el código aquí esta haciendo es: generar una palabra aleatoria con nuestra función “random_word()” y luego con base en esa palabra se obtiene su longitud y simplemente se concatena el carácter “-” en su lugar, de manera que si la palabra es “love” la palabra oculta seria: “—-” o 4 veces “-“.

Entrada del Usuario y lógica del juego

Para que el usuario sea capaz de interactuar con nuestro juego necesita poder escribir una letra, para esto utilizamos una función de Python que se llama input():

 current_letter = str(input('Type a Letter: '))

Lo que acá se esta haciendo es asignarle lo que sea que el usuario escriba a la variable “current_letter“, nota que estoy usando str(), esto es por que necesitamos que se interprete lo que el usuario escriba como una cadena de caracteres o “string”.

Ahora la “carnita” del juego, la lógica de verificar que la letra que escribió el usuario existe en la palabra, para esto necesitamos obtener los indices de la palabra y hacer la verificación, en caso de que exista agregaremos ese indice a una variable de control de los indices, en caso de que esta variable de control este vacía significa que no ha habido ninguna letra que coincida por lo tanto es un error, recuerda que el usuario tiene 7 oportunidades antes de “ahorcar” al “mono”:

letter_indexes = []
        for i in range(len(word)):
            if word[i] == current_letter:
                letter_indexes.append(i)
        if len(letter_indexes) == 0:
            tries += 1

Si el usuario no logra adivinar la palabra en 7 intentos necesitamos procesar que se termine el juego y se le diga al usuario cual era la palabra:

if tries == 7:
                display(hidden_word, tries)
                print('')
                print('Dammit, you killed the poor fuck,\nanyway, the word was: {}'.format(word))
                break

De otro modo significa que el usuario ha adivinado una letra, entonces hay que agregar esa letra a nuestra variable de la palabra oculta y cambiar para “revelar” el caracter en el indice que corresponde y reseteamos la variable de control de los indices:

for i in letter_indexes:
   hidden_word[i]= current_letter
letter_indexes = []

En algun punto el usuario si no mato al pobre mono adivinara la palabra entonces en este caso como nuestra variable de la palabra oculta esta utilizando el caracter “-” para las letras que aun no son descubiertas, si no hay mas caracteres “-” significa que la palabra ha sido descubierta y se lo dejamos saber al usuario con un mensaje:

 try:
            hidden_word.index('-')
        except ValueError:
            print('')
            print('Phew!\nthat MoFo sweat it out,\nthe word was \"{}\", good job!'.format(word))
            break

Estoy utilizando un try/except para procesar el error que Python va a regresar en caso de que no encuentre mas el caracter “-” en la cadena oculta, de otro modo el programa simplemente se “rompería”, con esto le doy uso a ese error y le dejo saber al usuario que ha salvado a nuestro “mono” de morir ahorcado.

Así terminamos, es en realidad un ejemplo muy sencillo pero entretenido, este es el código completo:

import random
import os

IMAGES = ['''
    
    +----+
    |    |
         |
         |
         |
         |
         ==========''', '''

    +----+
    |    |
    O    |
         |
         |
         |
         ==========''', '''

    +----+
    |    |
    O    |
    |    |
         |
         |
         ==========''', '''

    +----+
    |    |
    O    |
   /|    |
         |
         |
         ==========''', '''

    +----+
    |    |
    O    |
   /|\   |
         |
         |
         ==========''', '''

    +----+
    |    |
    O    |
   /|\   |
    |    |
         |
         ==========''', '''

    +----+
    |    |
    O    |
   /|\   |
    |    |
   /     |
         ==========''', '''

    +----+
    |    |
    O    |
   /|\   |
    |    |
   / \   |
         ==========''', '''

''']

WORDS = [
    'can',
    'you',
    'feel',
    'the',
    'love',
    'tonight',
    'pinche',
    'pendejo'
]

def random_word():
    idx = random.randint(0,len(WORDS) - 1)
    return WORDS[idx]

def display(hidden_word, tries):
    if tries > 0:
        os.system('clear')
        display_header()
    print(IMAGES[tries])
    print('')
    print(hidden_word)
    print('\n##########################################################')


def run_game():
    word = random_word()
    hidden_word = ['-'] * len(word)
    tries = 0

    while True:
        display(hidden_word, tries)
        current_letter = str(input('Type a Letter: '))

        letter_indexes = []
        for i in range(len(word)):
            if word[i] == current_letter:
                letter_indexes.append(i)
        if len(letter_indexes) == 0:
            tries += 1
            if tries == 7:
                display(hidden_word, tries)
                print('')
                print('Dammit, you killed the poor fuck,\nanyway, the word was: {}'.format(word))
                break
        else:
            for i in letter_indexes:
                hidden_word[i]= current_letter
            letter_indexes = []

        try:
            hidden_word.index('-')
        except ValueError:
            print('')
            print('Phew!\nthat MoFo sweat it out,\nthe word was \"{}\", good job!'.format(word))
            break

def display_header():
    print('H A N G M A N\n\nGuess the word and don\'t hang the poor fuck!')

if __name__ == "__main__":
    display_header()
    run_game()

Aca te dejo la liga del repo en GitHub para que lo explores, espero hayas aprendido algo y te sirva de ejemplo.

MNK

Responder

Por favor, inicia sesión con uno de estos métodos para publicar tu comentario:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Crea un sitio web o blog en WordPress.com

Subir ↑

A %d blogueros les gusta esto: