Files
basic-computer-games/44 Hangman/csharp/Hangman/Program.cs
2021-02-21 21:01:05 -08:00

313 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
namespace Hangman
{
/// <summary>
/// C# version of the game "Hangman" from the book BASIC Computer Games.
/// </summary>
static class Program
{
static void Main()
{
Console.WriteLine(Tab(32) + "HANGMAN");
Console.WriteLine(Tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
MainLoop();
Console.WriteLine();
Console.WriteLine("IT'S BEEN FUN! BYE FOR NOW.");
}
static void MainLoop()
{
var words = GetWords();
var stillPlaying = true;
while (stillPlaying)
{
if (words.Count == 0)
{
Console.WriteLine("YOU DID ALL THE WORDS!!");
break;
}
// Get a random number from 0 to the number of words we have minus one (C# arrays are zero-based).
var rnd = new Random();
var randomNumber = rnd.Next(words.Count - 1);
// Pick a random word and remove it from the list.
var word = words[randomNumber];
words.Remove(word);
GameLoop(word);
// Game finished. Ask if player wants another one.
Console.WriteLine("WANT ANOTHER WORD? ");
var response = Console.ReadLine();
if (response == null || response.ToUpper() != "YES")
{
stillPlaying = false; // Exit the loop if the player didn't answer "yes".
}
}
}
static void GameLoop(string word)
{
var graphic = new Graphic();
var wrongGuesses = 0;
var numberOfGuesses = 0;
var usedLetters = new List<char>();
// The word that the user sees. Since we just started, it's just dashes.
var displayedWord = new char[word.Length];
for (var i = 0; i < word.Length; i++)
{
displayedWord[i] = '-';
}
var stillPlaying = true;
while (stillPlaying)
{
var guess = GetLetterFromPlayer(displayedWord, usedLetters);
usedLetters.Add(guess);
numberOfGuesses++;
var correctLetterCount = 0;
// Now we check every letter in the word to see if the player guessed any of them correctly.
for(var i = 0; i < word.Length; i++)
{
if (word[i] == guess)
{
correctLetterCount++;
displayedWord[i] = guess;
}
}
if (correctLetterCount == 0)
{
// Wrong guess.
Console.WriteLine("SORRY, THAT LETTER ISN'T IN THE WORD.");
wrongGuesses++;
DrawBody(graphic, wrongGuesses);
if (wrongGuesses == 10)
{
// Player exhausted all their guesses. Finish the game loop.
Console.WriteLine($"SORRY, YOU LOSE. THE WORD WAS {word}");
Console.Write("YOU MISSED THAT ONE. DO YOU ");
stillPlaying = false;
}
}
else
{
// Player guessed a correct letter. Let's see if there are any unguessed letters left in the word.
if (displayedWord.Contains('-'))
{
Console.WriteLine(displayedWord);
// Give the player a chance to guess the whole word.
var wordGuess = GetWordFromPlayer();
if (word == wordGuess)
{
// Player found the word. Mark it found.
Console.WriteLine("YOU FOUND THE WORD!");
stillPlaying = false; // Exit game loop.
}
else
{
// Player didn't guess the word. Continue the game loop.
Console.WriteLine("WRONG. TRY ANOTHER LETTER.");
}
}
else
{
// Player guessed all the letters.
Console.WriteLine("YOU FOUND THE WORD!");
stillPlaying = false; // Exit game loop.
}
}
} // End of game loop.
}
/// <summary>
/// Display the current state of the word and all the already guessed letters, and get a new guess from the player
/// </summary>
/// <param name="displayedWord">A char array that represents the current state of the guessed word</param>
/// <param name="usedLetters">A list of chars that represents all the letters guessed so far</param>
/// <returns>The letter that the player has just entered as a guess</returns>
private static char GetLetterFromPlayer(char[] displayedWord, List<char> usedLetters)
{
while (true) // Infinite loop, unless the player enters an unused letter.
{
Console.WriteLine();
Console.WriteLine(displayedWord);
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("HERE ARE THE LETTERS YOU USED:");
for (var i = 0; i < usedLetters.Count; i++)
{
Console.Write(usedLetters[i]);
// If it's not the last letter, print a comma.
if (i != usedLetters.Count - 1)
{
Console.Write(",");
}
}
Console.WriteLine();
Console.WriteLine("WHAT IS YOUR GUESS?");
var guess = char.ToUpper(Console.ReadKey().KeyChar);
Console.WriteLine();
if (usedLetters.Contains(guess))
{
// After this the loop will continue.
Console.WriteLine("YOU GUESSED THAT LETTER BEFORE!");
}
else
{
// Break out of the loop by returning guessed letter.
return guess;
}
}
}
/// <summary>
/// Gets a word guess from the player.
/// </summary>
/// <returns>The guessed word.</returns>
private static string GetWordFromPlayer()
{
while (true) // Infinite loop, unless the player enters something.
{
Console.WriteLine("WHAT IS YOUR GUESS FOR THE WORD? ");
var guess = Console.ReadLine();
if (guess != null)
{
return guess.ToUpper();
}
}
}
/// <summary>
/// Draw body after wrong guess.
/// </summary>
/// <param name="graphic">The instance of the Graphic class being used.</param>
/// <param name="wrongGuesses">Number of wrong guesses.</param>
private static void DrawBody(Graphic graphic, int wrongGuesses)
{
switch (wrongGuesses)
{
case 1:
Console.WriteLine("FIRST, WE DRAW A HEAD.");
graphic.AddHead();
break;
case 2:
Console.WriteLine("NOW WE DRAW A BODY.");
graphic.AddBody();
break;
case 3:
Console.WriteLine("NEXT WE DRAW AN ARM.");
graphic.AddRightArm();
break;
case 4:
Console.WriteLine("THIS TIME IT'S THE OTHER ARM.");
graphic.AddLeftArm();
break;
case 5:
Console.WriteLine("NOW, LET'S DRAW THE RIGHT LEG.");
graphic.AddRightLeg();
break;
case 6:
Console.WriteLine("THIS TIME WE DRAW THE LEFT LEG.");
graphic.AddLeftLeg();
break;
case 7:
Console.WriteLine("NOW WE PUT UP A HAND.");
graphic.AddRightHand();
break;
case 8:
Console.WriteLine("NEXT THE OTHER HAND.");
graphic.AddLeftHand();
break;
case 9:
Console.WriteLine("NOW WE DRAW ONE FOOT.");
graphic.AddRightFoot();
break;
case 10:
Console.WriteLine("HERE'S THE OTHER FOOT -- YOU'RE HUNG!!");
graphic.AddLeftFoot();
break;
}
graphic.Print();
}
/// <summary>
/// Get a list of words to use in the game.
/// </summary>
/// <returns>List of strings.</returns>
private static List<string> GetWords() => new()
{
"GUM",
"SIN",
"FOR",
"CRY",
"LUG",
"BYE",
"FLY",
"UGLY",
"EACH",
"FROM",
"WORK",
"TALK",
"WITH",
"SELF",
"PIZZA",
"THING",
"FEIGN",
"FIEND",
"ELBOW",
"FAULT",
"DIRTY",
"BUDGET",
"SPIRIT",
"QUAINT",
"MAIDEN",
"ESCORT",
"PICKAX",
"EXAMPLE",
"TENSION",
"QUININE",
"KIDNEY",
"REPLICA",
"SLEEPER",
"TRIANGLE",
"KANGAROO",
"MAHOGANY",
"SERGEANT",
"SEQUENCE",
"MOUSTACHE",
"DANGEROUS",
"SCIENTIST",
"DIFFERENT",
"QUIESCENT",
"MAGISTRATE",
"ERRONEOUSLY",
"LOUDSPEAKER",
"PHYTOTOXIC",
"MATRIMONIAL",
"PARASYMPATHOMIMETIC",
"THIGMOTROPISM"
};
/// <summary>
/// Leave a number of spaces empty.
/// </summary>
/// <param name="length">Number of spaces.</param>
/// <returns>The result string.</returns>
private static string Tab(int length) => new string(' ', length);
}
}