/** * Copyright (c) 2021 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "winner.h" void pokerWinnerHandGetFull( pokerdealer_t *dealer, pokerplayer_t *player, card_t *cards ) { uint8_t i; // Add the dealer hand for(i = 0; i < dealer->cardsFacing; i++) { cards[i] = dealer->cards[i]; } // Add the player hand for(i = 0; i < player->cardCount; i++) { cards[i+dealer->cardsFacing] = player->cards[i]; } // Sort by card value cardHandSort(cards, dealer->cardsFacing + player->cardCount); } void pokerWinnerPlayerGet( pokerdealer_t *dealer, 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 = dealer->cardsFacing + player->cardCount; pokerWinnerHandGetFull(dealer, player, winning->full); // 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 ); 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; printf("Full House\n"); 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]; winning->setSize++; if(winning->setSize == POKER_WINNING_SET_SIZE) break; } if(winning->setSize < POKER_WINNING_SET_SIZE) continue; winning->set[0] = winning->full[0]; winning->type = POKER_WINNING_TYPE_FLUSH; 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; 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[j] = winning->full[winning->setSize + pairs[j]]; } // arrayCopy(sizeof(int32_t), pairs, pairCount, winning->set+winning->setSize); 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_WINNNIG_TYPE_HIGH_CARD; return; } 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); } 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 pokerWinnerCalculate( pokerwinner_t *winner, pokerdealer_t *dealer, pokerplayer_t *players ) { uint8_t i, j, number, highNumber; pokerplayerwinning_t *left, *right; pokerplayer_t *player; card_t card, highCard; bool isWinner; winner->winnerCount = 0; highCard = 0xFF; // Get winning sets for(i = 0; i < POKER_PLAYER_COUNT; i++) { left = winner->winnings + i; left->type = POKER_WINNING_TYPE_NULL; player = players + i; if(!pokerPlayerIsInRound(player)) continue; // Get the players' winning state. pokerWinnerPlayerGet(dealer, player, left); } // Compare against each player for(i = 0; i < POKER_PLAYER_COUNT; i++) { left = winner->winnings + i; if(left->type == POKER_WINNING_TYPE_NULL) continue; isWinner = true; highNumber = 0xFF; for(j = 0; j < POKER_PLAYER_COUNT; j++) { if(i == j) continue; right = winner->winnings + j; if(right->type == POKER_WINNING_TYPE_NULL) continue; // 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; winner->winners[winner->winnerCount++] = i; } } card_t pokerWinnerGetBestCard(card_t *cards, uint8_t cardCount) { uint8_t i, number, bestNumber; card_t card, bestCard; bestNumber = 0xFF; for(i = 0; i < cardCount; i++) { card = cards[i]; number = cardGetNumber(card); if(number == CARD_ACE) return card; if(bestNumber != 0xFF && number <= bestNumber) continue; bestCard = card; bestNumber = number; } return bestNumber; } float pokerWinnerGetTypeConfidence(uint8_t type) { switch(type) { case POKER_WINNING_TYPE_ROYAL_FLUSH: return POKER_WINNNIG_CONFIDENCE_ROYAL_FLUSH; case POKER_WINNING_TYPE_STRAIGHT_FLUSH: return POKER_WINNNIG_CONFIDENCE_STRAIGHT_FLUSH; case POKER_WINNING_TYPE_FOUR_OF_A_KIND: return POKER_WINNNIG_CONFIDENCE_FOUR_OF_A_KIND; case POKER_WINNING_TYPE_FULL_HOUSE: return POKER_WINNNIG_CONFIDENCE_FULL_HOUSE; case POKER_WINNING_TYPE_FLUSH: return POKER_WINNNIG_CONFIDENCE_FLUSH; case POKER_WINNING_TYPE_STRAIGHT: return POKER_WINNNIG_CONFIDENCE_STRAIGHT; case POKER_WINNING_TYPE_THREE_OF_A_KIND: return POKER_WINNNIG_CONFIDENCE_THREE_OF_A_KIND; case POKER_WINNING_TYPE_TWO_PAIR: return POKER_WINNNIG_CONFIDENCE_TWO_PAIR; case POKER_WINNING_TYPE_PAIR: return POKER_WINNNIG_CONFIDENCE_PAIR; default: return POKER_WINNNIG_CONFIDENCE_HIGH_CARD; } } float pokerWinnerGetCardWeight(card_t card) { uint8_t number; number = cardGetNumber(card); return ((float)number + 1)/((float)CARD_ACE + 1); }