This commit is contained in:
2022-11-21 22:04:05 -08:00
parent ad34be05e3
commit c1ac69a146
5 changed files with 259 additions and 128 deletions

View File

@ -8,16 +8,64 @@
using namespace Dawn; using namespace Dawn;
void Card::fillDeck(std::vector<struct Card> *deck) { void Card::fillDeck(std::vector<struct Card> *deck) {
assertNotNull(deck);
for(uint8_t i = 0; i < CARD_DECK_SIZE; i++) { for(uint8_t i = 0; i < CARD_DECK_SIZE; i++) {
deck->push_back(Card(i)); deck->push_back(Card(i));
} }
} }
int32_t Card::contains(std::vector<struct Card> *deck, struct Card c) {
assertNotNull(deck);
assertTrue(deck->size() > 0);
void Card::sort(std::vector<struct Card> *deck) { auto it = deck->begin();
std::sort(deck->begin(), deck->end(), &cardSorter); while(it != deck->end()) {
if(it->cardValue == c.cardValue) return (int32_t)(it - deck->begin());
++it;
}
return -1;
} }
bool_t cardSorter(struct Card left, struct Card right) { int32_t Card::containsNumber(
std::vector<struct Card> *deck,
enum CardValue number
) {
assertNotNull(deck);
assertTrue(number < CARD_COUNT_PER_SUIT);
auto it = deck->begin();
while(it != deck->end()) {
if(it->getValue() == number) return (int32_t)(it - deck->begin());
++it;
}
return -1;
}
std::vector<struct Card> Card::countPairs(
std::vector<struct Card> *deck,
enum CardValue val
) {
std::vector<struct Card> pairs;
assertNotNull(deck);
assertTrue(deck->size() > 0);
auto it = deck->begin();
while(it != deck->end()) {
if(it->getValue() == val) pairs.push_back(*it);
++it;
}
return pairs;
}
bool_t Card::cardSorter(struct Card left, struct Card right) {
return left.cardValue < right.cardValue; return left.cardValue < right.cardValue;
} }
void Card::sort(std::vector<struct Card> *deck) {
assertNotNull(deck);
assertTrue(deck->size() > 1);
std::sort(deck->begin(), deck->end(), &Card::cardSorter);
}

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include "dawnlibs.hpp" #include "dawnlibs.hpp"
#include "assert/assert.hpp"
namespace Dawn { namespace Dawn {
enum CardSuit { enum CardSuit {
@ -43,14 +44,56 @@ namespace Dawn {
public: public:
uint8_t cardValue; uint8_t cardValue;
static void fillDeck(std::vector<struct Card> *deck); /**
* Shuffles a hand / deck
*
* @param deck Array of cards to shuffle.
*/
static void shuffle(std::vector<struct Card> *deck); static void shuffle(std::vector<struct Card> *deck);
static bool_t contains(std::vector<struct Card> *deck, struct Card);
/**
* Fills a vector with all of the cards in a deck, in order.
*
* @param deck Deck to fill.
*/
static void fillDeck(std::vector<struct Card> *deck);
/**
* Check if an array of cards contains a specific card.
*
* @param deck Deck/Hand/Array of cards to check.
* @param card Card to look for
* @returns The index within the array that the card is. -1 if not found.
*/
static int32_t contains(std::vector<struct Card> *deck, struct Card card);
/**
* Check if the array of cards contains a specific number.
*
* @param deck Array of cards to check
* @param number The number to look for.
* @returns The index that the first card is. -1 if not found.
*/
static int32_t containsNumber(
std::vector<struct Card> *deck,
enum CardValue number
);
/**
* Counts the amount of times a card's number appears within the given
* hand.
*
* @param deck The hand to check
* @param val Value of pairs to find.
* @return Card pairs in the deck.
*/
static std::vector<struct Card> countPairs( static std::vector<struct Card> countPairs(
std::vector<struct Card> *deck, std::vector<struct Card> *deck,
enum CardValue value enum CardValue val
); );
static bool_t cardSorter(struct Card left, struct Card right);
/** /**
* Sort a hand of cards. Cards are ordered in descending weight, aces are * Sort a hand of cards. Cards are ordered in descending weight, aces are
* high. Cards will be grouped by their suits, e.g. CARD_CLUBS_TWO will * high. Cards will be grouped by their suits, e.g. CARD_CLUBS_TWO will
@ -71,14 +114,21 @@ namespace Dawn {
assertTrue(cv < CARD_DECK_SIZE); assertTrue(cv < CARD_DECK_SIZE);
} }
/**
* Returns the number of a given card.
* @returns The card number.
*/
CardValue getValue() { CardValue getValue() {
return (CardValue)(cardValue % CARD_COUNT_PER_SUIT); return (CardValue)(cardValue % CARD_COUNT_PER_SUIT);
} }
/**
* Returns the suit of a given card.
* @returns The suit.
*/
CardSuit getSuit() { CardSuit getSuit() {
return (CardSuit)(cardValue / CARD_COUNT_PER_SUIT); return (CardSuit)(cardValue / CARD_COUNT_PER_SUIT);
} }
}; };
bool_t cardSorter(struct Card left, struct Card right);
} }

View File

@ -239,206 +239,196 @@ int32_t PokerPlayer::getSumOfChips() {
struct PokerWinning PokerPlayer::getWinning() { struct PokerWinning PokerPlayer::getWinning() {
struct PokerWinning winning; struct PokerWinning winning;
uint8_t i, j, l; struct Card card(0x00);
uint8_t i, j;
int32_t index;
enum CardValue number, look;
enum CardSuit suit;
std::vector<struct Card> pairs;
// Get the full poker hand (should be a 7 card hand, but MAY not be) // Get the full poker hand (should be a 7 card hand, but MAY not be)
auto itHand = this->hand.begin(); for(i = 0; i < this->pokerGame->community.size(); i++) {
while(itHand != this->hand.end()) { winning.full.push_back(this->pokerGame->community[i]);
winning.full.push_back(*itHand);
++itHand;
} }
for(i = 0; i < this->hand.size(); i++) {
auto itCommunity = this->pokerGame->community.begin(); winning.full.push_back(this->hand[i]);
while(itCommunity != this->pokerGame->community.end()) {
winning.full.push_back(*itCommunity);
++itCommunity;
} }
Card::sort(&winning.full); Card::sort(&winning.full);
//////////////////////// Now look for the winning set //////////////////////// //////////////////////// Now look for the winning set ////////////////////////
// Royal / Straight Flush // Royal / Straight Flush
auto it = winning.full.begin(); for(i = 0; i < winning.full.size(); i++) {
while(it != winning.full.end()) { card = winning.full[i];
auto number = it->getValue(); number = card.getValue();
auto suit = it->getSuit(); if(number < CARD_FIVE) continue;
if(number < CARD_FIVE) {
++it;
continue;
}
suit = card.getSuit();
winning.set.clear(); winning.set.clear();
winning.set.push_back(*it); winning.set.push_back(card);
// Now look for the matching cards (Reverse order to order from A to 10) // Now look for the matching cards (Reverse order to order from A to 10)
for(j = 1; j <= 4; j++) { for(j = 1; j <= 4; j++) {
l = number == CARD_FIVE && j == 4 ? CARD_ACE : number - j;//Ace low. // Ace low.
auto c = Card(suit, (CardValue)l); look = (
if(!Card::contains(&winning.full, c)) break; number == CARD_FIVE && j == 4 ?
winning.set.push_back(c); (enum CardValue)CARD_ACE :
(enum CardValue)(number - j)
);
index = Card::contains(&winning.full, Card(suit, look));
if(index == -1) break;
winning.set.push_back(winning.full[index]);
} }
// Check if has all necessary cards. // Check if has all necessary cards.
if(winning.set.size() != 5) { if(winning.set.size() < POKER_WINNING_SET_SIZE) continue;
++it;
continue;
}
// Add self to array // Add self to array
winning.type = ( winning.type = (
number == CARD_ACE ? POKER_WINNING_TYPE_ROYAL_FLUSH : number == CARD_ACE ? POKER_WINNING_TYPE_ROYAL_FLUSH :
POKER_WINNING_TYPE_STRAIGHT_FLUSH POKER_WINNING_TYPE_STRAIGHT_FLUSH
); );
pokerWinnerFillRemaining(winning); winning.fillRemaining();
return winning; return winning;
} }
// Four of a kind. // Four of a kind.
it = winning.full.begin(); for(i = 0; i < winning.full.size(); i++) {
while(it != winning.full.end()) { card = winning.full[i];
auto pairs = Card::countPairs(&winning.full, it->getValue()); number = card.getValue();
if(pairs.size() < CARD_SUIT_COUNT) { pairs = Card::countPairs(&winning.full, number);
++it; if(pairs.size() < CARD_SUIT_COUNT) continue;
continue;
}
winning.set = pairs; winning.set = pairs;
winning.type = POKER_WINNING_TYPE_FOUR_OF_A_KIND; winning.type = POKER_WINNING_TYPE_FOUR_OF_A_KIND;
pokerWinnerFillRemaining(winning); winning.fillRemaining();
return winning; return winning;
} }
// Full House // Full House
winning.set.clear(); winning.set.clear();
it = winning.full.begin(); for(i = 0; i < winning.full.size(); i++) {
while(it != winning.full.end()) {
// Check we haven't already added this card. // Check we haven't already added this card.
if(Card::contains(&winning.set, *it) != -1) { card = winning.full[i];
++it; if(Card::contains(&winning.set, card) != -1) {
continue; continue;
} }
auto pairs = Card::countPairs(&winning.full, it->getValue()); number = card.getValue();
pairs = Card::countPairs(&winning.full, number);
// Did we find either two pair or three pair? // Did we find either two pair or three pair?
if(pairs.size() != 2 && pairs.size() != 3) { if(pairs.size() != 2 && pairs.size() != 3) continue;
++it; if(winning.set.size() == 3) {//Clamp to 5 max.
continue; pairs.pop_back();
}
if(winning.set.size() == 3) {
winning.set.pop_back();
} }
// Copy found pairs. // Copy found pairs.
auto itPairs = pairs.begin(); for(j = 0; j < pairs.size(); j++) {
while(itPairs != pairs.end()) { winning.set.push_back(pairs[j]);
winning.set.push_back(*itPairs);
++itPairs;
} }
// Winned? // Winned?
if(winning.set.size() != 5) { if(winning.set.size() != POKER_WINNING_SET_SIZE) continue;
++it;
continue;
}
winning.type = POKER_WINNING_TYPE_FULL_HOUSE; winning.type = POKER_WINNING_TYPE_FULL_HOUSE;
pokerWinnerFillRemaining(winning); winning.fillRemaining();
return winning; return winning;
} }
// Flush (5 same suit) // Flush (5 same suit)
for(i = 0; i < winning->fullSize; i++) { for(i = 0; i < winning.full.size(); i++) {
card = winning->full[i]; card = winning.full[i];
suit = cardGetSuit(card); suit = card.getSuit();
winning->setSize = 1;
for(j = i+1; j < winning->fullSize; j++) { winning.set.clear();
if(cardGetSuit(winning->full[j]) != suit) continue; winning.set.push_back(card);
winning->set[winning->setSize++] = winning->full[j];
if(winning->setSize == POKER_WINNING_SET_SIZE) break; for(j = i+1; j < winning.full.size(); j++) {
if(winning.full[j].getSuit() != suit) continue;
winning.set.push_back(winning.full[j]);
if(winning.set.size() == POKER_WINNING_SET_SIZE) break;
} }
if(winning->setSize < POKER_WINNING_SET_SIZE) continue; if(winning.set.size() < POKER_WINNING_SET_SIZE) continue;
winning->set[0] = winning->full[i]; winning.type = POKER_WINNING_TYPE_FLUSH;
winning->type = POKER_WINNING_TYPE_FLUSH; winning.fillRemaining();
pokerWinnerFillRemaining(winning); return winning;
return;
} }
// Straight (sequence any suit) // Straight (sequence any suit)
winning->setSize = 0; for(i = 0; i < winning.full.size(); i++) {
for(i = 0; i < winning->fullSize; i++) { card = winning.full[i];
card = winning->full[i]; number = card.getValue();
number = cardGetNumber(card);
if(number < CARD_FIVE) continue; if(number < CARD_FIVE) continue;
winning->setSize = 1;
winning.set.clear();
winning.set.push_back(card);
for(j = 1; j <= 4; j++) { for(j = 1; j <= 4; j++) {
l = number == CARD_FIVE && j == 4 ? CARD_ACE : number - j;//Ace low. // Ace low.
index = cardContainsNumber(winning->full, winning->fullSize, l); look = (
number == CARD_FIVE && j == 4 ?
(enum CardValue)CARD_ACE :
(enum CardValue)(number - j)
);
index = Card::containsNumber(&winning.full, look);
if(index == -1) break; if(index == -1) break;
winning->set[j] = winning->full[index]; winning.set.push_back(winning.full[index]);
winning->setSize++;
} }
// Check if has all necessary cards. // Check if has all necessary cards.
if(winning->setSize < POKER_WINNING_SET_SIZE) continue; if(winning.set.size() < POKER_WINNING_SET_SIZE) continue;
winning->set[0] = winning->full[i]; winning.type = POKER_WINNING_TYPE_STRAIGHT;
winning->type = POKER_WINNING_TYPE_STRAIGHT; winning.fillRemaining();
pokerWinnerFillRemaining(winning); return winning;
return;
} }
// Three of a kind // Three of a kind
winning->setSize = 0; for(i = 0; i < winning.full.size(); i++) {
for(i = 0; i < winning->fullSize; i++) { card = winning.full[i];
card = winning->full[i]; number = card.getValue();
number = cardGetNumber(card); pairs = Card::countPairs(&winning.full, number);
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs); if(pairs.size() != 3) continue;
if(pairCount != 3) continue;
winning->setSize = pairCount; winning.set = pairs;
for(j = 0; j < pairCount; j++) winning->set[j] = winning->full[pairs[j]]; winning.type = POKER_WINNING_TYPE_THREE_OF_A_KIND;
winning->type = POKER_WINNING_TYPE_THREE_OF_A_KIND; winning.fillRemaining();
pokerWinnerFillRemaining(winning); return winning;
return;
} }
// Two Pair // Two Pair
winning->setSize = 0; winning.set.clear();
for(i = 0; i < winning->fullSize; i++) { for(i = 0; i < winning.full.size(); i++) {
card = winning->full[i];// Check we haven't already added this card. card = winning.full[i];// Check we haven't already added this card.
if( if(
winning->setSize > 0 && winning.set.size() > 0 &&
cardContains(winning->set, winning->setSize, card) != -1 Card::contains(&winning.set, card) != -1
) { ) {
continue; continue;
} }
number = cardGetNumber(card); number = card.getValue();
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs); pairs = Card::countPairs(&winning.full, number);
if(pairCount != 2) continue; if(pairs.size() != 2) continue;
for(j = 0; j < pairs.size(); j++) {
for(j = 0; j < pairCount; j++) { winning.set.push_back(pairs[j]);
winning->set[winning->setSize+j] = winning->full[pairs[j]];
} }
winning->setSize += pairCount; if(winning.set.size() != 4) continue;
if(winning->setSize != 4) continue; winning.type = POKER_WINNING_TYPE_TWO_PAIR;
winning.fillRemaining();
winning->type = POKER_WINNING_TYPE_TWO_PAIR; return winning;
pokerWinnerFillRemaining(winning);
return;
} }
// Pair // Pair
if(winning->setSize == 2) { if(winning.set.size() == 2) {
winning->type = POKER_WINNING_TYPE_PAIR; winning.type = POKER_WINNING_TYPE_PAIR;
pokerWinnerFillRemaining(winning); winning.fillRemaining();
return; return winning;
} }
// High card // High card
winning->setSize = 0; winning.set.clear();
pokerWinnerFillRemaining(winning); winning.fillRemaining();
winning->type = POKER_WINNING_TYPE_HIGH_CARD; winning.type = POKER_WINNING_TYPE_HIGH_CARD;
return winning;
return;
} }

View File

@ -30,4 +30,37 @@ float_t PokerWinning::getWinningTypeConfidence(enum PokerWinningType type) {
default: default:
return POKER_WINNING_CONFIDENCE_HIGH_CARD; return POKER_WINNING_CONFIDENCE_HIGH_CARD;
} }
}
void PokerWinning::fillRemaining() {
uint8_t i, highest, current;
struct Card highestCard(0x00);
struct Card currentCard(0x00);
// Set the kicker
this->kicker = 0xFF;
// Fill the remaining cards
while(this->set.size() < POKER_WINNING_SET_SIZE) {
highest = 0xFF;
for(i = 0; i < this->full.size(); i++) {
currentCard = this->full[i];
if(Card::contains(&this->set, currentCard) != -1) continue;
if(highest == 0xFF) {
highestCard = currentCard;
highest = highestCard.getValue();
} else {
current = currentCard.getValue();
if(current != CARD_ACE && current < highest) continue;
highestCard = currentCard;
highest = current;
}
}
if(highest == 0xFF) break;
this->set.push_back(highestCard);
}
Card::sort(&this->set);
} }

View File

@ -18,6 +18,9 @@
#define POKER_WINNING_CONFIDENCE_PAIR 0.2f #define POKER_WINNING_CONFIDENCE_PAIR 0.2f
#define POKER_WINNING_CONFIDENCE_HIGH_CARD 0.1f #define POKER_WINNING_CONFIDENCE_HIGH_CARD 0.1f
/** How many cards in the winning set */
#define POKER_WINNING_SET_SIZE 5
namespace Dawn { namespace Dawn {
enum PokerWinningType { enum PokerWinningType {
POKER_WINNING_TYPE_NULL, POKER_WINNING_TYPE_NULL,
@ -38,7 +41,14 @@ namespace Dawn {
enum PokerWinningType type; enum PokerWinningType type;
std::vector<struct Card> full; std::vector<struct Card> full;
std::vector<struct Card> set; std::vector<struct Card> set;
struct Card kicker;
PokerWinning() : kicker(0x00) {
}
static float_t getWinningTypeConfidence(enum PokerWinningType type); static float_t getWinningTypeConfidence(enum PokerWinningType type);
void fillRemaining();
}; };
} }