Comience creando un archivo de texto vacío llamado ahorcado.hs: la extensión hs es para indicar que este archivo contiene el código fuente de Haskell.
El corazón del juego consiste en verificar las conjeturas del jugador. Queremos saber si la suposición fue correcta. Este resultado es un valor Bool, ya sea verdadero o falso. Necesitamos actualizar la palabra mostrada, si la suposición fue correcta, reemplazando los guiones apropiados en la palabra mostrada con el carácter correctamente adivinado. Por lo tanto, el tipo de resultado de la función es un par (Bool, String). El primer elemento del par es el resultado de la suposición. El segundo elemento es la Cadena que se mostrará al usuario para la próxima ronda.
Ahora, la función de verificación necesita saber:
- La palabra secreta, una cadena
- La palabra que se muestra en pantalla o real, también una cadena
- El carácter elegido por el jugador.
Estas son las entradas a la función de verificación. Entonces ahora podemos establecer el tipo de la función:
check :: String -> String -> Char -> (Bool, String)
La nueva palabra que se mostrará será:
[(if x==c then c else y) | (x,y) <- zip word display]
Esta es una lista de comprensión, donde seleccionamos cada letra de la palabra real o de la pantalla anterior. La palabra es texto sin formato, mientras que la pantalla comienza con todos los caracteres discontinuos.
La siguiente función que definiremos es la función de giro. Esta es la función que se llamará cada vez que sea el turno del jugador para ingresar un caracter. Primero debemos comprobar cuántas conjeturas le quedan al jugador:
if n == 0
Si quedan algunas conjeturas, entonces necesitamos ver si el jugador completo la palabra o no:
if word == display
Entonces tendremos dos verificaciones if, cada una seguida de mensajes de estado putStrLn y el final de la secuencia de llamada a la función (ya que es el final del juego). Sin embargo, si ninguna de las condiciones es verdadera, entonces el jugador puede tomar un turno, por lo que llamamos a otra función para obtener otro personaje de la entrada del usuario.
Tenga en cuenta que hay una forma más ordenada de escribir la función de giro, utilizando Haskell guards, pero no vamos a utilizarlas para simplificar el programa.
¿Cuál es el tipo de mkguess? ¿Puedes resolverlo y agregarlo antes de la definición de la función? Tomamos una línea de entrada del usuario, pero solo usamos el primer carácter para la suposición. Esto fallará si el usuario simplemente presiona ENTER sin escribir ningún carácter, ya que q será una cadena vacía.
Bien, ahora solo necesitamos una función de nivel superior:
Esta función toma dos argumentos, el primero es la palabra a adivinar y el segundo es el número de conjeturas incorrectas que el jugador tiene permitido.
Pongamos todas estas cuatro funciones en un archivo de texto, llamado starman.hs
Guarde el archivo, luego inicie ghci quizás escribiendo ghci en un símbolo del sistema de DOS, ejecutando WinGHCi o escribiendo ghci en una ventana de terminal (macOS o Linux).
Si está en el directorio correcto, es decir, en el que guardó starman.hs, debería poder escribir
:l starman.hs
y el programa debería cargarse. Dirá algo como:
Prelude> :l ahorcado.hs
[1 of 1] Compiling Main ( ahorcado.hs, interpreted )
Ok, one module loaded.
Starman "funcionalmente" 5
y comienza a jugar el juego! Volverá a la solicitud de GHCi cuando se complete la función starman.
Y Listo!!
check :: String -> String -> Char -> (Bool, String)
Siempre es útil determinar primero el tipo de función. Esto enfoca su atención en lo que se supone que debe calcular la función, y qué datos necesita para hacerlo. Los buenos ingenieros de software hacen las especificaciones antes de la implementación.
¿Cómo será el cuerpo de la función de verificación? La suposición del jugador es correcta si y solo si el carácter elegido c está en la palabra secreta. Entonces la suposición es correcta si :
c palabra `elem`
¿Cómo será el cuerpo de la función de verificación? La suposición del jugador es correcta si y solo si el carácter elegido c está en la palabra secreta. Entonces la suposición es correcta si :
c palabra `elem`
La nueva palabra que se mostrará será:
[(if x==c then c else y) | (x,y) <- zip word display]
Esta es una lista de comprensión, donde seleccionamos cada letra de la palabra real o de la pantalla anterior. La palabra es texto sin formato, mientras que la pantalla comienza con todos los caracteres discontinuos.
check :: String -> String -> Char -> (Bool, String)
check word display c
= (c `elem` word, [if x==c
then c
else y | (x,y) <- zip word display])
La siguiente función que definiremos es la función de giro. Esta es la función que se llamará cada vez que sea el turno del jugador para ingresar un caracter. Primero debemos comprobar cuántas conjeturas le quedan al jugador:
if n == 0
Si quedan algunas conjeturas, entonces necesitamos ver si el jugador completo la palabra o no:
if word == display
Entonces tendremos dos verificaciones if, cada una seguida de mensajes de estado putStrLn y el final de la secuencia de llamada a la función (ya que es el final del juego). Sin embargo, si ninguna de las condiciones es verdadera, entonces el jugador puede tomar un turno, por lo que llamamos a otra función para obtener otro personaje de la entrada del usuario.
turn :: String -> String -> Int -> IO ()
turn word display n =
do if n==0
then putStrLn "You lose"
else if word==display
then putStrLn "You win!"
else mkguess word display n
mkguess word display n =
do putStrLn (display ++ " " ++ take n (repeat '*'))
putStr " Enter your guess: "
q <- getLine
let (correct, display') = check word display (q!!0)
let n' = if correct then n else n-1
turn word display' n'
Bien, ahora solo necesitamos una función de nivel superior:
starman :: String -> Int -> IO ()
starman word n = turn word ['-' | x <- word] n
Pongamos todas estas cuatro funciones en un archivo de texto, llamado starman.hs
Guarde el archivo, luego inicie ghci quizás escribiendo ghci en un símbolo del sistema de DOS, ejecutando WinGHCi o escribiendo ghci en una ventana de terminal (macOS o Linux).
Si está en el directorio correcto, es decir, en el que guardó starman.hs, debería poder escribir
:l starman.hs
y el programa debería cargarse. Dirá algo como:
Prelude> :l ahorcado.hs
[1 of 1] Compiling Main ( ahorcado.hs, interpreted )
Ok, one module loaded.
Starman "funcionalmente" 5
y comienza a jugar el juego! Volverá a la solicitud de GHCi cuando se complete la función starman.
Y Listo!!