19. Ahorcado en modo texto

Antes de hacer que nuestro "juego de plataformas en modo texto" sea un poco más modular, descomponiéndolo en funciones, y ya que hemos empezado a manejar "arrays" y "structs", vamos a cambiar momentáneamente de juego para practicar el uso de "arrays" y de "cadenas de texto", creando un "juego del ahorcado".

La lógica básica del juego será la siguiente:

  1. El ordenador escoge una palabra al azar (de entre un conjunto prefijado)
  2. La palabra se muestra como una serie de guiones: ---- ----
  3. El usuario elige una letra
  4. Si la letra no es parte de la palabra, el jugador pierde un intento (de los ocho iniciales)
  5. Si la letra es parte de la palabra, el jugador no pierde ningún intento, y la letra se muestra como parte de la palabra oculta: --a- -a--
  6. Esta estructura se repite desde el punto 2, hasta que el usuario se queda sin intentos o adivina toda la palabra.

La apariencia debería ser algo como:

Juego04

¿Cómo se puede conseguir? Algunas de esas tareas son simples, pero también hay alguna un poco más enrevesada:

  1. Para escoger una palabra al azar de entre varias, basta con guardarlas en un "array de strings" y escoger una de ellas con la ayuda de un "Random".
  2. Para mostrar la palabra como una serie de guiones (---- ----) podemos volcar de forma repetitiva en una nueva cadena de texto, recorriendo letra por letra, y añadiendo un espacio si la frase a adivinar contiene algún espacio, o añadiendo un punto en caso de que sea cualquier otra letra.
  3. Lo de que el usuario elija una letra debería ser trivial a estas alturas...
  4. Para ver si la letra no es parte de la palabra, podemos usar "IndexOf"
  5. Para ir añadiendo letras a la palabra oculta (--a- -a--), como en C# no se pueden modificar directamente letras de una cadena, podemos ir volcando a una nueva cadena, de forma parecida a lo que hicimos en el punto 2: en una cadena auxiliar vamos guardando las letras de la frase que estábamos mostrando en pantalla, o la letra indicada por el usuario en caso de que coincida.
  6. Finalmente, para saber el final de la partida: lo de que el usuario se quede sin intentos es fácil si estamos llevando un contador de errores; lo de si adivina toda la palabra tampoco es difícil: podemos comprobar si ya no quedan guiones en el texto que se muestra en pantalla, o si la palabra que había que adivinar coincide con ese texto que se muestra en pantalla.

En forma de programa quedaría:

// Juego del ahorcado en modo texto
 
using System;
 
public class Ahorcado
{
 
  public static void Main()
  {
 
      // 1: El ordenador escoge una palabra al azar (de entre un conjunto prefijado)
 
      string[] palabras = { "memento", "krull", "spiderman",  
        "star wars", "hulk", "batman" };
      Random generadorAleatorio = new Random();
      int numeroAzar = generadorAleatorio.Next(0,palabras.Length);
      string palabraAdivinar = palabras[ numeroAzar ];
 
      // 1b: La palabra se muestra como serie de guiones: ---- ----
      string palabraMostrar = "";
      for (int i=0; i< palabraAdivinar.Length; i++)
          if (palabraAdivinar[i] == ' ')
              palabraMostrar += " ";
          else
              palabraMostrar += "-";
 
 
      // Otras variables
      int fallosRestantes = 8;
      char letraActual;
      bool terminado = false;
 
      // Parte repetitiva
      do
      {
 
          // 2: Se muestra la palabra oculta y el usuario elige una letra
          Console.WriteLine( "Palabra oculta:  {0}", palabraMostrar);
          Console.WriteLine( "Fallos restantes: {0}", fallosRestantes);
 
          // 3: El usuario elige una letra
          Console.Write( "Introduzca una letra: ");
          letraActual = Convert.ToChar( Console.ReadLine() );
 
          // 4: Si la letra no es parte de la palabra, el jugador 
          // pierde un intento (de los ocho iniciales)
          if( palabraAdivinar.IndexOf( letraActual ) == -1 )
              fallosRestantes--;
 
          // 5: Si la letra es parte de la palabra, el jugador no 
          // pierde ningún intento, y la letra se muestra como
          // parte de la palabra oculta: --a- -a--
          string siguienteMostrar = "";
 
          for( int i = 0; i < palabraAdivinar.Length; i++)
          {
              if( letraActual == palabraAdivinar[i] )
                  siguienteMostrar += letraActual;
              else
                  siguienteMostrar += palabraMostrar[i];
          }
          palabraMostrar = siguienteMostrar;
 
          // 6: Comprobar si ha terminado: si el usuario se queda sin intentos
          // o adivina toda la palabra.
          if( palabraMostrar.IndexOf("-") < 0 )
          {
              Console.WriteLine("Felicidades, acertaste!  ({0})",
                 palabraAdivinar);
              terminado = true;
          }
 
          if( fallosRestantes == 0 )
          {
              Console.WriteLine("Lo siento. Era {0}", palabraAdivinar);
              terminado = true;
          }
 
          Console.WriteLine();
      }
      while ( ! terminado );
 
  }
}
 

Ejercicio propuesto: Haz que este juego se comporte correctamente aunque la palabra tenga letras en mayúsculas o minúsculas, y aunque el usuario introduzca las letras en mayúsculas o en minúsculas.

Nota: también se puede modificar un poco, para practicar el uso de cadenas modificables (StringBuilder) y de "foreach", de forma que el paso 5 queda simplificado:

// Juego del ahorcado en modo texto 
// (Version con "StringBuilder" y "foreach"
 
using System;
using System.Text; // Para "StringBuilder"
 
public class Ahorcado
{
 
  public static void Main()
  {
 
      // 1: El ordenador escoge una palabra al azar (de entre un conjunto prefijado)
 
      string[] palabras = { "memento", "krull", "spiderman",  
        "star wars", "hulk", "batman" };
      Random generadorAleatorio = new Random();
      int numeroAzar = generadorAleatorio.Next(0,palabras.Length);
      string palabraAdivinar = palabras[ numeroAzar ];
 
      // 1b: La palabra se muestra como serie de guiones: ---- ----
      StringBuilder palabraMostrar =  new StringBuilder();
      foreach (char letra in palabraAdivinar)
        if (letra == ' ')
            palabraMostrar.Append(" ");
        else
            palabraMostrar.Append("-");        
 
      // Otras variables
      int fallosRestantes = 8;
      char letraActual;
      bool terminado = false;
 
      // Parte repetitiva
      do
      {
 
          // 2: Se muestra la palabra oculta y el usuario elige una letra
          Console.WriteLine( "Palabra oculta:  {0}", palabraMostrar);
          Console.WriteLine( "Fallos restantes: {0}", fallosRestantes);
 
          // 3: El usuario elige una letra
          Console.Write( "Introduzca una letra: ");
          letraActual = Convert.ToChar( Console.ReadLine() );
 
          // 4: Si la letra no es parte de la palabra, el jugador 
          // pierde un intento (de los ocho iniciales)
          if( palabraAdivinar.IndexOf( letraActual ) == -1 )
              fallosRestantes--;
 
          // 5: Si la letra es parte de la palabra, el jugador no 
          // pierde ningún intento, y la letra se muestra como
          // parte de la palabra oculta: --a- -a--
          for( int i = 0; i < palabraAdivinar.Length; i++)
              if( letraActual == palabraAdivinar[i] )
                  palabraMostrar[i]= letraActual;
 
          // 6: Comprobar si ha terminado: si el usuario se queda sin intentos
          // o adivina toda la palabra.
          if( palabraMostrar.ToString().IndexOf("-") < 0 )
          {
              Console.WriteLine("Felicidades, acertaste!  ({0})",
                 palabraAdivinar);
              terminado = true;
          }
 
          if( fallosRestantes == 0 )
          {
              Console.WriteLine("Lo siento. Era {0}", palabraAdivinar);
              terminado = true;
          }
 
          Console.WriteLine();
      }
      while ( ! terminado );
 
  }
}