Reputation: 55
I am trying to sort a hand of poker based on their rank and suits, but it is still not fully sorted, here are the code, Note that the suits is sorted, but not the ranks
My hand before the sort:
1: KING of HEARTS 2: FOUR of DIAMONDS 3: SEVEN of CLUBS 4: KING of CLUBS 5: THREE of HEARTS 6: FIVE of DIAMONDS 7: TWO of CLUBS 8: KING of DIAMONDS 9: FOUR of SPADES 10: THREE of DIAMONDS
After the sort:
1: FOUR of SPADES 2: KING of HEARTS 3: THREE of HEARTS 4: TWO of CLUBS 5: KING of CLUBS 6: SEVEN of CLUBS 7: KING of DIAMONDS 8: FIVE of DIAMONDS 9: FOUR of DIAMONDS 10: THREE of DIAMONDS
Card object
public int compareTo(Card that)
{
if(this.suit.ordinal() > that.suit.ordinal())
{
return 1;
}
if(this.suit.ordinal() < that.suit.ordinal())
{
return -1;
}
int rank1 = (this.rank.ordinal() + 11) % 13; //A>K
int rank2 = (that.rank.ordinal() + 11) % 13;
if(rank1 > rank2) return 1;
if(rank1 < rank2) return -1;
return 0;
}
Player Object
public void tryTest()
{
Card temp = new Card();
for(int i=0;i<countCard;i++)
{
for(int j=0;j<countCard;j++)
{
if(playerHand[i].compareTo(playerHand[j]) > 0)
{
temp=this.playerHand[j];
this.playerHand[j] = this.playerHand[i];
this.playerHand[i] = temp;
}
}
}
}
Enum Ranks
ACE,
TWO,
THREE,
FOUR,
FIVE,
SIX,
SEVEN,
EIGHT,
NINE,
TEN,
JACK,
QUEEN,
KING;
Enum Suits
DIAMONDS,
CLUBS,
HEARTS,
SPADES;
Upvotes: 4
Views: 1789
Reputation: 48600
If you want to sort a poker hand, you can sort hands like this.
As long as your Rank
enum is ordered from lowest to highest e.g. TWO
to ACE
then your comparison of the ordinal()
values should work.
public static void sortHandBySuitThenRank(List<Card> hand) {
hand.sort(Comparator.comparing(Card::getSuit).thenComparing(Card::getRank));
}
public static void sortHandByRankThenSuit(List<Card> hand) {
hand.sort(Comparator.comparing(Card::getRank).thenComparing(Card::getSuit));
}
Here is a demo of the code in action:
package org.example.cards;
import java.util.*;
import java.util.stream.Collectors;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Poker {
public static void main(String[] args) {
PokerGame game = new PokerGame();
List.of("Alice", "Bob", "Charlie", "David")
.forEach(name -> game.addPlayer(new Player(name)));
game.shuffleDeck();
game.dealInitialHand();
game.showHands();
game.evaluateHands();
game.showDiscardPile();
game.determineWinner().ifPresent(winner -> {
log.info("Winner: {}", winner.getName());
log.info("Hand: {} ({})", winner.showHand(), winner.evaluateHand().getDescription());
});
}
static class PokerGame {
private static final int HAND_SIZE = 5;
private final List<Player> players;
private final Deck<Card> deck;
private final List<Card> discardPile;
public PokerGame() {
this.players = new ArrayList<>();
this.deck = new PokerDeck();
this.discardPile = new ArrayList<>();
}
public void addPlayer(Player player) {
players.add(player);
}
public void shuffleDeck() {
deck.shuffle();
}
public void dealInitialHand() {
for (int i = 0; i < HAND_SIZE; i++) {
for (Player player : players) {
player.drawCard(deck.deal());
}
}
}
public void discardCard(Card card) {
discardPile.add(card);
}
public void showHands() {
for (Player player : players) {
player.sortHand();
log.debug("{}'s hand: {}", player.getName(), player.showHand());
}
}
public void showDiscardPile() {
log.debug("Discard pile: {}", PokerUtils.formatHand(discardPile));
}
public Optional<Player> determineWinner() {
return players.stream().max(Comparator.comparing(Player::getHandRank));
}
public void evaluateHands() {
for (Player player : players) {
log.info("{}'s hand: {} ({})", player.getName(), player.showHand(), player.evaluateHand().getDescription());
List<Card> cardsToDiscard = player.decideCardsToDiscard();
log.info("Discarding: {}", PokerUtils.formatHand(cardsToDiscard));
int cardsToDraw = cardsToDiscard.size();
for (Card card : cardsToDiscard) {
player.discardCard(card);
discardCard(card);
}
for (int i = 0; i < cardsToDraw; i++) {
player.drawCard(deck.deal());
}
log.info("New hand: {} ({})", player.showHand(), player.evaluateHand().getDescription());
}
}
}
static class HandEvaluator {
public static HandType evaluateHand(List<Card> hand) {
// Sort the hand by rank
PokerUtils.sortHandByRankThenSuit(hand);
// Check for various hand types, starting from the strongest
if (isRoyalFlush(hand)) return HandType.ROYAL_FLUSH;
else if (isStraightFlush(hand)) return HandType.STRAIGHT_FLUSH;
else if (isFourOfAKind(hand)) return HandType.FOUR_OF_A_KIND;
else if (isFullHouse(hand)) return HandType.FULL_HOUSE;
else if (isFlush(hand)) return HandType.FLUSH;
else if (isStraight(hand)) return HandType.STRAIGHT;
else if (isThreeOfAKind(hand)) return HandType.THREE_OF_A_KIND;
else if (isTwoPair(hand)) return HandType.TWO_PAIR;
else if (isOnePair(hand)) return HandType.ONE_PAIR;
return HandType.HIGH_CARD;
}
private static boolean isRoyalFlush(List<Card> hand) {
return isStraightFlush(hand) && hand.getLast().getRank() == Rank.ACE;
}
private static boolean isStraightFlush(List<Card> hand) {
return isStraight(hand) && isFlush(hand);
}
private static boolean isFourOfAKind(List<Card> hand) {
return getRankCounts(hand).containsValue(4);
}
private static boolean isFullHouse(List<Card> hand) {
Map<Rank, Integer> rankCounts = getRankCounts(hand);
return rankCounts.containsValue(3) && rankCounts.containsValue(2);
}
private static boolean isFlush(List<Card> hand) {
final Suit firstSuit = hand.getFirst().getSuit();
return hand.stream().allMatch(card -> card.getSuit() == firstSuit);
}
private static boolean isStraight(List<Card> hand) {
for (int i = 0; i < hand.size() - 1; i++) {
if (hand.get(i).getRank().ordinal() + 1 != hand.get(i + 1).getRank().ordinal()) {
return false;
}
}
return true;
}
private static boolean isThreeOfAKind(List<Card> hand) {
Map<Rank, Integer> rankCounts = getRankCounts(hand);
return rankCounts.containsValue(3) && !rankCounts.containsValue(2);
}
private static boolean isTwoPair(List<Card> hand) {
return getRankCounts(hand).values().stream().filter(count -> count == 2).count() == 2;
}
private static boolean isOnePair(List<Card> hand) {
Map<Rank, Integer> rankCounts = getRankCounts(hand);
return rankCounts.containsValue(2) && !rankCounts.containsValue(3);
}
private static Map<Rank, Integer> getRankCounts(List<Card> hand) {
return hand.stream().collect(Collectors.groupingBy(Card::getRank, Collectors.summingInt(e -> 1)));
}
}
@Getter
static class Player {
private final String name;
private final List<Card> hand;
public Player(String name) {
this.name = name;
hand = new ArrayList<>();
}
public void drawCard(Card card) {
hand.add(card);
}
public void discardCard(Card card) {
hand.remove(card);
}
public void sortHand() {
PokerUtils.sortHandBySuitThenRank(hand);
}
public String showHand() {
return PokerUtils.formatHand(hand);
}
public HandType evaluateHand() {
return HandEvaluator.evaluateHand(hand);
}
public List<Card> decideCardsToDiscard() {
return PokerUtils.decideCardsToDiscard(hand).stream()
.limit(3)
.toList();
}
public int getHandRank() {
return this.evaluateHand().ordinal();
}
}
@NoArgsConstructor(access = AccessLevel.PRIVATE)
static class PokerUtils {
public static String formatHand(List<Card> hand) {
return hand.stream().map(Card::toString).collect(Collectors.joining(" "));
}
public static void sortHandBySuitThenRank(List<Card> hand) {
hand.sort(Comparator.comparing(Card::getSuit).thenComparing(Card::getRank));
}
public static void sortHandByRankThenSuit(List<Card> hand) {
hand.sort(Comparator.comparing(Card::getRank).thenComparing(Card::getSuit));
}
public static void shuffle(List<Card> cards) {
Random rand = new Random();
for (int currIndex = cards.size() - 1; currIndex > 0; currIndex--) {
int randIndex = rand.nextInt(currIndex + 1);
Card randCard = cards.get(randIndex);
cards.set(randIndex, cards.get(currIndex));
cards.set(currIndex, randCard);
}
}
public static List<Card> decideCardsToDiscard(List<Card> hand) {
HandType handType = HandEvaluator.evaluateHand(hand);
Map<Rank, Long> rankCounts = hand.stream()
.collect(Collectors.groupingBy(Card::getRank, Collectors.counting()));
return switch (handType) {
case HIGH_CARD -> {
final Card highestCard = hand.stream().max(Comparator.comparing(Card::getRank)).orElse(null);
yield hand.stream()
.filter(card -> !card.equals(highestCard))
.toList();
// Discard all but the highest card
}
case ONE_PAIR -> {
final Rank pairRank = rankCounts.entrySet().stream().filter(entry -> entry.getValue() == 2).map(Map.Entry::getKey).findFirst().orElse(null);
// Discard the three cards that are not part of the pair
yield hand.stream()
.filter(card -> !card.getRank().equals(pairRank))
.toList();
}
case TWO_PAIR -> {
final List<Rank> pairRanks = rankCounts.entrySet().stream()
.filter(entry -> entry.getValue() == 2)
.map(Map.Entry::getKey)
.toList();
// Discard the fifth card that is not part of the pairs
yield hand.stream()
.filter(card -> !pairRanks.contains(card.getRank()))
.toList();
}
case THREE_OF_A_KIND -> {
final Rank threeOfAKindRank = rankCounts.entrySet().stream()
.filter(entry -> entry.getValue() == 3)
.map(Map.Entry::getKey)
.findFirst()
.orElse(null);
// Discard the two cards that are not part of the three of a kind
yield hand.stream()
.filter(card -> !card.getRank().equals(threeOfAKindRank))
.toList();
}
case STRAIGHT, FLUSH, FULL_HOUSE, FOUR_OF_A_KIND, STRAIGHT_FLUSH, ROYAL_FLUSH ->
Collections.emptyList();
};
}
}
static class PokerDeck implements Deck<Card> {
private final List<Card> cards;
public PokerDeck() {
cards = new ArrayList<>();
for (Suit suit : Suit.values()) {
for (Rank rank : Rank.values()) {
cards.add(new PokerCard(suit, rank));
}
}
}
@Override
public void shuffle() {
PokerUtils.shuffle(cards);
}
@Override
public Card deal() {
return cards.removeFirst();
}
}
@Value
static class PokerCard implements Card {
Suit suit;
Rank rank;
@Override
public String toString() {
return String.format("%s%s", rank.getSymbol(), suit.getSymbol());
}
}
@RequiredArgsConstructor
@Getter
enum Suit {
HEARTS("♥"),
DIAMONDS("♦"),
CLUBS("♣"),
SPADES("♠");
private final String symbol;
}
@RequiredArgsConstructor
@Getter
enum Rank {
TWO("2", 2),
THREE("3", 3),
FOUR("4", 4),
FIVE("5", 5),
SIX("6", 6),
SEVEN("7", 7),
EIGHT("8", 8),
NINE("9", 9),
TEN("T", 10),
JACK("J", 11),
QUEEN("Q", 12),
KING("K", 13),
ACE("A", 14);
private final String symbol;
private final int value;
}
@RequiredArgsConstructor
@Getter
enum HandType {
HIGH_CARD("High Card"),
ONE_PAIR("One Pair"),
TWO_PAIR("Two Pair"),
THREE_OF_A_KIND("Three of a Kind"),
STRAIGHT("Straight"),
FLUSH("Flush"),
FULL_HOUSE("Full House"),
FOUR_OF_A_KIND("Four of a Kind"),
STRAIGHT_FLUSH("Straight Flush"),
ROYAL_FLUSH("Royal Flush");
private final String description;
}
interface Deck<T extends Card> {
void shuffle();
T deal();
}
interface Card {
Suit getSuit();
Rank getRank();
}
}
Output:
DEBUG [main] o.e.c.Poker$PokerGame: Alice's hand: T♥ A♥ 4♦ A♦ 5♠
DEBUG [main] o.e.c.Poker$PokerGame: Bob's hand: Q♥ 3♦ T♦ J♦ J♠
DEBUG [main] o.e.c.Poker$PokerGame: Charlie's hand: 9♦ 4♣ 5♣ 7♠ 9♠
DEBUG [main] o.e.c.Poker$PokerGame: David's hand: 8♥ 5♦ 3♠ 6♠ A♠
INFO [main] o.e.c.Poker$PokerGame: Alice's hand: T♥ A♥ 4♦ A♦ 5♠ (One Pair)
INFO [main] o.e.c.Poker$PokerGame: Discarding: 4♦ 5♠ T♥
INFO [main] o.e.c.Poker$PokerGame: New hand: A♥ A♦ 5♥ T♣ K♥ (One Pair)
INFO [main] o.e.c.Poker$PokerGame: Bob's hand: Q♥ 3♦ T♦ J♦ J♠ (One Pair)
INFO [main] o.e.c.Poker$PokerGame: Discarding: 3♦ T♦ Q♥
INFO [main] o.e.c.Poker$PokerGame: New hand: J♦ J♠ 6♦ J♥ 2♣ (Three of a Kind)
INFO [main] o.e.c.Poker$PokerGame: Charlie's hand: 9♦ 4♣ 5♣ 7♠ 9♠ (One Pair)
INFO [main] o.e.c.Poker$PokerGame: Discarding: 4♣ 5♣ 7♠
INFO [main] o.e.c.Poker$PokerGame: New hand: 9♦ 9♠ 4♥ J♣ Q♣ (One Pair)
INFO [main] o.e.c.Poker$PokerGame: David's hand: 8♥ 5♦ 3♠ 6♠ A♠ (High Card)
INFO [main] o.e.c.Poker$PokerGame: Discarding: 3♠ 5♦ 6♠
INFO [main] o.e.c.Poker$PokerGame: New hand: 8♥ A♠ 2♠ 2♥ 7♣ (One Pair)
DEBUG [main] o.e.c.Poker$PokerGame: Discard pile: 4♦ 5♠ T♥ 3♦ T♦ Q♥ 4♣ 5♣ 7♠ 3♠ 5♦ 6♠
INFO [main] o.e.c.Poker: Winner: Bob
INFO [main] o.e.c.Poker: Hand: 2♣ 6♦ J♥ J♦ J♠ (Three of a Kind)
Upvotes: 1
Reputation: 3650
Look into some standard sorting algorithms. The code you have right now compares everything to everything else, and then swaps them if one is greater than the other. However this could lead to you swapping backwards:
1, 2
2>1 therefore swap
2,1
The closest algorithm to what you have would be Bubble Sort, which uses slightly different indexes:
for(int i=0;i<countCard;i++)
{
for(int j=0;j<countCard -1;j++)
{
if(playerHand[j].compareTo(playerHand[j+1]) > 0)
{
temp=this.playerHand[j+1];
this.playerHand[j+1]= this.playerHand[j];
this.playerHand[j] = temp;
}
}
}
Upvotes: 3