Room and Board

When the board gets created, we want to create the spaces in it in the same order every time. Remember that the basic spaces go in that standard pattern, and we can just insert the speciality, licorice, and shortcut spaces where they go.

The code that creates the spaces into their collection looks like this:

CardDeck has three methods we'll need to flesh out: CreateDeck, Shuffle, and Draw.

For CreateDeck, we want to create the same number, type, and amount of cards that would be found in a regular real-world Candy Land set. I counted all the cards in my set and found the following numbers:

Let's start with the cards. I copied down the contents of all our cards and came up with the following numbers:

CandyColor

Value

Count

Red

1

6

Orange

1

6

Yellow

1

6

Green

1

6

Blue

1

6

Purple

1

5

Red

2

4

Orange

2

4

Yellow

2

4

Green

2

3

Blue

2

3

Purple

2

4

Star

1

1

Ice Cream

1

1

Gingerbread

1

1

Lollipop

1

1

Ice Pop

1

1

Chocolate

1

1

Ice Pop

1

1

The total cards we have is 64, which matches what my instruction manual tells me, so we're good to go. Now we can fill in the CreateDeck method that will create a standard, unshuffled deck of cards.

However, that's not going to be much fun, since the cards will always appear in that order. Just like with real-world cards, we want to shuffle these cards, and to do so we can use an algorithm known as the Fisher-Yates shuffle:

public void Shuffle()
{
Random rng = new Random();
int length = Cards.Count;
while (length > 1) //Cycle through each card in order
{
length--;
int k = rng.Next(length + 1); //Random number 1-64
Card value = Cards[k]; //Remove the card at that index from the deck
Cards[k] = Cards[length]; //Take the card from the current index and place it at the randomized index
Cards[length] = value; //Take the card from the randomized index and place it at the current index.
}
}

This results in a good (but not perfect) shuffle, and it'll suit our needs.

We still have one method to work out, and that's Draw(). When a person draws a card in real life, that card is removed from the draw pile. However, we don't want to run into a situation where we have no cards to draw, so we need to account for that as well. Here's the code:

Take Turns, Children

With the Board and Cards created and our GetMatchingSpace extension ready, we now need a way to have a Player conduct their turn. We also need a way to make sure the Players take their turns in order, and we'll get to that in a little bit.

In order for a player to take their turn, they need to know the spaces on the board and the deck of cards. We also want this method to return a description of what happened on that turn, so that we can write the message to the console. Hence our method signature will look like this:

public string TakeTurn(Board board, CardDeck deck)
{
}

When it is a player's turn, several things can happen.

If the player landed on a licorice space on his turn immediately prior, then his turn is skipped.

If a player landed on a shortcut space, s/he immediately takes the shortcut.

With that in place, we are ready to write the final piece of our solution: the Game object.

Game On!

The Game object will keep track of the players, the board spaces, and the deck of cards. It will also need to know which player is next, and whether or not the game has started. Finally, we'll create methods to add players, to start the game, and to run the next move.

Start with AddPlayer and StartGame. We can't play a game without at least 2 players, but we can't have more than 4. Also, we can't add players to a game once the game has been started. Therefore, these two method look like this:

In the final method, NextMove, we need to tell the current player to take their turn, then process what that turn was. We also need to tell the next player that their turn is coming up. That method looks like this:

Finally, we've gotten the last piece in place! The Candy Land simulation is complete!

I've written up a command-line program so that you can run this simulation however you like, grab it from GitHub.

I'm hoping to do some more advanced things with this simulation, like maybe calculating the shortest possible path for a single player, or the maximum number of turns a game would take (I'd be willing to bet that given perfectly bad shuffles, the game would never end). If anybody has any ideas, hit me up in the comments or on Twitter.