Getting to the heart of it

The first couple of tests for the Poker Game kata were relatively simple, as it should be, but now I'm really getting to the heart of the problem. This next chunk of work involved the identification of a winning hand, albeit the simplest one being the highest card:

@Test
public void when_both_players_see_all_the_cards_and_both_only_have_high_card_then_the_winner_should_be_the_one_with_the_highest_card() {
  PokerRound round = new PokerRound();
  round.deal("john").holeCards("4d", "2d");
  round.deal("jane").holeCards("Ah", "3c");
  round
   .dealFlop("Qc", "Td", "5s")
   .dealTurn("6c")
   .dealRiver("9h");

  Assert.assertEquals("john: 4d 2d Qc Td 5s 6c 9h\n" +
    "jane: Ah 3c Qc Td 5s 6c 9h (Winner)", round.results());
}

Note that at this stage, I'm not considering anything more than who has the highest card. For example, the implementation could (and in fact does) simply check which player(s) hold the top valued card. In reality of course, the best five cards would be chosen and all considered. This is deemed out-of-scope for the time being. That may be going a bit too fast too soon.

Onto the implementation and I decide to enhance the results() method by adding a class called RoundWinners which will calculate the winning hand / player. The iteration within the results method then simply asks the RoundWinners class if the particular player has won before adding the "(Winner)" text.

To begin with, I hard-code the isWinner method of the RoundWinners class to look for the particular hand. This then makes the test pass. I then set about with a real implementation.

The approach I take is to find the highest valued card. Then, given a players hand, I simply return true from isWinner if that hand contains the highest card. This calls for something a bit more than a List<String> objects representing the hand, so I introduce a Card class:

class Card {
  final int numericValue; // e.g. 12
  final char value; // e.g. 'Q'
  final Suit suit; // enum value; one of Hearts, Clubs, Diamonds, Spades
}

I refactored the PokerRound and RoundWinners classes appropriately. I also see a common pattern where we need a list of cards, so I create a simple factory method Cards.from(). Now, the RoundWinners class can take the map of players and their cards:

public RoundWinners(Map<String, List<Card>> playersAndTheirCards) {
  this.playersAndTheirCards = playersAndTheirCards;
}

Lastly, we can set about with the implementation of the isWinner method:

public boolean isWinner(String player) {
  int highestCardValue = findHighestCardForAnyPlayer();
  List<Card> cardsForPlayer = playersAndTheirCards.get(player);
  for (Card c : cardsForPlayer)
    if (c.getNumericValue() == highestCardValue) return true;
  return false;
}

private int findHighestCardForAnyPlayer() {
  int highestCard = 2;
  for (List<Card> cards : playersAndTheirCards.values())
    for (Card card : cards)
      highestCard = Math.max(highestCard, card.getNumericValue());
  return highestCard;
}

Still green. This is just but a step on the road to our solution of identifying the winning hand. Clearly we want to break up the identification somehow, otherwise this class is going to be both very large and very complicated. This has been noted in the issues file, and the resolved points have been removed - always my favourite part.

My next step will possibly be implementing another winning hand: probably something like a Pair beating a High card. That should flesh out the RoundWinners concept and give the opportunity to look at the map of players and their cards abstraction.


Comment Guidelines
See the FAQ for details on the full rules and guidelines. No Spam. Write clearly and thoughtfully - no bad language.