Search

Coding a model(part 1)

One of first steps I do when designing a game is code a model to test the mechanics. In part 1 we will code a model for a simple game and use that model to identify a problem. The value of writing a model is two fold you can find some hard to find problems (Dead Locks, Starvation, and infinite loops) but it also forces you to reduce the concepts of a game to pure mechanics. We're going to use a dirt simple game we all know to avoid having to learn a new game while learning to code. So were going to code a model for war.

Code reference by this blog here


Rules

The Base Line Code

So this example is based in Java, Maven and JUnit but by no means is that the only choice, its just one flavor. When writing a simulation start with two categories of items(Components and Concepts):


Components

Components are items that will ultimately be physical parts, collections of physical parts or a location in the game. To simulate War we only needed two:


Card

A card is the most basic element and has two values, rank (2,3,4,5,6,7,8,9,10,J,Q,K,A) and Suit(spade,club,heart,diamond). If you really boil it down, you don’t need suit for the base game of war but it is an element of the card. In java the use of an enum for the suit has performance benefits when comparing but you could use a string or a simple char just as well.

Deck

A deck is a simple collection of cards. The only important thing you need to decide on is does order of the collection matter. In this case it does so ArrayList is one option but a Queue might be more apt and you would have to less direct index manipulation.

Concepts

Concepts are any other part of the game and mechanics parts that have to make decisions or carry a larger state changes. Concepts should be light on data elements big on methods.

The base line simulation has two.


Player

The player has their own deck (deck being a collection of cards not a full deck) and a name so we tell them apart.

  • accept(Card) – take a card and add it to your deck

  • accept(Deck) – take a full deck and add it to your own

  • accept(List<Card>) – take a collection of a cards and add it your deck

  • topCard() – give me your top card

  • topCard(int) – give me your top x cards


Game

The game class represents one full play through. We have a list of players and some variables were going to use to count events

  • addPlayer(Player) – add a player to the game

  • deal() – build the main deck and distribute it o the players

  • isGameOver() – return true if the game has ended

  • playOneRound() – starts the playing of one round of the game

  • playOneRound(List<Card>) – recursive function because war can stack

  • findHighCardPlayer(Map<Player, Card>) – look at the cards played and find the winner

Exceptions

Exceptions are great for simulating and tracking events. Two advantages is they are easy to catch and record and if you throw one from a method the code will force you to deal with all the points it touches. You may see interactions you didn’t consider.


WarException

Thrown if the ranks of two cards match. Then when caught we go down a different path of logic for that situation



BoredomException

Always include this type of exception, it always pays dividends in the analysis, in this case it will be the crux of the problem. if the round count goes over 1000 throw this exception, basically representing players getting feed up with game and quitting.


OutOfCardsException

Thrown when a player draws there top card but is out of cards, this signifies them losing and the catch logic ends the game


Putting the elements in motion

JUnits give us a gram work to write test for our code. They are already designed to exercise cod and that's all we need to do now that we have the classes built.


The Single game test:

Run this test a lot before going on to the next test. Because randomization(pseudo randomization, sorry computers can’t really be random) you won’t find everything on the first pass.

The structure is very simple.

  1. Instantiate a game

  2. add two players

  3. deal the cards

  4. loop until the game ends – every 50 rounds print the status of the game

  5. output the details

Output:


Ten Thousand Game Test

So our single player game is going well we have run it like 50 times, lets scale it up so we can get some real data, good data needs a large sample size.


Output:

Conclusion

If nearly half the games played ended with players quitting, that's a pretty boreing game. When testing for this kind of condition you have to decide on your own threshold. Its nice if you can eliminate the condition completely but if 10 games in 10,000 show it that's not statistically significant. So in part two well try adding some house rules to fix war.

10 views

© 2020 by Double Watt Games