I am designing an in-depth poker game. I am first focusing on recognizing the strength of a hand given the set of cards.
- Is the following algorithm suitable for the stated purpose?
- Am I using correct OOP design principles and implementation in my code?
Algorithm:
Go from a top down approach checking for the following in order:
- Is: the hand a royal flush
- If not: is the hand a straight flush
- If not: is the hand a four of a kind
- If not: is the hand a full house
Eventually if none are met, it will just return the high card.
Checking for each individual instance:
- Royal flush: is it a flush and is it a straight and are all the cards picture cards
- Is a straight flush: is it a straight and is it a flush
- Is it a 4 of a kind: is the same card repeated 4 times
- Is it a full house: is there a 3 of a kind and a 2 of a kind
- Is it a flush: are there 5 cards with the same suit
- Is it a straight: are there 5 cards in a row with a common difference of 1
- Is it a 3 of a kind: are there 3 repeated cards
- Is it a two pair: are there two pairs
- Is it a pair: are there 2 repeated cards
package main;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.stream.Stream;
/**
*
* @author Tamir
*/
public class Hand {
private Card[] hand = new Card[2];
public enum HandRank {
ROYAL_FLUSH,
STRAIGHT_FLUSH,
FOUR_OF_A_KIND,
FULL_HOUSE,
FLUSH,
STRAIGHT,
THREE_OF_A_KIND,
TWO_PAIR,
PAIR,
HIGH_CARD;
}
public Hand() {
}
public Hand(Card[] hand) {
this.hand = hand;
}
public Card[] getHand() {
return hand;
}
public void setHand(Card[] hand) {
this.hand = hand;
}
public void printHand() {
for (Card c : hand) {
System.out.println(c);
}
}
public HandRank determineHandRank(Card[] flop) {
if (isARoyalFlush(flop)) {
return HandRank.ROYAL_FLUSH;
} else if (isAStraightFlush(flop)) {
return HandRank.STRAIGHT_FLUSH;
} else if (isAFourOfAKind(flop)) {
return HandRank.FOUR_OF_A_KIND;
} else if (isAFullHouse(flop)) {
return HandRank.FULL_HOUSE;
} else if (isAFlush(flop)) {
return HandRank.FLUSH;
} else if (isAStraight(flop)) {
return HandRank.STRAIGHT;
} else if (isThreeOfAKind(flop)) {
return HandRank.THREE_OF_A_KIND;
} else if (isTwoPair(flop)) {
return HandRank.TWO_PAIR;
} else if (isPair(flop)) {
return HandRank.PAIR;
} else {
return HandRank.HIGH_CARD;
}
}
public boolean isARoyalFlush(Card[] flop) {
if (isAStraight(flop) && isAFlush(flop)) {
Card[] allCards = Stream.concat(Arrays.stream(flop), Arrays.stream(hand))
.toArray(Card[]::new);
boolean aceExists = false, kingExists = false, queenExists = false, jackExists = false, tenExists = false;
for (Card c : allCards) {
switch (c.getRank().getRank()) {
case "ACE":
aceExists = true;
break;
case "KING":
kingExists = true;
break;
case "QUEEN":
queenExists = true;
break;
case "JACK":
jackExists = true;
break;
case "TEN":
tenExists = true;
break;
}
}
return (aceExists && kingExists && queenExists && jackExists && tenExists);
} else {
return false;
}
}
public boolean isAStraight(Card[] flop) {
Card[] allCards = Stream.concat(Arrays.stream(flop), Arrays.stream(hand))
.toArray(Card[]::new);
Arrays.sort(allCards, byRank);
int noOfCardsInARow = 0;
int pos = 0;
boolean isAStraight = false;
while (pos < allCards.length - 1 && !isAStraight) {
if (allCards[pos + 1].getRank().getValue() - allCards[pos].getRank().getValue() == 1) {
noOfCardsInARow++;
if (noOfCardsInARow == 4) {
isAStraight = true;
} else {
pos++;
}
} else {
noOfCardsInARow = 0;
pos++;
}
}
return isAStraight;
}
public boolean isAFlush(Card[] flop) {
Card[] allCards = Stream.concat(Arrays.stream(flop), Arrays.stream(hand))
.toArray(Card[]::new);
int noOfClubs = 0;
int noOfSpades = 0;
int noOfHearts = 0;
int noOfDiamonds = 0;
for (Card c : allCards) {
switch (c.getSuit()) {
case "HEART":
noOfHearts++;
break;
case "SPADES":
noOfSpades++;
break;
case "CLUBS":
noOfClubs++;
break;
case "DIAMONDS":
noOfDiamonds++;
break;
}
}
return (noOfClubs == 5 || noOfSpades == 5 || noOfHearts == 5 || noOfDiamonds == 5);
}
private boolean isThreeOfAKind(Card[] flop) {
Card[] allCards = Stream.concat(Arrays.stream(flop), Arrays.stream(hand))
.toArray(Card[]::new);
int cardRepeats = 1;
boolean isThreeOfAKind = false;
int i = 0;
int k = i + 1;
while (i < allCards.length && !isThreeOfAKind) {
cardRepeats = 1;
while (k < allCards.length && !isThreeOfAKind) {
if (allCards[i].getRank().getValue() == allCards[k].getRank().getValue()) {
cardRepeats++;
if (cardRepeats == 3) {
isThreeOfAKind = true;
}
}
k++;
}
i++;
}
return isThreeOfAKind;
}
private boolean isTwoPair(Card[] flop) {
Card[] allCards = Stream.concat(Arrays.stream(flop), Arrays.stream(hand))
.toArray(Card[]::new);
int cardRepeats = 1;
int noOfCardRepeats = 0;
boolean isTwoPair = false;
int i = 0;
int k = i + 1;
while (i < allCards.length && !isTwoPair) {
cardRepeats = 1;
while (k < allCards.length && !isTwoPair) {
if (allCards[i].getRank().getValue() == allCards[k].getRank().getValue()) {
cardRepeats++;
if (cardRepeats == 2) {
cardRepeats = 1;
noOfCardRepeats++;
if (noOfCardRepeats == 2) {
isTwoPair = true;
}
}
}
k++;
}
i++;
}
return isTwoPair;
}
private boolean isPair(Card[] flop) {
Card[] allCards = Stream.concat(Arrays.stream(flop), Arrays.stream(hand))
.toArray(Card[]::new);
int cardRepeats = 1;
boolean isPair = false;
int i = 0;
int k = i + 1;
while (i < allCards.length && !isPair) {
cardRepeats = 1;
while (k < allCards.length && !isPair) {
if (allCards[i].getRank().getValue() == allCards[k].getRank().getValue()) {
cardRepeats++;
if (cardRepeats == 2) {
isPair = true;
}
}
k++;
}
i++;
}
return isPair;
}
public Comparator<Card> byRank = (Card left, Card right) -> {
if (left.getRank().getValue() < right.getRank().getValue()) {
return -1;
} else {
return 1;
}
};
private boolean isAFullHouse(Card[] flop) {
Card[] allCards = Stream.concat(Arrays.stream(flop), Arrays.stream(hand))
.toArray(Card[]::new);
Arrays.sort(allCards, byRank);
int noOfRepeats = 1;
boolean isThreeOfAKind = false;
boolean isTwoOfAKind = false;
for (int i = 0; i < allCards.length - 1; i++) {
if (allCards[i].getRank().getValue() == allCards[i + 1].getRank().getValue()) {
noOfRepeats++;
if (noOfRepeats == 3) {
isThreeOfAKind = true;
noOfRepeats = 1;
} else if (noOfRepeats == 2) {
isTwoOfAKind = true;
noOfRepeats = 1;
}
} else {
noOfRepeats = 1;
}
}
return (isTwoOfAKind && isThreeOfAKind);
}
public boolean isAFourOfAKind(Card[] flop) {
Card[] allCards = Stream.concat(Arrays.stream(flop), Arrays.stream(hand))
.toArray(Card[]::new);
int cardRepeats = 1;
boolean isFourOfAKind = false;
int i = 0;
int k = i + 1;
while (i < allCards.length && !isFourOfAKind) {
cardRepeats = 1;
while (k < allCards.length && !isFourOfAKind) {
if (allCards[i].getRank().getValue() == allCards[k].getRank().getValue()) {
cardRepeats++;
if (cardRepeats == 4) {
isFourOfAKind = true;
}
}
k++;
}
i++;
}
return isFourOfAKind;
}
private boolean isAStraightFlush(Card[] flop) {
if (isAFlush(flop) && isAStraight(flop)) {
return true;
} else {
return false;
}
}
public Card getHighCard(Card[] flop) {
Card[] allCards = Stream.concat(Arrays.stream(flop), Arrays.stream(hand))
.toArray(Card[]::new);
Arrays.sort(allCards, byRank);
return allCards[0];
}
public Card getHandHighCard() {
Arrays.sort(hand, byRank);
return hand[0];
}
}
Card
object
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package main;
/**
*
* @author Tamir
*/
public class Card {
private String suit;
private Rank rank;
//isDealt: checks if the card is in play and out of the deck
private boolean isDealt;
public Card() {
}
public Card(String suit, Rank rank, boolean isDealt) {
this.suit = suit;
this.rank = rank;
this.isDealt = isDealt;
}
public String getSuit() {
return suit;
}
public void setSuit(String suit) {
this.suit = suit;
}
public Rank getRank() {
return rank;
}
public void setRank(Rank rank) {
this.rank = rank;
}
public boolean isIsDealt() {
return isDealt;
}
public void setIsDealt(boolean isDealt) {
this.isDealt = isDealt;
}
@Override
public String toString() {
return suit + " " + rank;
}
}
Rank
object
package main;
/**
*
* @author Tamir
*/
public class Rank {
private int value;
private String rank;
public Rank() {
}
public Rank(int value, String rank) {
this.value = value;
this.rank = rank;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String getRank() {
return rank;
}
public void setRank(String rank) {
this.rank = rank;
}
@Override
public String toString() {
String stg = "";
stg += this.rank + "(" + this.value + ")";
return stg;
}
}
Card
andRank
classes too? \$\endgroup\$TwoPair
is wrong, in my opinion. What if theallCards
array is[2,2,3,2]
? You'll get a two pair, but it obviously isn't one. \$\endgroup\$