today I created a simple hangman game, which has 10 different categories with 10 words each. The words order is being randomized each time you pick a category. You have the chance to pick a wrong letter 8 times, after this it's game over and your progress on the current category is being wiped out. The game also saves all the completed categories in the Settings of the project so you wont loose any progress if you restart the game. There are 3 difficulties - easy, medium, hard. Easy show's you the first and the last letters of the word, medium shows you only the first one and hard shows none. Each one has separate progress completion. This is how the game looks http://prntscr.com/b0hkye you can enter letter by pressing them on your keyboard or by using the alphabet built-in the app. That's pretty much of it now I'm going to quickly go over the code.
The game has a static class which holds some data that will be used over all the forms.
public static class GeneralSettings
{
public enum Difficulty
{
Easy,
Medium,
Hard
}
public enum Category
{
Capitals,
FoodAndDrinks,
Animals,
Plants,
Objects,
Movies,
Cities,
Furniture,
Figures,
Sports
}
public static Difficulty GameDifficulty { get; set; }
public static Category GameCategory { get; set; }
public static string[] GameWords { get; set; }
}
and I also created another static class which holds all the available words
public static class Words
{
public static string[] Capitals =
{
"London",
"Tokyo",
"Paris",
"Berlin",
"Ottawa",
"Washington",
"Copenhagen",
"Kabul",
"Sofia",
"Budapest"
};
public static string[] FoodAndDrinks =
{
"Haggis",
"Spaghetti",
"Pizza",
"Salad",
"Fanta",
"Hamburger",
"Steak",
"Eggs",
"Water",
"Juice"
};
//more here
}
Now the game initially start in the MainMenu
Form where you select your difficulty
using static GLS_GuessTheWord.GeneralSettings;
private void bEasy_Click(object sender, EventArgs e)
{
GameDifficulty = Difficulty.Easy;
ChapterSelection cs = new ChapterSelection();
cs.ShowDialog();
}
private void bMedium_Click(object sender, EventArgs e)
{
GameDifficulty = Difficulty.Medium;
ChapterSelection cs = new ChapterSelection();
cs.ShowDialog();
}
private void bHard_Click(object sender, EventArgs e)
{
GameDifficulty = Difficulty.Hard;
ChapterSelection cs = new ChapterSelection();
cs.ShowDialog();
}
private void bExit_Click(object sender, EventArgs e)
{
Application.Exit();
}
Once you've picked your difficulty you are taken to the ChapterSelection
Form which has different Checkboxs
foreach difficulty as mentioned earlier.
private void UpdateEasyCompletedCategories()
{
cbCapitals.Checked = Properties.Settings.Default.EasyCapitalsCompleted;
cbFoodAndDrinks.Checked = Properties.Settings.Default.EasyFoodAndDrinksCompleted;
cbAnimals.Checked = Properties.Settings.Default.EasyAnimalsCompleted;
cbPlants.Checked = Properties.Settings.Default.EasyPlantsCompleted;
cbObjects.Checked = Properties.Settings.Default.EasyObjectsCompleted;
cbMovies.Checked = Properties.Settings.Default.EasyMoviesCompleted;
cbFurniture.Checked = Properties.Settings.Default.EasyFurnitureCompleted;
cbCities.Checked = Properties.Settings.Default.EasyCitiesCompleted;
cbFigures.Checked = Properties.Settings.Default.EasyFiguresCompleted;
cbSports.Checked = Properties.Settings.Default.EasySportsCompleted;
}
private void UpdateMediumCompletedCategories()
{
cbCapitals.Checked = Properties.Settings.Default.MediumCapitalsCompleted;
cbFoodAndDrinks.Checked = Properties.Settings.Default.MediumFoodAndDrinksCompleted;
cbAnimals.Checked = Properties.Settings.Default.MediumAnimalsCompleted;
cbPlants.Checked = Properties.Settings.Default.MediumPlantsCompleted;
cbObjects.Checked = Properties.Settings.Default.MediumObjectsCompleted;
cbMovies.Checked = Properties.Settings.Default.MediumMoviesCompleted;
cbFurniture.Checked = Properties.Settings.Default.MediumFurnitureCompleted;
cbCities.Checked = Properties.Settings.Default.MediumCitiesCompleted;
cbFigures.Checked = Properties.Settings.Default.MediumFiguresCompleted;
cbSports.Checked = Properties.Settings.Default.MediumSportsCompleted;
}
private void UpdateHardCompletedCategories()
{
cbCapitals.Checked = Properties.Settings.Default.HardCapitalsCompleted;
cbFoodAndDrinks.Checked = Properties.Settings.Default.HardFoodAndDrinksCompleted;
cbAnimals.Checked = Properties.Settings.Default.HardAnimalsCompleted;
cbPlants.Checked = Properties.Settings.Default.HardPlantsCompleted;
cbObjects.Checked = Properties.Settings.Default.HardObjectsCompleted;
cbMovies.Checked = Properties.Settings.Default.HardMoviesCompleted;
cbFurniture.Checked = Properties.Settings.Default.HardFurnitureCompleted;
cbCities.Checked = Properties.Settings.Default.HardCitiesCompleted;
cbFigures.Checked = Properties.Settings.Default.HardFiguresCompleted;
cbSports.Checked = Properties.Settings.Default.HardSportsCompleted;
}
private void UpdateCompletedCategories()
{
switch (GameDifficulty)
{
case Difficulty.Easy:
UpdateEasyCompletedCategories();
break;
case Difficulty.Medium:
UpdateMediumCompletedCategories();
break;
case Difficulty.Hard:
UpdateHardCompletedCategories();
break;
}
}
private void bCapitals_Click(object sender, EventArgs e)
{
GameWords = Words.Capitals;
GameCategory = Category.Capitals;
MainGame mg = new MainGame();
mg.ShowDialog();
UpdateEasyCompletedCategories();
}
private void bFandD_Click(object sender, EventArgs e)
{
GameWords = Words.FoodAndDrinks;
GameCategory = Category.FoodAndDrinks;
MainGame mg = new MainGame();
mg.ShowDialog();
UpdateEasyCompletedCategories();
}
private void bAnimals_Click(object sender, EventArgs e)
{
GameWords = Words.Animals;
GameCategory = Category.Animals;
MainGame mg = new MainGame();
mg.ShowDialog();
UpdateEasyCompletedCategories();
}
private void bPlants_Click(object sender, EventArgs e)
{
GameWords = Words.Plants;
GameCategory = Category.Plants;
MainGame mg = new MainGame();
mg.ShowDialog();
UpdateEasyCompletedCategories();
}
private void bObjects_Click(object sender, EventArgs e)
{
GameWords = Words.Objects;
GameCategory = Category.Objects;
MainGame mg = new MainGame();
mg.ShowDialog();
UpdateEasyCompletedCategories();
}
private void bMovies_Click(object sender, EventArgs e)
{
GameWords = Words.Movies;
GameCategory = Category.Movies;
MainGame mg = new MainGame();
mg.ShowDialog();
UpdateEasyCompletedCategories();
}
private void bCities_Click(object sender, EventArgs e)
{
GameWords = Words.Cities;
GameCategory = Category.Cities;
MainGame mg = new MainGame();
mg.ShowDialog();
UpdateEasyCompletedCategories();
}
private void bHouse_Click(object sender, EventArgs e)
{
GameWords = Words.Furniture;
GameCategory = Category.Furniture;
MainGame mg = new MainGame();
mg.ShowDialog();
UpdateEasyCompletedCategories();
}
private void bFigures_Click(object sender, EventArgs e)
{
GameWords = Words.Figures;
GameCategory = Category.Figures;
MainGame mg = new MainGame();
mg.ShowDialog();
UpdateEasyCompletedCategories();
}
private void bSports_Click(object sender, EventArgs e)
{
GameWords = Words.Sports;
GameCategory = Category.Sports;
MainGame mg = new MainGame();
mg.ShowDialog();
UpdateEasyCompletedCategories();
}
And after this you can start playing the game in your desired category, which happens in the MainGame
Form :
public partial class MainGame : Form
{
private static readonly char[] letters =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
private static readonly Button[] LetterButtons = new Button[letters.Length];
private readonly List<Label> WordLettersLabels = new List<Label>();
private readonly string[] categoryWords = GameWords;
private static int hangManState = 0;
private string currentWord;
private static readonly Image[] HangManStateImages =
{
Image.FromFile(@"Assets\States\State1.png"),
Image.FromFile(@"Assets\States\State2.png"),
Image.FromFile(@"Assets\States\State3.png"),
Image.FromFile(@"Assets\States\State4.png"),
Image.FromFile(@"Assets\States\State5.png"),
Image.FromFile(@"Assets\States\State6.png"),
Image.FromFile(@"Assets\States\State7.png"),
Image.FromFile(@"Assets\States\State8.png"),
};
public MainGame()
{
InitializeComponent();
CreateLetterButtons();
ShuffleWords();
currentWord = categoryWords[0];
CreateLetterLabels(currentWord.Length);
DisplayStartingLetters();
lbStage.Text = @"1 " + @"/ " + categoryWords.Length;
}
private void CreateLetterButtons()
{
const int startingHorizontal = 25;
int horizontal = startingHorizontal;
int vertical = 375;
for (int i = 0; i < LetterButtons.Length; i++)
{
LetterButtons[i] = new Button
{
Size = new Size(35, 35),
Location = new Point(horizontal, vertical),
Text = letters[i].ToString(),
Font = new Font("Microsoft Sans Serif", 14),
};
LetterButtons[i].Click += LetterClick;
Controls.Add(LetterButtons[i]);
horizontal += LetterButtons[i].Width + 2;
if (i == 12) //break row
{
vertical += LetterButtons[i].Height + 5;
horizontal = startingHorizontal;
}
}
}
private void CreateLetterLabels(int wordLength)
{
int horizontal = 20;
int vertical = 310;
for (int i = 0; i < wordLength; i++)
{
Label newLetterLabel = new Label
{
Font = new Font("Microsoft Sans Serif", 30),
AutoSize = true,
Text = @"_",
Location = new Point(horizontal, vertical)
};
horizontal += newLetterLabel.Width/2;
Controls.Add(newLetterLabel);
WordLettersLabels.Add(newLetterLabel);
}
}
private void LetterClick(object sender, EventArgs e)
{
Button pressedButton = (Button) sender;
char currentLetter = pressedButton.Text.ToLower()[0];
CheckLetter(currentLetter, pressedButton);
}
private void CheckLetter(char currentLetter, Button pressedButton)
{
if (LetterIsContained(currentLetter))
{
IEnumerable<int> letterPositions = GetLetterPositions(currentLetter);
foreach (int letterPosition in letterPositions)
{
WordLettersLabels[letterPosition].Text = currentLetter.ToString();
}
pressedButton.Dispose();
}
else
{
pbHangman.BackgroundImage = HangManStateImages[hangManState];
hangManState++;
pressedButton.Dispose();
}
if (IsLost)
{
Lost();
return;
}
if (IsFinishedCategory)
{
FinishedCategory();
UpdateCompletedCategories();
Close();
}
if (IsCorrectWord)
{
CorrectWord();
}
}
private bool IsFinishedCategory => IsCorrect() && Array.IndexOf(categoryWords, currentWord) + 1 == categoryWords.Length;
private bool IsCorrectWord => IsCorrect() && Array.IndexOf(categoryWords, currentWord) + 1 < categoryWords.Length;
private static bool IsLost => hangManState == HangManStateImages.Length;
private void CompletedTheGame()
{
if (GameDifficulty == Difficulty.Easy && Properties.Settings.Default.EasyAnimalsCompleted &&
Properties.Settings.Default.EasyCapitalsCompleted && Properties.Settings.Default.EasyCitiesCompleted &&
Properties.Settings.Default.EasyFiguresCompleted &&
Properties.Settings.Default.EasyFoodAndDrinksCompleted &&
Properties.Settings.Default.EasyFurnitureCompleted && Properties.Settings.Default.EasyMoviesCompleted &&
Properties.Settings.Default.EasyObjectsCompleted && Properties.Settings.Default.EasyPlantsCompleted &&
Properties.Settings.Default.EasySportsCompleted)
{
DialogResult dialogResult =
MessageBox.Show(
@"You've finished all the available categories on Easy difficulty!" + Environment.NewLine +
@"Go back to the main menu and try different difficulty.", @"Congratulations");
}
else if (GameDifficulty == Difficulty.Medium && Properties.Settings.Default.MediumAnimalsCompleted &&
Properties.Settings.Default.MediumCapitalsCompleted &&
Properties.Settings.Default.MediumCitiesCompleted &&
Properties.Settings.Default.MediumFiguresCompleted &&
Properties.Settings.Default.MediumFoodAndDrinksCompleted &&
Properties.Settings.Default.MediumFurnitureCompleted &&
Properties.Settings.Default.MediumMoviesCompleted &&
Properties.Settings.Default.MediumObjectsCompleted &&
Properties.Settings.Default.MediumPlantsCompleted &&
Properties.Settings.Default.MediumSportsCompleted)
{
DialogResult dialogResult =
MessageBox.Show(
@"You've finished all the available categories on Medium difficulty!" + Environment.NewLine +
@"Go back to the main menu and try different difficulty.", @"Congratulations");
}
else if (GameDifficulty == Difficulty.Hard && Properties.Settings.Default.HardAnimalsCompleted &&
Properties.Settings.Default.HardCapitalsCompleted &&
Properties.Settings.Default.HardCitiesCompleted &&
Properties.Settings.Default.HardFiguresCompleted &&
Properties.Settings.Default.HardFoodAndDrinksCompleted &&
Properties.Settings.Default.HardFurnitureCompleted &&
Properties.Settings.Default.HardMoviesCompleted &&
Properties.Settings.Default.HardObjectsCompleted && Properties.Settings.Default.HardPlantsCompleted &&
Properties.Settings.Default.HardSportsCompleted)
{
DialogResult dialogResult =
MessageBox.Show(
@"You've finished all the available categories on Hard difficulty!" + Environment.NewLine +
@"Go back to the main menu and try different difficulty.", @"Congratulations");
}
Close();
}
private void FinishedCategory()
{
CompletedTheGame();
DialogResult dialogResult =
MessageBox.Show(
@"You've finished all the available word for this category !" + Environment.NewLine +
@"Go back to the main menu and pick another category.", @"Congratulations");
Close();
}
private void CorrectWord()
{
DialogResult dialogResult =
MessageBox.Show(
@"Good job you got the word correctly !" + Environment.NewLine +
@"Would you like to move to the next word ?", @"Congratulations", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
currentWord = categoryWords[Array.IndexOf(categoryWords, currentWord) + 1];
lbStage.Text = Array.IndexOf(categoryWords, currentWord) + 1 + @" / " + categoryWords.Length;
Reset();
}
}
private void Lost()
{
DialogResult dialogResult =
MessageBox.Show(
@"You've lost your progress on the current category !" + Environment.NewLine +
@"Would you like to try again ?", @"You've lost", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
ShuffleWords();
currentWord = categoryWords[0];
lbStage.Text = Array.IndexOf(categoryWords, currentWord) + 1 + @" / " + categoryWords.Length;
Reset();
}
}
private bool IsCorrect()
{
string formedWord = WordLettersLabels.Aggregate(string.Empty, (current, wordLettersLabel) => current + wordLettersLabel.Text);
return formedWord == currentWord.ToLower();
}
private void Reset()
{
for (int i = 0; i < LetterButtons.Length; i++)
{
LetterButtons[i].Dispose();
LetterButtons[i] = null;
}
foreach (var wordLettersLabel in WordLettersLabels)
{
wordLettersLabel.Dispose();
}
WordLettersLabels.Clear();
CreateLetterButtons();
CreateLetterLabels(currentWord.Length);
DisplayStartingLetters();
pbHangman.BackgroundImage = null;
hangManState = 0;
}
private IEnumerable<int> GetLetterPositions(char inputLetter)
{
List<int> letterPositions = new List<int>();
for (int i = 0; i < currentWord.Length; i++)
{
if (currentWord.ToLower()[i] == inputLetter)
{
letterPositions.Add(i);
}
}
return letterPositions.ToArray();
}
private bool LetterIsContained(char inputLetter) => currentWord.ToLower().Contains(inputLetter);
private void DisplayStartingLetters()
{
switch (GameDifficulty)
{
case Difficulty.Easy:
WordLettersLabels[0].Text = currentWord[0].ToString().ToLower();
WordLettersLabels[WordLettersLabels.Count - 1].Text = currentWord[currentWord.Length - 1].ToString().ToLower();
break;
case Difficulty.Medium:
WordLettersLabels[0].Text = currentWord[0].ToString().ToLower();
break;
}
}
private void ShuffleWords()
{
Random random = new Random();
for (int i = categoryWords.Length; i > 0; i--)
{
int j = random.Next(i);
string k = categoryWords[j];
categoryWords[j] = categoryWords[i - 1];
categoryWords[i - 1] = k;
}
}
private static void UpdateCompletedCategories()
{
switch (GameDifficulty)
{
case Difficulty.Easy:
switch (GameCategory)
{
case Category.Capitals:
Properties.Settings.Default.EasyCapitalsCompleted = true;
break;
case Category.FoodAndDrinks:
Properties.Settings.Default.EasyFoodAndDrinksCompleted = true;
break;
case Category.Animals:
Properties.Settings.Default.EasyAnimalsCompleted = true;
break;
case Category.Plants:
Properties.Settings.Default.EasyPlantsCompleted = true;
break;
case Category.Objects:
Properties.Settings.Default.EasyObjectsCompleted = true;
break;
case Category.Movies:
Properties.Settings.Default.EasyMoviesCompleted = true;
break;
case Category.Furniture:
Properties.Settings.Default.EasyFurnitureCompleted = true;
break;
case Category.Cities:
Properties.Settings.Default.EasyCitiesCompleted = true;
break;
case Category.Figures:
Properties.Settings.Default.EasyFiguresCompleted = true;
break;
case Category.Sports:
Properties.Settings.Default.EasySportsCompleted = true;
break;
}
break;
case Difficulty.Medium:
switch (GameCategory)
{
case Category.Capitals:
Properties.Settings.Default.MediumCapitalsCompleted = true;
break;
case Category.FoodAndDrinks:
Properties.Settings.Default.MediumFoodAndDrinksCompleted = true;
break;
case Category.Animals:
Properties.Settings.Default.MediumAnimalsCompleted = true;
break;
case Category.Plants:
Properties.Settings.Default.MediumPlantsCompleted = true;
break;
case Category.Objects:
Properties.Settings.Default.MediumObjectsCompleted = true;
break;
case Category.Movies:
Properties.Settings.Default.MediumMoviesCompleted = true;
break;
case Category.Furniture:
Properties.Settings.Default.MediumFurnitureCompleted = true;
break;
case Category.Cities:
Properties.Settings.Default.MediumCitiesCompleted = true;
break;
case Category.Figures:
Properties.Settings.Default.MediumFiguresCompleted = true;
break;
case Category.Sports:
Properties.Settings.Default.MediumSportsCompleted = true;
break;
}
break;
case Difficulty.Hard:
switch (GameCategory)
{
case Category.Capitals:
Properties.Settings.Default.HardCapitalsCompleted = true;
break;
case Category.FoodAndDrinks:
Properties.Settings.Default.HardFoodAndDrinksCompleted = true;
break;
case Category.Animals:
Properties.Settings.Default.HardAnimalsCompleted = true;
break;
case Category.Plants:
Properties.Settings.Default.HardPlantsCompleted = true;
break;
case Category.Objects:
Properties.Settings.Default.HardObjectsCompleted = true;
break;
case Category.Movies:
Properties.Settings.Default.HardMoviesCompleted = true;
break;
case Category.Furniture:
Properties.Settings.Default.HardFurnitureCompleted = true;
break;
case Category.Cities:
Properties.Settings.Default.HardCitiesCompleted = true;
break;
case Category.Figures:
Properties.Settings.Default.HardFiguresCompleted = true;
break;
case Category.Sports:
Properties.Settings.Default.HardSportsCompleted = true;
break;
}
break;
}
Properties.Settings.Default.Save();
} // this needs to be shorten
private void MainGame_KeyPress(object sender, KeyPressEventArgs e)
{
foreach (var letterButton in LetterButtons)
{
if (e.KeyChar == letterButton.Text.ToLower()[0])
{
CheckLetter(e.KeyChar, letterButton);
}
}
}
}
Here I have a few ugly methods which are performing operations with the Properties.Settings.Default
because I cant seem to find a way to pack them in some collection. If something is unclear I will happily answer in the comments. I'm looking for answer's concerning the code style and ideas on how to shorten the long methods or overall how to shorten the code.