From 49ec91be42068fb57e68faac4ab187db9a728981 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Tue, 18 Jan 2022 16:48:29 -0800 Subject: [PATCH] Bringing over winning logic, untested --- src/conversation/queue.c | 1 + src/poker/card.c | 34 ++++ src/poker/card.h | 8 +- src/poker/poker.c | 398 ++++++++++++++++++++++++++++++++++++++- src/poker/poker.h | 5 +- 5 files changed, 443 insertions(+), 3 deletions(-) diff --git a/src/conversation/queue.c b/src/conversation/queue.c index 6a5f92b..b6b7d53 100644 --- a/src/conversation/queue.c +++ b/src/conversation/queue.c @@ -173,6 +173,7 @@ void conversationQueueFlopTurnRiver() { void conversationQueueWinnerDecide() { QUEUE_ITEM = QUEUE_DEBUG; + // TODO: Decide on a winner for real. conversationTextboxString(DEBUG_WINNER_DECIDED); } diff --git a/src/poker/card.c b/src/poker/card.c index bf355ee..d991b37 100644 --- a/src/poker/card.c +++ b/src/poker/card.c @@ -13,4 +13,38 @@ inline uint8_t cardGetNumber(uint8_t card) { inline uint8_t cardGetSuit(uint8_t card) { return card / CARD_SUIT_COUNT; +} + +inline uint8_t cardGet(uint8_t number, uint8_t suit) { + return (suit * CARD_COUNT_PER_SUIT) + number; +} + +inline uint8_t cardContains(uint8_t *hand, uint8_t length, uint8_t card) { + uint8_t i; + for(i = 0; i < length; i++) { + if(hand[i] == card) return i; + } + return 0xFF; +} + +inline uint8_t cardContainsNumber(uint8_t *hand,uint8_t length,uint8_t number) { + uint8_t i; + for(i = 0; i < length; i++) { + if(cardGetNumber(hand[i]) == number) return i; + } + return 0xFF; +} + +uint8_t cardCountPairs( + uint8_t *in, uint8_t inCount, uint8_t number, uint8_t out[CARD_SUIT_COUNT] +) { + uint8_t i, count; + + count = 0; + for(i = 0; i < inCount; i++) {// "For each suit" + if(cardGetNumber(in[i]) != number) continue; + out[count++] = i; + } + + return count; } \ No newline at end of file diff --git a/src/poker/card.h b/src/poker/card.h index 17ccf60..908ad2f 100644 --- a/src/poker/card.h +++ b/src/poker/card.h @@ -107,4 +107,10 @@ #define CARD_DECK_SIZE 52 inline uint8_t cardGetNumber(uint8_t card); -inline uint8_t cardGetSuit(uint8_t card); \ No newline at end of file +inline uint8_t cardGetSuit(uint8_t card); +inline uint8_t cardGet(uint8_t card, uint8_t suit); +inline uint8_t cardContains(uint8_t *hand, uint8_t length, uint8_t card); +inline uint8_t cardContainsNumber(uint8_t *hand,uint8_t length,uint8_t number); +uint8_t cardCountPairs( + uint8_t *in, uint8_t inCount, uint8_t number, uint8_t out[CARD_SUIT_COUNT] +); \ No newline at end of file diff --git a/src/poker/poker.c b/src/poker/poker.c index c5147ad..902cdab 100644 --- a/src/poker/poker.c +++ b/src/poker/poker.c @@ -147,6 +147,7 @@ void pokerAi(uint8_t player, pokerturn_t *turn) { uint16_t callBet, maxBet, amount, bluffBet; uint8_t random;// TODO: Determine type. uint16_t confidence, expectedGain, potOdds; + pokerplayerwinning_t winning; pokerplayer_t *plyr = POKER_PLAYERS + player; // The following logic is heavily inspired by; @@ -188,7 +189,8 @@ void pokerAi(uint8_t player, pokerturn_t *turn) { } else { // Simulate my hand being the winning hand, use that as the confidence // TODO: Repurpose old code lmao. Just take it from Dawn-C - confidence = 0; + pokerWinnerGetForPlayer(player, &winning); + confidence = pokerWinnerGetTypeConfidence(winning.type); } // Now we know how confident the AI is, let's put a chip value to that weight @@ -359,4 +361,398 @@ inline uint8_t pokerGetRemainingBetterCount() { if(pokerDoesPlayerNeedToBet(i)) count++; } return count; +} + +void pokerWinnerFillRemaining(pokerplayerwinning_t *winning) { + uint8_t i, highest, current, 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) != 0xFF) { + 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(uint8_t playerIndex,pokerplayerwinning_t *winning){ + uint8_t i, j, l, card, number, suit, pairCount; + int16_t index; + int16_t pairs[CARD_SUIT_COUNT]; + pokerplayer_t *player; + + player = POKER_PLAYERS + playerIndex; + + // Get the full poker hand (should be a 7 card hand, but MAY not be) + for(i = 0; i < POKER_COMMUNITY_SIZE; i++) { + winning->full[i] = POKER_COMMUNITY[i]; + } + for(i = 0; i < POKER_PLAYER_HAND_SIZE_MAX; i++) { + winning->full[i + POKER_COMMUNITY_SIZE] = player->hand[i]; + } + winning->fullSize = POKER_COMMUNITY_SIZE + POKER_PLAYER_HAND_SIZE_MAX; + + // TODO: Do I need to sort this? + // 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 == 0xFF) 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) != 0xFF) 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 == 0xFF) 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) != 0xFF) { + 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; +} + +inline uint16_t 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; + } +} + +uint8_t pokerWinnerCompare( + pokerplayerwinning_t *left, pokerplayerwinning_t *right +) { + uint8_t + i, number, card, countCardsSame, index, + highCardLeft, highCardRight, 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 == 0xFF) { + // 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 != 0xFF) { + 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 != 0xFF) { + index = cardContains(left->set, left->setSize, card); + if(index != 0xFF) 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( + pokerpot_t *pot, + pokerplayerwinning_t *winners, + uint8_t *winnerPlayers, + uint8_t *winnerCount, + uint8_t *participants, + uint8_t *participantCount +) { + uint8_t i, j, countPlayers, countWinners, number, highNumber, card, highCard; + pokerplayerwinning_t *left, *right; + pokerplayer_t *player; + bool isWinner; + + countPlayers = 0; + countWinners = 0; + highCard = 0xFF; + + // Get participating players and their hands. + for(i = 0; i < POKER_PLAYER_COUNT_MAX; i++) { + if(pot->players[i] == 0) continue; + + player = POKER_PLAYERS + i; + if(player->state & (POKER_PLAYER_STATE_FOLDED|POKER_PLAYER_STATE_OUT)) { + continue; + } + + participants[countPlayers] = i; + pokerWinnerGetForPlayer(i, 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; } \ No newline at end of file diff --git a/src/poker/poker.h b/src/poker/poker.h index 8eac90c..438bc1f 100644 --- a/src/poker/poker.h +++ b/src/poker/poker.h @@ -37,7 +37,10 @@ void pokerInit(); void pokerNewRound(); inline void pokerBet(uint8_t player, uint16_t amount); inline uint8_t pokerGetCallBet(uint8_t player); +void pokerAi(uint8_t player, pokerturn_t *turn); inline bool pokerCanPlayerCheck(uint8_t player); inline bool pokerDoesPlayerNeedToBet(uint8_t playerIndex); inline uint8_t pokerGetRemainingBetterCount(); -void pokerAi(uint8_t player, pokerturn_t *turn); \ No newline at end of file +void pokerWinnerFillRemaining(pokerplayerwinning_t *winning); +void pokerWinnerGetForPlayer(uint8_t playerIndex,pokerplayerwinning_t *winning); +inline uint16_t pokerWinnerGetTypeConfidence(uint8_t type); \ No newline at end of file