Es divertido, mucho. Pero después de reventarme contra ello es de esas cosas que sé que puedo entender si la reviso, pero no sé si sería capaz de crearlo por mí mismo (dudo mucho que fuera capaz).
# el famosísimo internacionalmente juego del ahorcado versión mimismo
import random # importamos el módulo para elegir posteriormente entre las palabras de la variable "palabras"
'''
Cadena multi-línea: comillas triples en una variable permiten meter varias líneas sin tener que utilizar \n
Lista: contiene varios valores a los que se puede acudir por número de izq a der empezando desde el 0,
en la de abajo IMÁGENES_AHORCADO cada elemento de la lista es una cadena multi-línea
Constantes: para variables constantes como IMÁGENES_AHORCADO la convención es que vayan escritas en mayúscula
(una "variable constante" es un contrasentido como un piano, yo diría "constante" sin más)
'''
IMÁGENES_AHORCADO = ['''
+---+
| |
|
|
|
|
=========''', '''
+---+
| |
O |
|
|
|
=========''', '''
+---+
| |
O |
| |
|
|
=========''', '''
+---+
| |
O |
/| |
|
|
=========''', '''
+---+
| |
O |
/|\ |
|
|
=========''', '''
+---+
| |
O |
/|\ |
/ |
|
=========''', '''
+---+
| |
O |
/|\ |
/ \ |
|
=========''']
palabras = 'hormiga babuino tejon murcielago oso castor camello gato almeja cobra pantera coyote cuervo ciervo perro burro pato aguila huron zorro rana cabra ganso halcon leon lagarto llama topo mono alce raton mula salamandra nutria buho panda loro paloma piton conejo carnero rata cuervo rinoceronte salmon foca tiburon oveja mofeta perezoso serpiente araña cigüeña cisne tigre sapo trucha pavo tortuga comadreja ballena lobo wombat cebra'.split()
# el método .split() devuelve una lista en la que cada palabra en la cadena es un elemento aparte, separa en cada hueco en blanco.
# "palabras" pasa a ser una lista igual que si hubiéramos escr
# con ListaDePalabras defines un parámetro, dices que al lanzar la función obtenerPalabraAlAzar le incluirás una lista entre (). ito palabras = ['hormiga', 'babuino'] etcetc.
# recordatorio personal: definir funciones no pone en marcha nada, simplemente las define para un futuro
# no es que estés creando otra lista, sino que le indicas que trabajará con una lista de palabras que proporcionas, en este caso 'palabras'
# eso mola porque la función utilizará listaDePalabras para manipularlas se llame como se llame la lista que le metas
# lo que me ha costado comprender esto, todo está relacionado con las variables globales y las variables locales
# si dentro de la función substituyes listaDePalabras por palabras todo seguiría funcionando igual, de hecho lo hace en la función siguiente
def obtenerPalabraAlAzar(listaDePalabras):
índiceDePalabras = random.randint(0, len(listaDePalabras) - 1) # el número que se usará para elegir de la lista palabras[x]
# -1 porque el elemento 1 es el 0 en la asignación, así que la cuarta palabra en la lista estará en la posición 3
# elige entre 0 y la longitud de la lista -1
return listaDePalabras[índiceDePalabras]
# devuelve listaDePalabras (que en este caso es palabras, el nombre de la lista) y [el índice]: palabras[x]
# en esta función las variables locales se llaman igual que las globales, aunque no son las mismas
def mostrarTablero(IMÁGENES_AHORCADO, letrasIncorrectas, letrasCorrectas, palabraSecreta):
print(IMÁGENES_AHORCADO[len(letrasIncorrectas)]) # imprime de la lista de imágenes la que está en la posición de las letras incorrectas
print() # imprimimos una línea en blanco
print('Letras incorrectas:', end=' ') # imprime el texto y no salta a la línea de abajo
for letra in letrasIncorrectas: # letra es una nueva variable for hace que "deletree" las letras que pertenecen a incorrectas y las guarda en cada ciclo en letra
print(letra, end=' ') # la secuencia for imprime letra sin saltar a la linea de abajo
print() # imprimimos una línea en blanco
espaciosVacíos = '_' * len(palabraSecreta) # las líneas de la palabra, imprime tantos _ como su longitud
for i in range(len(palabraSecreta)): # nueva variable i en la que se acumula toda la longitud de palabraSecreta, si tiene 7 letras se moverá entre el 0-6
if palabraSecreta[i] in letrasCorrectas: # si la letra que toca está en letras correctas... (cualquier variable es tb una lista de letras, guardas 'hola' y palabraSecreta[0] será h)
espaciosVacíos = espaciosVacíos[:i] + palabraSecreta[i] + espaciosVacíos[i+1:]
''' vamos a actualizar espaciosVacíos por las letras descubiertas con un corte de lista
corte de lista [a:c] marca las palabras que se van a incluir con desde-hasta, y el hasta no incluye, en hola[1:3] sería ol, las pos 1 y 2
1. espaciosVacíos[:i] metemos los valores de espacios vacíos hasta i (para no modificar los anteriores bucles de _ vacíos y letras descubiertas)
el hasta del corte llega hasta justo la posición anterior a i
2. palabraSecreta[i] metemos la letra que ha sido correcta en i
3. espaciosVacíos[i+1:] metemos desde i en adelante lo que hubiera (_ vacíos y letras descubiertas)
de espaciosVacíos nos interesan los _ y las letras descubiertas en bucles anteriores, y de palabraSecreta sólo la letra correcta
'''
for letra in espaciosVacíos: # generamos letra con todo lo que esté en spaciosVacíos
print(letra, end=' ') # imprimimos las letras y los _ (letra es la variable que creamos cada ciclo) y no saltamos de línea
print() # imprimimos una línea en blanco
# nueva función para recibir la nueva letra, le metemos letrasProbadas con las letras que hemos metido con anterioridad como parámetro
def obtenerIntento(letrasProbadas):
while True: # jaja, siempre es true hasta que sales con return
print('Adivina una letra.') # imprimimos Adivina...
intento = input() # le pedimos que meta una letra y la guardamos en intento
intento = intento.lower() # la ponemos en minúscula
if len(intento) != 1: # si la longitud de intento es más de uno es que ha metido más de una letra y no mola
print('Por favor, introduce una letra.') # le decimos lo que ha pasado
elif intento in letrasProbadas: # tb si la letra ya la ha metido antes
print('Ya has probado esa letra, elige otra.') # le decimos que ya lo ha hecho
elif intento not in 'abcdefghijklmnñopqrstuvwxyz': # si no está en el abecedario
print('Por favor, ingresa una LETRA.') # se lo recordamos
else: # en cualquier otro caso
return intento # devolvemos el resultado metiéndolo en la variable global intento
# función para volver a jugar o salir
def jugarDeNuevo(): # definimos, no necesita parámetro
print('¿Quieres jugar de nuevo (sí o no)') # imprimimos la pregunta
return input().lower().startswith('s') # ponemos input en minúsculas, si empieza por s devuelve True (s no es lo mismo que S)
# y empieza el juego!
print('A H O R C A D O') # imprimimos el nombre
letrasIncorrectas = '' # creamos la variable letrasIncorrectas
letrasCorrectas = '' # creamos la variable #letrasCorrectas
# la única vez que se invoca "palabras" es para meterla dentro de la función obtenerPalabraAlAzar
# le estás diciendo a la función el nombre de la lista que tiene que utilizar
palabraSecreta = obtenerPalabraAlAzar(palabras) # creamos la palabra correcta
juegoTerminado = False # establecemos el status para salir del juego en False
while True: # repite el bucle indefinidamente hasta que algo le saca
mostrarTablero(IMÁGENES_AHORCADO, letrasIncorrectas, letrasCorrectas, palabraSecreta) # invocas mostrarTablero con sus variables
intento = obtenerIntento(letrasIncorrectas + letrasCorrectas) # creas intento invocando a la función obtenerIntento, con las letrasIncorrectas y las letrasCorrectas como variables que se meterán en la variable local letrasProbadas
if intento in palabraSecreta: # aquí la función obtenerIntento ya ha devuelto la letra que ha metido el tipo, así que si está en la palabraSecreta...
letrasCorrectas = letrasCorrectas + intento # la añadimos a letrasCorrectas manteniendo las anteriores, en intento sigue estando la letra que ha metido el tipo
encontradoTodasLasLetras = True # marcamos el status de encontradoTodasLasLetras como verdadero, tendrá sentido en el siguiente if
for i in range(len(palabraSecreta)): # bucle for para testar las letras
if palabraSecreta[i] not in letrasCorrectas: # si una de las letras de palabraSecreta no está en letrasCorrectas
encontradoTodasLasLetras = False # cambiamos el status de encontradoTodasLasLetras a False
break # rompemos el for, así que pasará a else:
if encontradoTodasLasLetras: # si encontradoTodasLasLetras es True
print('¡Sí! ¡La palabra secreta es "' + palabraSecreta + '"! ¡Has ganado!') # imprimes el final
juegoTerminado = True # y creas juego terminado y le das valor True
else:
letrasIncorrectas = letrasIncorrectas + intento # si la letra no estaba en la palabra secreta, la añadimos a letras incorrectas
if len(letrasIncorrectas) == len(IMÁGENES_AHORCADO) - 1: # ojo, si la longitud de letrasIncorrectas es igual a IMÁGENES_AHORCADO - 1 (len empieza en 1, las listas en 0)
mostrarTablero(IMÁGENES_AHORCADO, letrasIncorrectas, letrasCorrectas, palabraSecreta) # invocamos mostrarTablero con sus parámetros
print('¡Te has quedado sin intentos!\nDespués de ' + str(len(letrasIncorrectas)) + ' intentos fallidos y ' + str(len(letrasCorrectas)) + ' aciertos, la palabra era "' + palabraSecreta + '"')
# imprimimos msg + el número de letras incorrectas + msg + el número de letras correctas + msg + la palabra secreta que había que adivinar
juegoTerminado = True # y establecemos juegoTerminado en True
if juegoTerminado: # invocamos juegoTerminado, y si devuelve True
if jugarDeNuevo(): # si el tipo ha contestado cualquier cosa que empiece por s, incluido soplapollas
# atención a cómo juegoTerminado, que no es una función, no tiene (), mientras que jugarDeNuevo, que sí lo es, sí los tiene
letrasIncorrectas = '' # ponemos a cero letrasIncorrectas
letrasCorrectas = '' # ponemos a cero letrasCorrectas
juegoTerminado = False # convertimos juegoTerminado a False
palabraSecreta = obtenerPalabraAlAzar(palabras) # obtenemos una nueva palabraSecreta
else: # si jugarDeNuevo devuelve false
break # cerramos el programa