We are going to write a program to play the popular and simple card game of Blackjack. Specifically, your program is going to play the role of dealer, and the user interface will the user(s) to be the players against the dealer.
In our version of the game, we will rely on standard playing cards. More specifically, a game of Blackjack will rely on a shoe of cards, where multiple decks are shuffled together. Thus, if 5 decks are used, then there will be 52 * 5 = 260 cards total, with 5 aces of spades, 5 jacks of clubs, etc.
We are going to use a reasonably simplified set of the rules of Blackjack to avoid needless complexity. Here is how a game progresses:
Each player places a bet.
The dealer gives two cards to each player, face-up.
The dealer gives itself two cards, one face-up, and the other face-down (the hole card).
One player at a time, the dealer allows each player to hit (be dealt another card) as many times as the player chooses until either:
The player chooses to stay (be dealt no more cards), or...
The player busts (has a hand whose value is more than 21, even with aces interpreted as being worth 1).
Once the player stays or busts, the player's turn is over.
The dealer reveals its hole card, and then proceeds to hit (deal cards to its own hand) until either:
The dealer's hand is worth at least 17 point (even if that value is reached by interpreting an ace as being worth 11), or...
The dealer busts (has a hand worth more than 21, even with aces interpreting as being worth 1).
Bets are then handled depending on the outcome of the hands. Specifically:
Player wins: The player did not bust, and either the dealer did bust, or the player has a hand worth more than the dealer's. Here, the dealer must pay the player a reward equal to her bet.
Dealer wins: The player busts (irrespective of whether the dealer also busts), or the dealer has a hand worth more than the player's. Here, the dealer takes the player's bet.
Push: If neither player nor dealer busts, and both player and dealer have hands of equal value, then neither wins. Here, the player retains her bet without being paid anything additional.
If the player is out of money or chooses not to play again, the player's game is then done.
This project requires a number of classes -- some free-standing, others based on inheritance relationships. Below are a list of the classes and descriptions of their roles in this program. I have ordered them roughly from the top down (that is, higher-level to lower-level).
Blackjack: This class should contain the main() method that starts the program. It should create a Blackjack object that then plays the actual game. Specifically, it is this object that should coordinate the Dealer and the Players, and control the progression of the game itself.
Dealer: A Dealer object should hold a Hand of Cards. It should contain the code to play out its own hand, taking hits as described in the rule above. It should be able to compare its result to a Player and then determine how the bets and payouts are handled with that Player. Moreover, the Dealer should have a Shoe and be capable of distributing cards to a Player from that Shoe of Cards.
Player: There should also be a Hand to go with each Player object. It should provide a text interface to the player, allow her to hit or stay according to the rules above. It should keep track of how much money a player has, and how much has been bet on a given hand.
Shoe: A collection of arbitrarily many Cards. It should be possible to fill a Shoe with whichever Cards one desires. The Shoe should be capable of shuffling these cards into a random permutation. Finally, a Shoe should track how many cards are left since the last shuffle operation. Upon shuffling, the Shoe should pick a number between 0.5 and 0.75. When that more than that fraction of the Cards have been removed from the Shoe, it should note that, upon the next request, it should indicate that it does need to be refilled and shuffled again. It is up to the holder of the Shoe, once a hand has been played, to check the Shoe and see if refill-and-reshuffle must be performed.
Deck: A standard collection of 52 Cards. Used primarily to generate new Cards in the correct proportion, full Decks should be inserted into a Shoe be extracting all Cards from the former and inserting them into the latter.
Card: A single card from a standard playing deck. That is, it holds a suit (spade, club, diamond, or heart) and a rank (Ace, 2 through 9, Jack, Queen, or King).
CardContainer/ArrayCardContainer/ListCardContainer: The abstract class CardContainer defines an interface for a linear container for Cards. A Shoe should use a CardContainer to hold its Cards, which should provide the Shoe with the ability to insert, access, and/or remove Cards. Exactly what that interface needs to do is up to you.
The two non-abstract subclasses, ArrayCardContainer and ListCardContainer, implement the interface of CardContainer by using an array and a linked list, respectively. How they implement the necessary methods is up to you.
List/ListNode/ListIterator: The ListCardContainer should use a generic linked list implementation to store its Cards. Specifically, you should write your own such generic container. A List object should create a maintain a collection of ListNodes that store the data inserted into the list. Access to the list should be allowed only through a ListIterator, a kind of "smart pointer" that itself points directly to a ListNode, but only allows limited access to the ListNode. Specifically, methods outside of these three should have no way to change the pointers within a node.
When a user runs this program, she will have to specify a number of items on the command line. Specifically, here is the usage for the program:
java Blackjack [number of decks] [number of players] [container type (Array, List)] [initial money per player]
From within your project-5 subdirectory, use the following command to submit you work (all of your Java code files) when you are done:
cs12-submit project-5 *.java