Dawn/src/poker/poker.c

841 lines
23 KiB
C

/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "poker.h"
void pokerInit(poker_t *poker) {
poker->playerCount = 0;
poker->playerDealer = 0;
poker->playerSmallBlind = 0;
poker->playerBigBlind = 0;
pokerResetRound(poker);
}
void pokerResetRound(poker_t *poker) {
uint8_t i;
pokerplayer_t *player;
poker->deckSize = cardWriteDeck(poker->deck);
poker->graveSize = 0;
poker->communitySize = 0;
poker->potCount = 0;
pokerPotAdd(poker);
pokerResetBettingRound(poker);
for(i = 0; i < poker->playerCount; i++) {
player = poker->players + i;
player->cardCount = 0;
player->currentBet = 0;
player->state &= ~(
POKER_PLAYER_STATE_FOLDED |
POKER_PLAYER_STATE_HAS_BET_THIS_ROUND |
POKER_PLAYER_STATE_SHOWING
);
}
}
void pokerResetBettingRound(poker_t *poker) {
uint8_t i;
pokerplayer_t *player;
// Reset the round betting state.
for(i = 0; i < poker->playerCount; i++) {
player = poker->players + i;
player->state =flagOff(player->state,POKER_PLAYER_STATE_HAS_BET_THIS_ROUND);
}
// Now reset to the first player that needs to bet.
if(poker->playerCount > 0) {
poker->better = (poker->playerBigBlind + 1) % poker->playerCount;
} else {
poker->better = 0x00;
}
// Then we check who's remaining. We do this because the default better may
// have folded already.
poker->better = pokerPlayerGetRemainingBetter(poker);
}
void pokerNewDealer(poker_t *poker) {
uint8_t i, j, k;
pokerplayer_t *player;
bool foundDealer;
bool foundSmall;
foundDealer = false;
foundSmall = false;
j = poker->playerDealer + 1;
for(i = 0; i < poker->playerCount; i++) {
k = (j + i) % poker->playerCount;
player = poker->players + k;
if(player->state & POKER_PLAYER_STATE_OUT) continue;
if(!foundDealer) {
poker->playerDealer = k;
foundDealer = true;
} else if(!foundSmall) {
poker->playerSmallBlind = k;
foundSmall = true;
} else {
poker->playerBigBlind = k;
break;
}
}
}
void pokerTakeBlinds(poker_t *poker, int32_t small, int32_t big) {
pokerPlayerBet(poker, poker->playerSmallBlind, small);
pokerPlayerBet(poker, poker->playerBigBlind, big);
}
int32_t pokerGetCallValue(poker_t *poker) {
uint8_t i;
int32_t call;
call = 0;
for(i = 0; i < poker->playerCount; i++) {
call = mathMax(call, poker->players[i].currentBet);
}
return call;
}
// Pot functions
uint8_t pokerPotAdd(poker_t *poker) {
pokerpot_t *pot;
uint8_t i = poker->potCount++;
pot = poker->pots + i;
pot->chips = 0;
pot->playerCount = 0;
return i;
}
void pokerPotAddPlayer(pokerpot_t *pot, uint8_t playerIndex) {
if(arrayContains(
sizeof(uint8_t), pot->players, pot->playerCount, &playerIndex
)) return;
pot->players[pot->playerCount++] = playerIndex;
}
// Dealer Functions
void pokerTurn(poker_t *poker, uint8_t count) {
uint8_t i;
for(i = 0; i < count; i++) {
cardDeal(
poker->deck, &poker->deckSize, poker->community, &poker->communitySize
);
}
}
void pokerBurn(poker_t *poker, uint8_t count) {
uint8_t i;
for(i = 0; i < count; i++) {
cardDeal(poker->deck, &poker->deckSize, poker->grave, &poker->graveSize);
}
}
// Player Functions
uint8_t pokerPlayerAdd(poker_t *poker) {
pokerplayer_t *player;
uint8_t i = poker->playerCount++;
player = poker->players + i;
player->cardCount = 0;
player->chips = 0;
player->currentBet = 0;
player->state = POKER_PLAYER_STATE_OUT;
return i;
}
void pokerPlayerDeal(poker_t *poker, pokerplayer_t *player, uint8_t count) {
uint8_t i;
for(i = 0; i < count; i++) {
cardDeal(poker->deck, &poker->deckSize, player->cards, &player->cardCount);
}
}
void pokerPlayerChipsAdd(pokerplayer_t *player, int32_t chips) {
player->chips += chips;
if(player->chips > 0) {
player->state = flagOff(player->state, POKER_PLAYER_STATE_OUT);
}
}
void pokerPlayerDealAll(poker_t *poker, uint8_t count) {
uint8_t i, j;
pokerplayer_t *player;
for(j = 0; j < count; j++) {
for(i = 0; i < poker->playerCount; i++) {
player = poker->players + i;
// Can't deal to a player who is folded or out
if(player->state & (POKER_PLAYER_STATE_FOLDED|POKER_PLAYER_STATE_OUT)) {
continue;
}
pokerPlayerDeal(poker, player, 1);
}
}
}
bool pokerPlayerDoesNeedToBetThisRound(poker_t *poker, uint8_t playerIndex) {
pokerplayer_t *player;
player = poker->players + playerIndex;
if(player->state & POKER_PLAYER_STATE_FOLDED) return false;
if(player->chips <= 0) return false;
if(!(player->state & POKER_PLAYER_STATE_HAS_BET_THIS_ROUND)) return true;
if(player->currentBet < pokerGetCallValue(poker)) return true;
return false;
}
uint8_t pokerPlayerGetRemainingBetter(poker_t *poker) {
uint8_t i, j;
for(i = 0; i < poker->playerCount; i++) {
j = (i + poker->playerBigBlind + 1) % poker->playerCount;
if(pokerPlayerDoesNeedToBetThisRound(poker, j)) return j;
}
return 0xFF;
}
uint8_t pokerPlayerGetNextBetter(poker_t *poker, uint8_t current) {
uint8_t i, j;
for(i = 0; i < poker->playerCount; i++) {
j = (i + current + 1) % poker->playerCount;
if(pokerPlayerDoesNeedToBetThisRound(poker, j)) return j;
}
return 0xFF;
}
int32_t pokerPlayerGetCallBet(poker_t *poker, pokerplayer_t *player) {
return pokerGetCallValue(poker) - player->currentBet;
}
uint8_t pokerInRoundGetCount(poker_t *poker) {
uint8_t i, count;
pokerplayer_t *player;
count = 0;
for(i = 0; i < poker->playerCount; i++) {
player = poker->players + i;
if(player->state & (POKER_PLAYER_STATE_FOLDED | POKER_PLAYER_STATE_OUT)) {
continue;
}
count++;
}
return count;
}
uint8_t pokerPlayerGetRemainingBetterCount(poker_t *poker) {
uint8_t i, count;
count = 0;
for(i = 0; i < poker->playerCount; i++) {
if(!pokerPlayerDoesNeedToBetThisRound(poker, i)) continue;
count++;
}
return count;
}
// Betting
void pokerPlayerBetPot(
poker_t *poker, pokerpot_t *pot, uint8_t playerIndex, int32_t chips
) {
pokerplayer_t *player;
player = poker->players + playerIndex;
player->chips -= chips;
player->currentBet += chips;
pot->chips += chips;
player->state |= POKER_PLAYER_STATE_HAS_BET_THIS_ROUND;
pokerPotAddPlayer(pot, playerIndex);
}
void pokerPlayerBet(poker_t *poker, uint8_t playerIndex, int32_t chips) {
pokerPlayerBetPot(
poker, poker->pots + (poker->potCount - 1), playerIndex, chips
);
}
bool pokerPlayerCanCheck(poker_t *poker, pokerplayer_t *player) {
return pokerGetCallValue(poker) <= player->currentBet;
}
pokerturn_t pokerTurnFold(poker_t *poker, uint8_t player) {
return (pokerturn_t){
.chips = 0,
.confidence = 1,
.type = POKER_TURN_TYPE_FOLD
};
}
pokerturn_t pokerTurnBet(poker_t *poker, uint8_t playerIndex, int32_t chips) {
pokerturn_t turn;
pokerplayer_t *player;
int32_t i;
player = poker->players + playerIndex;
turn.confidence = 1;
if(chips == 0) {
turn.type = POKER_TURN_TYPE_CHECK;
turn.chips = 0;
} else if(player->chips <= chips) {
turn.chips = player->chips;
turn.type = POKER_TURN_TYPE_ALL_IN;
} else {
turn.chips = chips;
turn.type = POKER_TURN_TYPE_BET;
i = pokerGetCallValue(poker);
if(chips == (i - player->currentBet)) {
turn.type = POKER_TURN_TYPE_CALL;
}
}
return turn;
}
pokerturn_t pokerTurnGetForPlayer(poker_t *poker, uint8_t playerIndex) {
int32_t random, maxBet, bluffBet, callBet;
float confidence, expectedGain, potOdds;
bool isBluff;
int32_t amount;
pokerplayer_t *player;
pokerplayerwinning_t winning;
uint8_t i, cardNumber0, cardNumber1, suitNumber0, suitNumber1;
pokerturn_t turn;
player = poker->players + playerIndex;
// Can the player do anything?
if(player->state & (POKER_PLAYER_STATE_FOLDED | POKER_PLAYER_STATE_OUT)) {
turn.type = POKER_TURN_TYPE_OUT;
return turn;
}
// The following logic is heavily inspired by;
// https://github.com/gorel/C-Poker-AI/blob/master/src/common/pokerai.c
// But with some changes and smarts added by me. The original source code will
// essentially just run a crap tun of simulated games and get the times that
// they are expected to win from those games, but I'm just going to use the
// odds of the winning hand.
// Is this preflop?
if(poker->communitySize == 0 && player->cardCount >= 2) {
// Get the hand weight
cardNumber0 = cardGetNumber(player->cards[0]);
cardNumber1 = cardGetNumber(player->cards[1]);
suitNumber0 = cardGetSuit(player->cards[0]);
suitNumber1 = cardGetSuit(player->cards[1]);
// Get delta between cards
i = mathAbs(cardNumber0 - cardNumber1);
// Get card weight
confidence = (float)cardNumber0 + (float)cardNumber1;
if(cardNumber0 == cardNumber1) {// Pairs
confidence += 6;
} else if(suitNumber0 == suitNumber1) {// Same suit
confidence += 4;
}
// Get difference from cards for guessing flush
if(i > 4) {
confidence -= 4;
} else if(i > 2) {
confidence -= i;
}
// Get the confidence delta 0-1
confidence = confidence / 30.0f;
} else {
// Simulate my hand being the winning hand, use that as the confidence
// pokerWinnerPlayerGet(&poker->community, player, &winning);
// confidence = pokerWinnerGetTypeConfidence(winning.type);
}
// Now we know how confident the AI is, let's put a chip value to that weight
// How many chips to call?
callBet = pokerPlayerGetCallBet(poker, player);
// Do they need chips to call, or is it possible to check?
// if(callBet > 0) {
// potOdds = (float)callBet / ((float)callBet + (float)poker->bet.pot);
// } else {
// potOdds = (
// 1.0f / (float)pokerBetGetRemainingPlayerCount(&poker->bet, poker->players)
// );
// }
// Now determine the expected ROI
expectedGain = confidence / potOdds;
// Now get a random 0-100
random = randInt32() % 100;
// Determine the max bet that the AI is willing to make
maxBet = (int32_t)((float)player->chips / 1.75f) - (random / 2);
maxBet -= callBet;
// Determine what's a good bluff bet.
bluffBet = random * maxBet / 100 / 2;
// Now prep the output
isBluff = false;
amount = 0;
// Now the actual AI can happen. This is basically a weight to confidence
// ratio. The higher the gains and the confidence then the more likely the AI
// is to betting. There are also bluff chances within here.
if(expectedGain < 0.8 && confidence < 0.8) {
if(random < 95) {
amount = 0;
} else {
amount = bluffBet;
isBluff = true;
}
} else if ((expectedGain < 1.0 && confidence < 0.85) || confidence < 0.1) {
if (random < 80) {
amount = 0;
} else if(random < 5) {
amount = callBet;
isBluff = true;
} else {
amount = bluffBet;
isBluff = true;
}
} else if ((expectedGain < 1.3 && confidence < 0.9) || confidence < 0.5) {
if (random < 60 || confidence < 0.5) {
amount = callBet;
} else {
amount = maxBet;
}
} else if (confidence < 0.95 || poker->communitySize < 0x04) {
if(random < 20) {
amount = callBet;
} else {
amount = maxBet;
}
} else {
amount = (player->chips - callBet) * 9 / 10;
}
// If this is the first round... make it a lot less likely I'll bet
if(poker->communitySize == 0x00 && amount > callBet) {
if(random > 5) amount = callBet;
}
// Did we actually bet?
// if(amount > 0) {
// printf("AI is betting %i chips, bluff: %i\n", amount, isBluff);
// // Let's not get caught in a raising loop with AI.
// if(player->timesRaised >= POKER_TURN_MAX_RAISES) {
// amount = callBet;
// }
// amount = mathMax(amount, callBet);
// turn = pokerTurnRaise(poker, playerIndex, amount);
// turn.confidence = confidence;
// } else if(pokerTurnCanPlayerCheck(poker, playerIndex)) {
// turn = pokerTurnCheck(poker, playerIndex);
// turn.confidence = 1;
// } else {
// turn = pokerTurnFold(poker, playerIndex);
// turn.confidence = 1 - confidence;
// }
return turn;
}
// Winning
void pokerHandGetFull(
poker_t *poker, pokerplayer_t *player, card_t cards[POKER_WINNING_FULL_SIZE]
) {
uint8_t i;
// Add the dealer hand
for(i = 0; i < poker->communitySize; i++) {
cards[i] = poker->community[i];
}
// Add the player hand
for(i = 0; i < player->cardCount; i++) {
cards[i+poker->communitySize] = player->cards[i];
}
}
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;
pokerHandGetFull(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]];
}
// 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_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;
}