Dawn/src/poker/winner.c
2021-10-14 22:02:50 -07:00

401 lines
11 KiB
C

/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "winner.h"
void pokerWinnerFillRemaining(pokerplayerwinning_t *winning) {
uint8_t i, highest, current;
card_t highestCard, currentCard;
// Set the kicker
winning->kicker = 0xFF;
// Fill the remaining cards
while(winning->setSize < POKER_WINNING_SET_SIZE) {
highest = 0xFF;
for(i = 0; i < winning->fullSize; i++) {
currentCard = winning->full[i];
if(cardContains(winning->set, winning->setSize, currentCard) != -1) {
continue;
}
if(highest == 0xFF) {
highestCard = currentCard;
highest = cardGetNumber(highestCard);
} else {
current = cardGetNumber(currentCard);
if(current != CARD_ACE && current < highest) continue;
highestCard = currentCard;
highest = current;
}
}
if(highest == 0xFF) break;
winning->set[winning->setSize++] = highestCard;
}
cardHandSort(winning->set, winning->setSize);
}
void pokerWinnerGetForPlayer(
poker_t *poker, pokerplayer_t *player, pokerplayerwinning_t *winning
) {
uint8_t i, j, l;
int32_t index;
card_t card;
uint8_t number, suit, pairCount;
int32_t pairs[CARD_SUIT_COUNT];
// Get the full poker hand (should be a 7 card hand, but MAY not be)
winning->fullSize = poker->communitySize + player->cardCount;
pokerPlayerGetFullHand(poker, player, winning->full);
cardHandSort(winning->full, winning->fullSize);
// Reset the winning status.
winning->setSize = 0;
//////////////////////// Now look for the winning set ////////////////////////
// Royal / Straight Flush
for(i = 0; i < winning->fullSize; i++) {
card = winning->full[i];
number = cardGetNumber(card);
if(number < CARD_FIVE) continue;
suit = cardGetSuit(card);
winning->setSize = 1;
// Now look for the matching cards (Reverse order to order from A to 10)
for(j = 1; j <= 4; j++) {
l = number == CARD_FIVE && j == 4 ? CARD_ACE : number - j;//Ace low.
index = cardContains(winning->full, winning->fullSize, cardGet(l, suit));
if(index == -1) break;
winning->set[j] = winning->full[index];
winning->setSize++;
}
// Check if has all necessary cards.
if(winning->setSize < POKER_WINNING_SET_SIZE) continue;
// Add self to array
winning->set[0] = winning->full[i];
winning->type = (
number == CARD_ACE ? POKER_WINNING_TYPE_ROYAL_FLUSH :
POKER_WINNING_TYPE_STRAIGHT_FLUSH
);
pokerWinnerFillRemaining(winning);
return;
}
// Four of a kind.
winning->setSize = 0;
for(i = 0; i < winning->fullSize; i++) {
card = winning->full[i];
number = cardGetNumber(card);
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
if(pairCount < CARD_SUIT_COUNT) continue;
winning->setSize = pairCount;
for(j = 0; j < pairCount; j++) winning->set[j] = winning->full[pairs[j]];
winning->type = POKER_WINNING_TYPE_FOUR_OF_A_KIND;
pokerWinnerFillRemaining(winning);
return;
}
// Full House
winning->setSize = 0;
for(i = 0; i < winning->fullSize; i++) {
// Check we haven't already added this card.
card = winning->full[i];
if(cardContains(winning->set, winning->setSize, card) != -1) continue;
number = cardGetNumber(card);
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
// Did we find either two pair or three pair?
if(pairCount != 2 && pairCount != 3) continue;
if(winning->setSize == 3) pairCount = 2;//Clamp to 5 max.
// Copy found pairs.
for(j = 0; j < pairCount; j++) {
winning->set[winning->setSize + j] = winning->full[pairs[j]];
}
winning->setSize += pairCount;
// Winned?
if(winning->setSize != POKER_WINNING_SET_SIZE) continue;
winning->type = POKER_WINNING_TYPE_FULL_HOUSE;
pokerWinnerFillRemaining(winning);
return;
}
// Flush (5 same suit)
for(i = 0; i < winning->fullSize; i++) {
card = winning->full[i];
suit = cardGetSuit(card);
winning->setSize = 1;
for(j = i+1; j < winning->fullSize; j++) {
if(cardGetSuit(winning->full[j]) != suit) continue;
winning->set[winning->setSize++] = winning->full[j];
if(winning->setSize == POKER_WINNING_SET_SIZE) break;
}
if(winning->setSize < POKER_WINNING_SET_SIZE) continue;
winning->set[0] = winning->full[i];
winning->type = POKER_WINNING_TYPE_FLUSH;
pokerWinnerFillRemaining(winning);
return;
}
// Straight (sequence any suit)
winning->setSize = 0;
for(i = 0; i < winning->fullSize; i++) {
card = winning->full[i];
number = cardGetNumber(card);
if(number < CARD_FIVE) continue;
winning->setSize = 1;
for(j = 1; j <= 4; j++) {
l = number == CARD_FIVE && j == 4 ? CARD_ACE : number - j;//Ace low.
index = cardContainsNumber(winning->full, winning->fullSize, l);
if(index == -1) break;
winning->set[j] = winning->full[index];
winning->setSize++;
}
// Check if has all necessary cards.
if(winning->setSize < POKER_WINNING_SET_SIZE) continue;
winning->set[0] = winning->full[i];
winning->type = POKER_WINNING_TYPE_STRAIGHT;
pokerWinnerFillRemaining(winning);
return;
}
// Three of a kind
winning->setSize = 0;
for(i = 0; i < winning->fullSize; i++) {
card = winning->full[i];
number = cardGetNumber(card);
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
if(pairCount != 3) continue;
winning->setSize = pairCount;
for(j = 0; j < pairCount; j++) winning->set[j] = winning->full[pairs[j]];
winning->type = POKER_WINNING_TYPE_THREE_OF_A_KIND;
pokerWinnerFillRemaining(winning);
return;
}
// Two Pair
winning->setSize = 0;
for(i = 0; i < winning->fullSize; i++) {
card = winning->full[i];// Check we haven't already added this card.
if(cardContains(winning->set, winning->setSize, card) != -1) {
continue;
}
number = cardGetNumber(card);
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
if(pairCount != 2) continue;
for(j = 0; j < pairCount; j++) {
winning->set[winning->setSize+j] = winning->full[pairs[j]];
}
winning->setSize += pairCount;
if(winning->setSize != 4) continue;
winning->type = POKER_WINNING_TYPE_TWO_PAIR;
pokerWinnerFillRemaining(winning);
return;
}
// Pair
if(winning->setSize == 2) {
winning->type = POKER_WINNING_TYPE_PAIR;
pokerWinnerFillRemaining(winning);
return;
}
// High card
winning->setSize = 0;
pokerWinnerFillRemaining(winning);
winning->type = POKER_WINNING_TYPE_HIGH_CARD;
return;
}
card_t pokerWinnerCompare(
pokerplayerwinning_t *left, pokerplayerwinning_t *right
) {
uint8_t i, number;
card_t card;
int32_t index;
uint8_t countCardsSame;
card_t highCardLeft, highCardRight;
uint8_t highNumberLeft, highNumberRight;
highNumberLeft = 0xFF;
highNumberRight = 0xFF;
countCardsSame = 0;
for(i = 0; i < left->setSize; i++) {
card = left->set[i];
number = cardGetNumber(card);
if(highNumberLeft != 0xFF && number < highNumberLeft) continue;//Quick check
// Check if this number is within the other hand or not
index = cardContainsNumber(right->set, right->setSize, number);
if(index != -1) {
// This number IS within the other hand, let's check that the EXACT card
// is a match/isn't a match.
index = cardContains(right->set, right->setSize, card);
// Exact card match
if(index != -1) {
countCardsSame++;
continue;
}
// Not exact card match.. ?
}
if(highNumberLeft == 0xFF||number == CARD_ACE||highNumberLeft < number) {
highNumberLeft = number;
highCardLeft = card;
}
}
for(i = 0; i < right->setSize; i++) {
card = right->set[i];
number = cardGetNumber(card);
if(highNumberRight != 0xFF && number < highNumberRight) continue;
index = cardContainsNumber(left->set, left->setSize, number);
if(index != -1) {
index = cardContains(left->set, left->setSize, card);
if(index != -1) continue;
}
if(highNumberRight == 0xFF||number == CARD_ACE||highNumberRight < number) {
highNumberRight = number;
highCardRight = card;
}
}
if(countCardsSame == left->setSize) {
for(i = 0; i < left->setSize; i++) {
card = left->set[i];
number = cardGetNumber(card);
if(highNumberLeft == 0xFF||number == CARD_ACE||highNumberLeft < number) {
highNumberLeft = number;
highCardLeft = card;
}
}
return highCardLeft;
}
if(highCardLeft == 0xFF) return 0xFF;
if(highNumberLeft < highNumberRight) return 0xFF;
return highCardLeft;//Greater or Equal to.
}
void pokerWinnerDetermineForPot(
poker_t *poker,
pokerpot_t *pot,
pokerplayerwinning_t winners[POKER_PLAYER_COUNT_MAX],
uint8_t winnerPlayers[POKER_PLAYER_COUNT_MAX],
uint8_t *winnerCount,
uint8_t participants[POKER_PLAYER_COUNT_MAX],
uint8_t *participantCount
) {
uint8_t i, j, countPlayers, countWinners, number, highNumber;
pokerplayerwinning_t *left, *right;
pokerplayer_t *player;
card_t card, highCard;
bool isWinner;
countPlayers = 0;
countWinners = 0;
highCard = 0xFF;
// Get participating players and their hands.
for(i = 0; i < pot->playerCount; i++) {
player = poker->players + pot->players[i];
if(player->state & (POKER_PLAYER_STATE_FOLDED|POKER_PLAYER_STATE_OUT)) {
continue;
}
participants[countPlayers] = pot->players[i];
pokerWinnerGetForPlayer(poker, player, winners + countPlayers++);
}
// Compare participating players
for(i = 0; i < countPlayers; i++) {
left = winners + i;
isWinner = true;
highNumber = 0xFF;
for(j = 0; j < countPlayers; j++) {
if(i == j) continue;
right = winners + j;
// Am I the better hand / Is it the better hand?
if(left->type < right->type) continue;
if(left->type > right->type) {
isWinner = false;
break;
}
// Equal, compare hands.
card = pokerWinnerCompare(left, right);
if(card == 0xFF) {
isWinner = false;
break;
}
// Determine high card.
number = cardGetNumber(card);
if(highNumber == 0xFF || number == CARD_ACE || number > highNumber) {
highCard = card;
highNumber = number;
}
}
if(!isWinner) continue;
left->kicker = highCard;
winnerPlayers[countWinners++] = participants[i];
}
*participantCount = countPlayers;
*winnerCount = countWinners;
}
float pokerWinnerGetTypeConfidence(uint8_t type) {
switch(type) {
case POKER_WINNING_TYPE_ROYAL_FLUSH:
return POKER_WINNING_CONFIDENCE_ROYAL_FLUSH;
case POKER_WINNING_TYPE_STRAIGHT_FLUSH:
return POKER_WINNING_CONFIDENCE_STRAIGHT_FLUSH;
case POKER_WINNING_TYPE_FOUR_OF_A_KIND:
return POKER_WINNING_CONFIDENCE_FOUR_OF_A_KIND;
case POKER_WINNING_TYPE_FULL_HOUSE:
return POKER_WINNING_CONFIDENCE_FULL_HOUSE;
case POKER_WINNING_TYPE_FLUSH:
return POKER_WINNING_CONFIDENCE_FLUSH;
case POKER_WINNING_TYPE_STRAIGHT:
return POKER_WINNING_CONFIDENCE_STRAIGHT;
case POKER_WINNING_TYPE_THREE_OF_A_KIND:
return POKER_WINNING_CONFIDENCE_THREE_OF_A_KIND;
case POKER_WINNING_TYPE_TWO_PAIR:
return POKER_WINNING_CONFIDENCE_TWO_PAIR;
case POKER_WINNING_TYPE_PAIR:
return POKER_WINNING_CONFIDENCE_PAIR;
default:
return POKER_WINNING_CONFIDENCE_HIGH_CARD;
}
}