Clean up comments and convert Card to a record

This commit is contained in:
Mitch Peck
2022-03-18 12:52:14 -05:00
parent 88202ec9be
commit 0b1f809707
3 changed files with 21 additions and 43 deletions

View File

@@ -1,37 +1,27 @@
/** /**
* This is an example of an "immutable" class in Java. That's just a fancy way * This is an example of an "record" class in Java. That's just a fancy way
* of saying the properties (value and suit) can't change after the object has * of saying the properties (value and suit) can't change after the object has
* been created (it has no 'setter' methods and the properties are 'final'). * been created (it has no 'setter' methods and the properties are implicitly 'final').
* *
* Immutability often makes it easier to reason about code logic and avoid * Immutability often makes it easier to reason about code logic and avoid
* certain classes of bugs. * certain classes of bugs.
* *
* Since it would never make sense for a card to change in the middle of a game, * Since it would never make sense for a card to change in the middle of a game,
* this is a good candidate for immutability. * this is a good candidate for immutability.
*
*/ */
// TODO consider making this a Record record Card(int value, Suit suit) {
public final class Card {
public enum Suit { public enum Suit {
HEARTS, DIAMONDS, SPADES, CLUBS; HEARTS, DIAMONDS, SPADES, CLUBS;
} }
// Since this class is immutable, there's no reason these couldn't be public Card {
// 'public', but the pattern of using 'getters' is more consistent with
// typical Java coding patterns.
private final int value;
private final Suit suit;
public Card(int value, Suit suit) {
if(value < 1 || value > 13) { if(value < 1 || value > 13) {
throw new IllegalArgumentException("Invalid card value " + value); throw new IllegalArgumentException("Invalid card value " + value);
} }
if(suit == null) { if(suit == null) {
throw new IllegalArgumentException("Card suit must be non-null"); throw new IllegalArgumentException("Card suit must be non-null");
} }
this.value = value;
this.suit = suit;
} }
public int getValue() { public int getValue() {

View File

@@ -1,6 +1,5 @@
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.text.DecimalFormat; import java.text.DecimalFormat;
@@ -45,8 +44,7 @@ public class Game {
deck.reshuffle(); deck.reshuffle();
Player dealer = new Player(0); //Dealer is Player 0 - this can be converted into a dealer class later on Player dealer = new Player(0); //Dealer is Player 0
List<Player> players = new ArrayList<>(); List<Player> players = new ArrayList<>();
for(int i = 0; i < nPlayers; i++) { for(int i = 0; i < nPlayers; i++) {
@@ -121,15 +119,14 @@ public class Game {
/** /**
* Print the cards for each player and the up card for the dealer. * Print the cards for each player and the up card for the dealer.
* Prints the initial deal in the following format:
*
* PLAYER 1 2 DEALER
* 7 10 4
* 2 A
*/ */
private void printInitialDeal(List<Player> players, Player dealer) { private void printInitialDeal(List<Player> players, Player dealer) {
// Prints the initial deal in the following format:
/*
PLAYER 1 2 DEALER
7 10 4
2 A
*/
StringBuilder output = new StringBuilder(); StringBuilder output = new StringBuilder();
output.append("PLAYERS "); output.append("PLAYERS ");
for (Player player : players) { for (Player player : players) {
@@ -234,7 +231,6 @@ public class Game {
* @param players * @param players
* @return boolean whether the dealer should play * @return boolean whether the dealer should play
*/ */
protected boolean shouldPlayDealer(List<Player> players){ protected boolean shouldPlayDealer(List<Player> players){
for(Player player : players){ for(Player player : players){
int score = ScoringUtils.scoreHand(player.getHand()); int score = ScoringUtils.scoreHand(player.getHand());
@@ -256,24 +252,21 @@ public class Game {
* *
* DEALER HAS A 5 CONCEALED FOR A TOTAL OF 11 * DEALER HAS A 5 CONCEALED FOR A TOTAL OF 11
* DRAWS 10 ---TOTAL IS 21 * DRAWS 10 ---TOTAL IS 21
* *
* TODO find out if the dealer draws on a "soft" 17 (17 using an ace as 11) or not in the original basic code.
*
* @param dealerHand * @param dealerHand
* @return
*/ */
protected void playDealer(Player dealer) { protected void playDealer(Player dealer) {
int score = ScoringUtils.scoreHand(dealer.getHand()); int score = ScoringUtils.scoreHand(dealer.getHand());
userIo.println("DEALER HAS " + dealer.getHand().get(1).toProseString() + " CONCEALED FOR A TOTAL OF " + score); userIo.println("DEALER HAS " + dealer.getHand().get(1).toProseString() + " CONCEALED FOR A TOTAL OF " + score);
if(score < 17){ if(score < 17){
userIo.print("DRAWS "); userIo.print("DRAWS");
} }
while(score < 17) { while(score < 17) {
Card dealtCard = deck.deal(); Card dealtCard = deck.deal();
dealer.dealCard(dealtCard); dealer.dealCard(dealtCard);
score = ScoringUtils.scoreHand(dealer.getHand()); score = ScoringUtils.scoreHand(dealer.getHand());
userIo.print(dealtCard.toString() + " "); userIo.print(" " + String.format("%-4s", dealtCard.toString()));
} }
if(score > 21) { if(score > 21) {
@@ -285,19 +278,15 @@ public class Game {
/** /**
* Evaluates the result of the round, prints the results, and updates player/dealer totals. * Evaluates the result of the round, prints the results, and updates player/dealer totals.
*
* PLAYER 1 LOSES 100 TOTAL=-100
* PLAYER 2 WINS 150 TOTAL= 150
* DEALER'S TOTAL= 200
*
* @param players * @param players
* @param dealerHand * @param dealerHand
*/ */
protected void evaluateRound(List<Player> players, Player dealer) { protected void evaluateRound(List<Player> players, Player dealer) {
/*
PLAYER 1 LOSES 100 TOTAL=-100
PLAYER 2 WINS 150 TOTAL= 150
DEALER'S TOTAL= 200
*/
// this should probably take in a "Dealer" instance instead of just the dealer hand so we can update the dealer's total.
// currentBets of each player are added/subtracted from the dealer total depending on whether they win/lose (accounting for doubling down, insurance etc.)
// remember to handle a "PUSH" when the dealer ties and the bet is returned.
DecimalFormat formatter = new DecimalFormat("0.#"); //Removes trailing zeros DecimalFormat formatter = new DecimalFormat("0.#"); //Removes trailing zeros
for(Player player : players){ for(Player player : players){
int result = ScoringUtils.compareHands(player.getHand(), dealer.getHand()); int result = ScoringUtils.compareHands(player.getHand(), dealer.getHand());
@@ -328,7 +317,7 @@ public class Game {
if(totalBet < 0) { if(totalBet < 0) {
userIo.print(" LOSES " + String.format("%6s", formatter.format(Math.abs(totalBet)))); userIo.print(" LOSES " + String.format("%6s", formatter.format(Math.abs(totalBet))));
} else if(totalBet > 0) { } else if(totalBet > 0) {
userIo.print(" WINS " + String.format("%6s", formatter.format(totalBet))); userIo.print(" WINS " + String.format("%6s", formatter.format(totalBet)));
} else { } else {
userIo.print(" PUSHES "); userIo.print(" PUSHES ");
} }
@@ -352,5 +341,4 @@ public class Game {
.map(Player::getCurrentBet) .map(Player::getCurrentBet)
.allMatch(bet -> bet > 0 && bet <= 500); .allMatch(bet -> bet > 0 && bet <= 500);
} }
} }

View File

@@ -439,7 +439,7 @@ public class GameTest {
// Then // Then
assertAll( assertAll(
() -> assertTrue(out.toString().contains("PLAYER 1 WINS 100 TOTAL= 300")), () -> assertTrue(out.toString().contains("PLAYER 1 WINS 100 TOTAL= 300")),
() -> assertTrue(out.toString().contains("DEALER'S TOTAL= -100")) () -> assertTrue(out.toString().contains("DEALER'S TOTAL= -100"))
); );
} }