Assignment 5: Headless Game

A headless program is one that runs with a UI. It can be useful to design an interactive program (like a game) to be able to run headless in order to expedite testing, run in batch, run across networks and/or run against bots.

For this week's labs and assignments, we'll finish the headless version of the Nine Card Golf game. Your submission will have the specified game classes, unit tests for all the methods and a main method that runs a single two-player game at the console with random player actions.

Starting with your code from last week, commit your work to this new repository:

https://cssvn.utrgv.edu/svn_etomai/201810_3328/assn05_headless/<username>

The Rules

Shuffle one or more standard 52 card decks (with Jokers).

Deal 9 cards to each player, the rest of the deck is the draw pile. Flip the top card from the deck to start the discard pile.

Each player organizes their cards face down without looking at them in a 3x3 grid on the table (the hand). Each player turns any 3 of their cards face up.

Each player in turn:

  • Draw the top card from either the deck (face down) or the discard pile (face up).
  • Look at that card and replace any card (face down or face up) in your hand. The new card is face up, the replaced card is added to the top of the discard pile (face up).

When any player flips their last card face up, the game is over. Score the hands and declare the player with the lowest score the winner.

To score, add the values of all the cards in the hand:

  • Aces are worth 1 point
  • 2-10 are worth their face value
  • J, Q are worth 10 points
  • K are worth 0 points
  • Jokers are worth -2 points
  • Any three cards in a row, column or diagonal with the same value (e.g. three aces) cancel out and are all worth 0 points.

Classes and Methods

Your program must have the following classes and methods, as we discussed in lab time:

Card and Deck from the past assignment, plus these additional Deck methods:

  • Add: add a card to the top of the deck
  • IsEmpty: returns True if the deck is empty
  • Peek: return the card at a specified position without removing it (needed for testing and will be needed for the GUI eventually)

Hand

  • Add: add a card to the hand, facedown in the next position in the 3x3 grid
  • Peek: return the card at a specified position without removing it (needed for testing and will be needed for the GUI eventually)
  • TurnUp: change the card at the specified position from face down to face up
  • IsFaceUp: returns True if the card at the specified position is face up
  • Replace: add a card face up to the hand at a specified position and remove and return the card that was there; can also return True/False (by reference) to indicate whether all cards in the hard are now face up
  • IsDone: alternatively, can have this separate method to indicate whether all cards in the hand are now face up
  • Score: return the total score for the hand

Player

  • TakeTurn: play out a single turn for this player
  • ChooseDrawDiscard: bot decision-making, returns True to indicate draw from discard, False to indicate draw from the deck
  • ChooseReplace: bot decision-making, returns which card position in the hand to replace with the current draw

To start, the two Choose* methods should return randomly. However, not completly randomly, as that could make for very long games. Intead, have ChooseReplace follow a two-step process:

  1. Randomly choose whether to replace a face up or face down, with a bias to choose face down
  2. Randomly choose which one

Game

  • Game(): constructor, to setup all the necessary objects
  • Play: main loop function that plays a complete game

Testing

Create Unit Tests for all the Deck and Hand methods. The Player methods would require much more complex, sample-based testing to see if they are making reasonable moves (spoiler: they're not) and the Game methods require interactive testing, which is beyond the scope of unit testing.

Remember that in Visual Studio 2017, you must choose a .Net Framework project rather than .Net Core. Otherwise you won't have access to the unit test tools.

The Game

When you run your main program, it should play out a complete game between two random bots. After each turn, print the two hands to the console, like this (note Jk is Joker, and the 5 of Hearts is the discard):

====================
2D  7H  XX
XX  7S  JC
QC  XX  XX
---> 5H
4H  XX  XX
XX  Jk  AS
3D  XX  XX
====================

At the end of the game, display the final scores.

Committing

As with the GUI assignment, you'll need to commit the whole solution here. That means both project subdirectories! Please delete the obj and bin directories from both. VS2017 additionally creates frameworks subdirectories which should also not be committed (if you can't find them, don't worry about it this time).