HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Hangman Game in windows forms

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
formswindowsgamehangman

Problem

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",

Solution

A Single "Difficulty" Event Handler

Extend EventArgs so you can pass Difficulty.

public class HangEventArgs : EventArgs {
   public Difficulty challenge {get; set;}
}

// one handler to rule them all
private void Difficulty_Click(object sender, HangEventArgs e)
{
    GameDifficulty = e.challenge;
    ChapterSelection cs = new ChapterSelection();
    cs.ShowDialog();
}


More HangEventArgs Goodness

Same idea as above. BONUS: new categories use this handler too.

public class HangEventArgs : EventArgs {
   public Difficulty Challenge {get; set;}
   public Category Jeopardy {get; set;}
}

private void Category_Click(object sender, HangEventArgs e)
{
    GameWords = Words.Capitals;      // this will be dealt with below
    GameCategory = e.Jeopardy;
    MainGame mg = new MainGame();
    mg.ShowDialog();
    UpdateEasyCompletedCategories();  // this will be dealt with below
}


Data Structure Simplifies Everything

By data structure I mean a class design making the hangman data accessible. You almost got this with the GeneralSettings class. But we need instances.

The big insight to all of this is that there are not "easy difficulty", "medium difficulty", etc. There is just a "difficulty". Likewise with categories. And the enums say as much.

public class HangData {
    // moved the enums out
    // enums do not need to be inside of a class. They can be
    //    defined in the namespace.

    public Difficulty GameDifficulty { get; protected set; }
    public Category   GameCategory   { get; protected set; }
    public string[]   GameWords      { get; protected set; }

    public HangData (Difficulty howHard, Category askWhat) {
         GameDifficulty  = howHard;
         GameCategory    = askWhat;
         GameWords = GetGameWords(); 
    }        

    protected string[] GetGameWords() { // do it } 
}


Meanwhile, back at the Category_Click Handler

private void Category_Click(object sender, HangEventArgs e)
{
    MainGame mg = new MainGame( new HangData(e.Challenge, e.Jeopardy));
    mg.ShowDialog();
    UpdateEasyCompletedCategories();  // this will be dealt with below
}


Back to HangData class

Put the "completed" properties in here too.

public class HangData {
    public bool CapitalsCompleted {get; set;}
    // et cetera

    public HangData (Difficulty howHard, Category askWhat) {
        // all the earlier stuff, then
        SetCategoryCompleteFlags();
    }

    protected void SetCategoryCompleteFlags() { // whatever it takes }
}


At this point I'm not seeing a use for a collection of these flags.

One UpdateCompletedCategories() method

private void UpdateCompletedCategories() {
    cbCapitals.Checked = myHangData.CapitalsCompleted;
    // et cetera
}


You're going to use this in the category click event handler (not shown).

MainGame

I'm not going into the nit-picking of code changes, but note:

  • Don't need properties like categoryWords. It's all neatly encapsulated in HangData



  • The matrix of properties and methods named: "hard/med/easy" combined with every category - goes away.



  • The letters static property might best be put into HangData. Try it out and see how it feels.



The Big Picture

We made a data structure for the more abstract ideas of "difficulty" and "category" (vice "easy capitals" for example). This very dramatically reduced code volume and simplified client code.

Code Snippets

public class HangEventArgs : EventArgs {
   public Difficulty challenge {get; set;}
}

// one handler to rule them all
private void Difficulty_Click(object sender, HangEventArgs e)
{
    GameDifficulty = e.challenge;
    ChapterSelection cs = new ChapterSelection();
    cs.ShowDialog();
}
public class HangEventArgs : EventArgs {
   public Difficulty Challenge {get; set;}
   public Category Jeopardy {get; set;}
}

private void Category_Click(object sender, HangEventArgs e)
{
    GameWords = Words.Capitals;      // this will be dealt with below
    GameCategory = e.Jeopardy;
    MainGame mg = new MainGame();
    mg.ShowDialog();
    UpdateEasyCompletedCategories();  // this will be dealt with below
}
public class HangData {
    // moved the enums out
    // enums do not need to be inside of a class. They can be
    //    defined in the namespace.

    public Difficulty GameDifficulty { get; protected set; }
    public Category   GameCategory   { get; protected set; }
    public string[]   GameWords      { get; protected set; }

    public HangData (Difficulty howHard, Category askWhat) {
         GameDifficulty  = howHard;
         GameCategory    = askWhat;
         GameWords = GetGameWords(); 
    }        

    protected string[] GetGameWords() { // do it } 
}
private void Category_Click(object sender, HangEventArgs e)
{
    MainGame mg = new MainGame( new HangData(e.Challenge, e.Jeopardy));
    mg.ShowDialog();
    UpdateEasyCompletedCategories();  // this will be dealt with below
}
public class HangData {
    public bool CapitalsCompleted {get; set;}
    // et cetera

    public HangData (Difficulty howHard, Category askWhat) {
        // all the earlier stuff, then
        SetCategoryCompleteFlags();
    }

    protected void SetCategoryCompleteFlags() { // whatever it takes }
}

Context

StackExchange Code Review Q#127558, answer score: 2

Revisions (0)

No revisions yet.