Long time readers of this blog know that I'm a fan of board and card games, and specifically of modeling them as C# executable programs. In the past, we've modeled Uno, Candy Land, Minesweeper, and most recently Battleship. For this next edition of the Modeling Practice series, we're turning our attention to a much-beloved (and sometimes much-derided) card game: War.
Try It Yourself!
Before we get started on how to do this, it's important to understand why we're doing this. See, I want you, my dear readers who think they need a bit more practice designing and implementing complex applications, to attempt to model War in C# first, and then come read this series of posts. That way, you get both the experience of working through and modeling this problem yourself, and a bit of a sanity-check in comparing your solution to mine. You might even find a better solution than I do, and if you do so, I want to know about it, so share in the comments!
If, however, you still want to see one way we might model War in C#, read on...
The Sample Project
Check out the sample project for this series over on GitHub!
I De-Clare War!
War is a two-player card game, played with a standard 52-card deck. Each player starts with a shuffled half of that deck, and they do not look through their deck or know what card is on top of it. On each turn, each player flips over their top card. Whichever player has the card with the higher value (counting Aces as higher than Kings) gets both cards added to the bottom of his/her deck.
If both players flip over a card with the same value, a War is declared. In a War, each player places three cards face down on the table, and a fourth card face up. (Often this sequence is remembered using the mnemonic "1, 2, 3, 4, I De-Clare War" with a card being placed on the table for each of the last four syllables.) Whichever player has the higher value of this fourth card gets all the cards on the table, including the face-down ones. If the face-up cards have the same value, another war happens, and so on, until a winner is found.
Play continues like the above until one player "owns" all of the cards in the deck. That player is de-clared the winner.
So, to summarize:
- Each player gets half a shuffled deck of cards
- Aces are higher than Kings
- Players flip one card at a time, highest card wins
- If flipped cards are same value, a War is declared
- War is played until a player wins all cards on table
- The first player to run out of cards loses.
From the rules above, we can make a few observations.
First off, War is not deterministic, unlike Candy Land. In Candy Land, once all of the cards have been shuffled and the play order determined, we already know who the winner will be. In real-life War, because of the shuffled deck and no rule which states in what order won cards must be added to a player's deck, the outcome cannot be known at the start; and hence the game cannot be deterministic. We will need to account for this in our model, either by declaring an order in which won cards will be added to the winner's deck (and thus making the game deterministic), or by making that pickup random (and thus closer to its real-life version).
Secondly, it is entirely possible to have an infinite game of War. A poster on MathOverflow shows us that, for a particular order of cards (and enforcing the order of pickup on won cards) you can pretty easily have an infinite game of War. These kinds of games will not be useful to our model, so we will need a way to handle them.
Finally, we need to handle the situation in which a player does not have enough cards in their hand to complete a War. The "official" rules (inasmuch as such things exist for this particular game) do not specify what happens in this scenario, so we as the project architects need to account for what occurs here.
Given the rules and observations above, we can start making decisions as to what kinds of objects we will need to model in C# for our War-playing application.
First off, we will need a Card object, and a Deck object to contain these Cards.
Next, we'll need a Player object, to represent the two players the game requires.
Finally, we'll need a Game object, to represent and manage the game being played.
So, we need four objects:
In the next part of this series, we will use these objects to create and run a War-playing C# application. Stay tuned!
If you'd like to get a sneak peak of how I ended up modeling War as a C# application, check out the sample project over on GitHub. As always, comments and feedback about this project and series are welcomed!