diff --git a/44 Hangman/csharp/Hangman/Graphic.cs b/44 Hangman/csharp/Hangman/Graphic.cs new file mode 100644 index 00000000..ba01fcac --- /dev/null +++ b/44 Hangman/csharp/Hangman/Graphic.cs @@ -0,0 +1,129 @@ +using System; + +namespace Hangman +{ + /// + /// Represents the main "Hangman" graphic. + /// + public class Graphic + { + private readonly char[,] _graphic; + private const int Width = 12; + private const int Height = 12; + + public Graphic() + { + // 12 x 12 array to represent the graphics. + _graphic = new char[Height, Width]; + + // Fill it with empty spaces. + for (var i = 0; i < Height; i++) + { + for (var j = 0; j < Width; j++) + { + _graphic[i, j] = ' '; + } + } + + // Draw the vertical line. + for (var i = 0; i < Height; i++) + { + _graphic[i, 0] = 'X'; + } + + // Draw the horizontal line. + for (var i = 0; i < 7; i++) + { + _graphic[0, i] = 'X'; + } + + // Draw the rope. + _graphic[1, 6] = 'X'; + } + + public void Print() + { + for (var i = 0; i < Height; i++) + { + for (var j = 0; j < Width; j++) + { + Console.Write(_graphic[i, j]); + } + + Console.Write("\n"); // New line. + } + } + + public void AddHead() + { + _graphic[2, 5] = '-'; + _graphic[2, 6] = '-'; + _graphic[2, 7] = '-'; + _graphic[3, 4] = '('; + _graphic[3, 5] = '.'; + _graphic[3, 7] = '.'; + _graphic[3, 8] = ')'; + _graphic[4, 5] = '-'; + _graphic[4, 6] = '-'; + _graphic[4, 7] = '-'; + } + + public void AddBody() + { + for (var i = 5; i < 9; i++) + { + _graphic[i, 6] = 'X'; + } + } + + public void AddRightArm() + { + for (var i = 3; i < 7; i++) + { + _graphic[i, i - 1] = '\\'; // This is the escape character for the back slash. + } + } + + public void AddLeftArm() + { + _graphic[3, 10] = '/'; + _graphic[4, 9] = '/'; + _graphic[5, 8] = '/'; + _graphic[6, 7] = '/'; + } + + public void AddRightLeg() + { + _graphic[9, 5] = '/'; + _graphic[10, 4] = '/'; + } + + public void AddLeftLeg() + { + _graphic[9, 7] = '\\'; + _graphic[10, 8] = '\\'; + } + + public void AddRightHand() + { + _graphic[2, 2] = '/'; + } + + public void AddLeftHand() + { + _graphic[2, 10] = '\\'; + } + + public void AddRightFoot() + { + _graphic[11, 9] = '\\'; + _graphic[11, 10] = '-'; + } + + public void AddLeftFoot() + { + _graphic[11, 3] = '/'; + _graphic[11, 2] = '-'; + } + } +} \ No newline at end of file diff --git a/44 Hangman/csharp/Hangman/Hangman.csproj b/44 Hangman/csharp/Hangman/Hangman.csproj new file mode 100644 index 00000000..9590466a --- /dev/null +++ b/44 Hangman/csharp/Hangman/Hangman.csproj @@ -0,0 +1,8 @@ + + + + Exe + net5.0 + + + diff --git a/44 Hangman/csharp/Hangman/Hangman.sln b/44 Hangman/csharp/Hangman/Hangman.sln new file mode 100644 index 00000000..ef93fef7 --- /dev/null +++ b/44 Hangman/csharp/Hangman/Hangman.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hangman", "Hangman.csproj", "{1C516A9E-F4F2-4C79-8C37-0162C403B1F7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1C516A9E-F4F2-4C79-8C37-0162C403B1F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C516A9E-F4F2-4C79-8C37-0162C403B1F7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C516A9E-F4F2-4C79-8C37-0162C403B1F7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C516A9E-F4F2-4C79-8C37-0162C403B1F7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/44 Hangman/csharp/Hangman/Program.cs b/44 Hangman/csharp/Hangman/Program.cs new file mode 100644 index 00000000..7ecb09df --- /dev/null +++ b/44 Hangman/csharp/Hangman/Program.cs @@ -0,0 +1,313 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; + +namespace Hangman +{ + /// + /// C# version of the game "Hangman" from the book BASIC Computer Games. + /// + 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(); + + // 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. + } + + /// + /// Display the current state of the word and all the already guessed letters, and get a new guess from the player + /// + /// A char array that represents the current state of the guessed word + /// A list of chars that represents all the letters guessed so far + /// The letter that the player has just entered as a guess + private static char GetLetterFromPlayer(char[] displayedWord, List 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; + } + } + } + + /// + /// Gets a word guess from the player. + /// + /// The guessed word. + 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(); + } + } + } + + /// + /// Draw body after wrong guess. + /// + /// The instance of the Graphic class being used. + /// Number of wrong guesses. + 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(); + } + + /// + /// Get a list of words to use in the game. + /// + /// List of strings. + private static List 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" + }; + + /// + /// Leave a number of spaces empty. + /// + /// Number of spaces. + /// The result string. + private static string Tab(int length) => new string(' ', length); + } +} \ No newline at end of file