Moved a tonne of code around
This commit is contained in:
65
src/dawn/poker/bet.c
Normal file
65
src/dawn/poker/bet.c
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "bet.h"
|
||||
|
||||
uint8_t pokerBetGetNextPlayer(poker_t *poker) {
|
||||
uint8_t i, j;
|
||||
for(i = 0; i < poker->playerCount; i++) {
|
||||
j = (i + poker->better + 1) % poker->playerCount;
|
||||
if(pokerPlayerDoesNeedToBetThisRound(poker, j)) return j;
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
uint8_t pokerBetGetRemainingBetterCount(poker_t *poker) {
|
||||
uint8_t i, count;
|
||||
count = 0;
|
||||
for(i = 0; i < poker->playerCount; i++) {
|
||||
if(!pokerPlayerDoesNeedToBetThisRound(poker, i)) continue;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void pokerBet(
|
||||
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;
|
||||
pot->call = mathMax(pot->call, player->currentBet);
|
||||
pokerPotAddPlayer(pot, playerIndex);
|
||||
|
||||
player->state |= POKER_PLAYER_STATE_HAS_BET_THIS_ROUND;
|
||||
if(chips > 0) player->timesRaised++;
|
||||
}
|
||||
|
||||
void pokerBetForPlayer(poker_t *poker, uint8_t playerIndex, int32_t chips) {
|
||||
pokerBet(
|
||||
poker, poker->pots + (poker->potCount - 1), playerIndex, chips
|
||||
);
|
||||
}
|
||||
|
||||
int32_t pokerBetGetCurrentCallValue(poker_t *poker) {
|
||||
uint8_t i;
|
||||
int32_t call;
|
||||
call = 0;
|
||||
for(i = 0; i < poker->potCount; i++) {
|
||||
call = mathMax(call, poker->pots[i].call);
|
||||
}
|
||||
return call;
|
||||
}
|
||||
|
||||
//eh
|
||||
int32_t pokerPlayerGetCallBet(poker_t *poker, pokerplayer_t *player) {
|
||||
return pokerBetGetCurrentCallValue(poker) - player->currentBet;
|
||||
}
|
71
src/dawn/poker/bet.h
Normal file
71
src/dawn/poker/bet.h
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/math.h"
|
||||
#include "common.h"
|
||||
#include "player.h"
|
||||
#include "pot.h"
|
||||
|
||||
/**
|
||||
* Returns the index of the first player that remains to bet for the current
|
||||
* round. This is based on whatever current better player index you provide.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param current Current better player index.
|
||||
* @return The player index of the next remaining player, otherwise 0xFF.
|
||||
*/
|
||||
uint8_t pokerBetGetNextPlayer(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Returns the count of players remaining to bet.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @return Count of players left to bet.
|
||||
*/
|
||||
uint8_t pokerBetGetRemainingBetterCount(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Let a player bet chips into the pot.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param pot Poker pot to bet in to.
|
||||
* @param playerIndex The players' index that is betting.
|
||||
* @param chips The amount of chips the player is betting.
|
||||
*/
|
||||
void pokerBet(
|
||||
poker_t *poker, pokerpot_t *pot, uint8_t playerIndex, int32_t chips
|
||||
);
|
||||
|
||||
/**
|
||||
* Let a player bet chips into the current pot.
|
||||
*
|
||||
* @param bet Poker game instance.
|
||||
* @param playerIndex The players' index that is betting.
|
||||
* @param chips The amount of chips the player is betting.
|
||||
*/
|
||||
void pokerBetForPlayer(poker_t *poker, uint8_t playerIndex, int32_t chips);
|
||||
|
||||
/**
|
||||
* Gets the amount of chips necessary to call the current bet.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @return Chips necessary to call the current bet.
|
||||
*/
|
||||
int32_t pokerBetGetCurrentCallValue(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Get the bet necessary for a specific player to make a call. This takes the
|
||||
* players current bet and the bet necessary to call into the pot and will
|
||||
* return the difference.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param player Player instance to get the call value for.
|
||||
* @return The count of chips needed to call into the current active pot.
|
||||
*/
|
||||
int32_t pokerPlayerGetCallBet(poker_t *poker, pokerplayer_t *player);
|
98
src/dawn/poker/card.c
Normal file
98
src/dawn/poker/card.c
Normal file
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include "card.h"
|
||||
|
||||
void cardDeal(
|
||||
card_t *source, uint8_t *sourceSize, card_t *dest, uint8_t *destSize
|
||||
) {
|
||||
card_t card;
|
||||
uint8_t i;
|
||||
|
||||
// Take Card
|
||||
i = *sourceSize - 1;
|
||||
card = source[i];
|
||||
*sourceSize = i;
|
||||
|
||||
// Put card
|
||||
i = *destSize;
|
||||
dest[i] = card;
|
||||
*destSize = i+1;
|
||||
}
|
||||
|
||||
void cardHandSort(card_t *cards, uint8_t length) {
|
||||
arraySort(sizeof(card_t), cards, (int32_t)length, (arraysort_t *)&_cardSorter);
|
||||
}
|
||||
|
||||
int32_t _cardSorter(const void* left, const void* right) {
|
||||
card_t cardL = *((card_t *)left);
|
||||
card_t cardR = *((card_t *)right);
|
||||
|
||||
uint8_t suitL = cardGetSuit(cardL);
|
||||
uint8_t suitR = cardGetSuit(cardR);
|
||||
if(suitL != suitR) return suitL - suitR;
|
||||
|
||||
uint8_t numberL = cardGetNumber(cardL);
|
||||
uint8_t numberR = cardGetNumber(cardR);
|
||||
|
||||
// Get the suit and the value of the card (reversed)
|
||||
return numberR - numberL;
|
||||
}
|
||||
|
||||
int32_t cardContains(card_t *hand, uint8_t length, card_t card) {
|
||||
return arrayFind(sizeof(card_t), hand, (int32_t)length, &card);
|
||||
}
|
||||
|
||||
int32_t cardContainsNumber(card_t *hand, uint8_t length, uint8_t number) {
|
||||
int32_t i;
|
||||
for(i = 0; i < length; i++) {
|
||||
if(cardGetNumber(hand[i]) == number) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t cardCountPairs(card_t *in, uint8_t inCount, uint8_t number,
|
||||
int32_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;
|
||||
}
|
||||
|
||||
void cardShuffle(card_t *hand, uint8_t length) {
|
||||
arrayShuffle(sizeof(card_t), hand, length);
|
||||
}
|
||||
|
||||
uint8_t cardWriteDeck(card_t *hand) {
|
||||
uint8_t i;
|
||||
for(i = 0; i < CARD_DECK_SIZE; i++) hand[i] = i;
|
||||
return CARD_DECK_SIZE;
|
||||
}
|
||||
|
||||
card_t cardGetHighest(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 bestCard;
|
||||
}
|
214
src/dawn/poker/card.h
Normal file
214
src/dawn/poker/card.h
Normal file
@ -0,0 +1,214 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/array.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Cards
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Aces
|
||||
#define CARD_CLUBS_TWO 0x00
|
||||
#define CARD_CLUBS_THREE 0x01
|
||||
#define CARD_CLUBS_FOUR 0x02
|
||||
#define CARD_CLUBS_FIVE 0x03
|
||||
#define CARD_CLUBS_SIX 0x04
|
||||
#define CARD_CLUBS_SEVEN 0x05
|
||||
#define CARD_CLUBS_EIGHT 0x06
|
||||
#define CARD_CLUBS_NINE 0x07
|
||||
#define CARD_CLUBS_TEN 0x08
|
||||
#define CARD_CLUBS_JACK 0x09
|
||||
#define CARD_CLUBS_QUEEN 0x0A
|
||||
#define CARD_CLUBS_KING 0x0B
|
||||
#define CARD_CLUBS_ACE 0x0C
|
||||
|
||||
// Diamonds
|
||||
#define CARD_DIAMONDS_TWO 0x0D
|
||||
#define CARD_DIAMONDS_THREE 0x0E
|
||||
#define CARD_DIAMONDS_FOUR 0x0F
|
||||
#define CARD_DIAMONDS_FIVE 0x10
|
||||
#define CARD_DIAMONDS_SIX 0x11
|
||||
#define CARD_DIAMONDS_SEVEN 0x12
|
||||
#define CARD_DIAMONDS_EIGHT 0x13
|
||||
#define CARD_DIAMONDS_NINE 0x14
|
||||
#define CARD_DIAMONDS_TEN 0x15
|
||||
#define CARD_DIAMONDS_JACK 0x16
|
||||
#define CARD_DIAMONDS_QUEEN 0x17
|
||||
#define CARD_DIAMONDS_KING 0x18
|
||||
#define CARD_DIAMONDS_ACE 0x19
|
||||
|
||||
// Hearts
|
||||
#define CARD_HEARTS_TWO 0x1A
|
||||
#define CARD_HEARTS_THREE 0x1B
|
||||
#define CARD_HEARTS_FOUR 0x1C
|
||||
#define CARD_HEARTS_FIVE 0x1D
|
||||
#define CARD_HEARTS_SIX 0x1E
|
||||
#define CARD_HEARTS_SEVEN 0x1F
|
||||
#define CARD_HEARTS_EIGHT 0x20
|
||||
#define CARD_HEARTS_NINE 0x21
|
||||
#define CARD_HEARTS_TEN 0x22
|
||||
#define CARD_HEARTS_JACK 0x23
|
||||
#define CARD_HEARTS_QUEEN 0x24
|
||||
#define CARD_HEARTS_KING 0x25
|
||||
#define CARD_HEARTS_ACE 0x26
|
||||
|
||||
// Spades
|
||||
#define CARD_SPADES_TWO 0x27
|
||||
#define CARD_SPADES_THREE 0x28
|
||||
#define CARD_SPADES_FOUR 0x29
|
||||
#define CARD_SPADES_FIVE 0x2A
|
||||
#define CARD_SPADES_SIX 0x2B
|
||||
#define CARD_SPADES_SEVEN 0x2C
|
||||
#define CARD_SPADES_EIGHT 0x2D
|
||||
#define CARD_SPADES_NINE 0x2E
|
||||
#define CARD_SPADES_TEN 0x2F
|
||||
#define CARD_SPADES_JACK 0x30
|
||||
#define CARD_SPADES_QUEEN 0x31
|
||||
#define CARD_SPADES_KING 0x32
|
||||
#define CARD_SPADES_ACE 0x33
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Suits
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define CARD_SUIT_CLUBS 0x00
|
||||
#define CARD_SUIT_DIAMONDS 0x01
|
||||
#define CARD_SUIT_HEARTS 0x02
|
||||
#define CARD_SUIT_SPADES 0x03
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Card numbers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define CARD_TWO 0x00
|
||||
#define CARD_THREE 0x01
|
||||
#define CARD_FOUR 0x02
|
||||
#define CARD_FIVE 0x03
|
||||
#define CARD_SIX 0x04
|
||||
#define CARD_SEVEN 0x05
|
||||
#define CARD_EIGHT 0x06
|
||||
#define CARD_NINE 0x07
|
||||
#define CARD_TEN 0x08
|
||||
#define CARD_JACK 0x09
|
||||
#define CARD_QUEEN 0x0A
|
||||
#define CARD_KING 0x0B
|
||||
#define CARD_ACE 0x0C
|
||||
|
||||
/** Count of cards in each suit */
|
||||
#define CARD_COUNT_PER_SUIT 13
|
||||
|
||||
/** Count of suits */
|
||||
#define CARD_SUIT_COUNT 4
|
||||
|
||||
/** Standard Card Deck Size */
|
||||
#define CARD_DECK_SIZE 52
|
||||
|
||||
/** Type Representing a card's id */
|
||||
typedef uint8_t card_t;
|
||||
|
||||
/**
|
||||
* Returns the suit of a given card.
|
||||
* @param card to get the suit for.
|
||||
* @returns The suit.
|
||||
*/
|
||||
#define cardGetSuit(card) (card / CARD_COUNT_PER_SUIT)
|
||||
|
||||
/**
|
||||
* Returns the number of a given card.
|
||||
* @param card The card to get the number for.
|
||||
* @returns The card number.
|
||||
*/
|
||||
#define cardGetNumber(card) (card % CARD_COUNT_PER_SUIT)
|
||||
|
||||
/**
|
||||
* Returns the card number for a given suit.
|
||||
* @param number The number to get.
|
||||
* @param suit The suit to get.
|
||||
* @returns The card for this suit and number combo.
|
||||
*/
|
||||
#define cardGet(number, suit) ((suit * CARD_COUNT_PER_SUIT) + number)
|
||||
|
||||
/**
|
||||
* Deals a card from an array source to an array destination. Pointers to array
|
||||
* lengths will be updated.
|
||||
*
|
||||
* @param source Array source.
|
||||
* @param sourceSize Pointer to where the count of cards is being stored.
|
||||
* @param dest Array destination.
|
||||
* @param destSize Pointer to the size of the destination array.
|
||||
*/
|
||||
void cardDeal(
|
||||
card_t *source, uint8_t *sourceSize, card_t *dest, uint8_t *destSize
|
||||
);
|
||||
|
||||
/**
|
||||
* 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 appear before
|
||||
* CARD_DIAMONDS_KING.
|
||||
*
|
||||
* @param cards Hand of cards to sort.
|
||||
* @param length Length of the array of cards.
|
||||
*/
|
||||
void cardHandSort(card_t *cards, uint8_t length);
|
||||
int32_t _cardSorter(const void* left, const void* right);
|
||||
|
||||
/**
|
||||
* Check if an array of cards contains a specific card.
|
||||
*
|
||||
* @param hand Hand/Array of cards to check.
|
||||
* @param length Length of the array of cards.
|
||||
* @param card Card to look for
|
||||
* @returns The index within the array that the card is. -1 if not found.
|
||||
*/
|
||||
int32_t cardContains(card_t *hand, uint8_t length, card_t card);
|
||||
|
||||
/**
|
||||
* Check if the array of cards contains a specific number.
|
||||
*
|
||||
* @param hand Array of cards to check
|
||||
* @param length Length of the array.
|
||||
* @param number The number to look for.
|
||||
* @returns The index within the array that the first card is. -1 if not found.
|
||||
*/
|
||||
int32_t cardContainsNumber(card_t *hand, uint8_t length, uint8_t number);
|
||||
|
||||
/**
|
||||
* Counts the amount of times a card's number appears within the given hand.
|
||||
*
|
||||
* @param in The hand to check
|
||||
* @param inCount How big the hand being checked is
|
||||
* @param number The number to look for.
|
||||
* @param out The indexes within the hand array for each card matching.
|
||||
* @return How many cards in the pair, e.g. 3 for Three of a kind, 4 for full.
|
||||
*/
|
||||
uint8_t cardCountPairs(
|
||||
card_t *in, uint8_t inCount, uint8_t number, int32_t out[4]
|
||||
);
|
||||
|
||||
/**
|
||||
* Shuffles a hand / deck
|
||||
*
|
||||
* @param hand Hand to shuffle.
|
||||
* @param length Length of the hand to shuffle.
|
||||
*/
|
||||
void cardShuffle(card_t *hand, uint8_t length);
|
||||
|
||||
/**
|
||||
* Write an entire deck of cards (in order) to a given hand.
|
||||
*
|
||||
* @param hand Hand to write the deck to.
|
||||
* @return The count of cards in the deck.
|
||||
*/
|
||||
uint8_t cardWriteDeck(card_t *hand);
|
||||
|
||||
/**
|
||||
* Get the highest card from a hand of cards.
|
||||
*
|
||||
* @param cards Array of cards.
|
||||
* @param cardCount Length of the array.
|
||||
* @return The highest card in the array.
|
||||
*/
|
||||
card_t cardGetHighest(card_t *cards, uint8_t cardCount);
|
184
src/dawn/poker/common.h
Normal file
184
src/dawn/poker/common.h
Normal file
@ -0,0 +1,184 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/flags.h"
|
||||
#include "card.h"
|
||||
|
||||
/** Maximum number of players that the game state can support */
|
||||
#define POKER_PLAYER_COUNT_MAX 5
|
||||
|
||||
/** Maximum cards a players' hand can hold */
|
||||
#define POKER_PLAYER_HAND_SIZE_MAX 2
|
||||
|
||||
/** Player States */
|
||||
#define POKER_PLAYER_STATE_FOLDED flagDefine(0)
|
||||
#define POKER_PLAYER_STATE_OUT flagDefine(1)
|
||||
#define POKER_PLAYER_STATE_HAS_BET_THIS_ROUND flagDefine(2)
|
||||
#define POKER_PLAYER_STATE_SHOWING flagDefine(3)
|
||||
|
||||
/** Maximum number of cards that the grave can hold */
|
||||
#define POKER_GRAVE_SIZE_MAX CARD_DECK_SIZE
|
||||
|
||||
/** Maximum number of community cards */
|
||||
#define POKER_COMMUNITY_SIZE_MAX 5
|
||||
|
||||
/** Maximum number of pots in the poker game. */
|
||||
#define POKER_POT_COUNT_MAX POKER_PLAYER_COUNT_MAX
|
||||
|
||||
/** Maximum number of cards a winning state can hold. */
|
||||
#define POKER_WINNING_FULL_SIZE (\
|
||||
POKER_PLAYER_HAND_SIZE_MAX + POKER_COMMUNITY_SIZE_MAX\
|
||||
)
|
||||
|
||||
/** How many cards in the winning set */
|
||||
#define POKER_WINNING_SET_SIZE 5
|
||||
|
||||
/** Winning Types */
|
||||
#define POKER_WINNING_TYPE_NULL 0x00
|
||||
#define POKER_WINNING_TYPE_ROYAL_FLUSH 0x01
|
||||
#define POKER_WINNING_TYPE_STRAIGHT_FLUSH 0x02
|
||||
#define POKER_WINNING_TYPE_FOUR_OF_A_KIND 0x03
|
||||
#define POKER_WINNING_TYPE_FULL_HOUSE 0x04
|
||||
#define POKER_WINNING_TYPE_FLUSH 0x05
|
||||
#define POKER_WINNING_TYPE_STRAIGHT 0x06
|
||||
#define POKER_WINNING_TYPE_THREE_OF_A_KIND 0x07
|
||||
#define POKER_WINNING_TYPE_TWO_PAIR 0x08
|
||||
#define POKER_WINNING_TYPE_PAIR 0x09
|
||||
#define POKER_WINNING_TYPE_HIGH_CARD 0x0A
|
||||
|
||||
#define POKER_WINNING_CONFIDENCE_ROYAL_FLUSH 1.0f
|
||||
#define POKER_WINNING_CONFIDENCE_STRAIGHT_FLUSH 0.99f
|
||||
#define POKER_WINNING_CONFIDENCE_FOUR_OF_A_KIND 0.9f
|
||||
#define POKER_WINNING_CONFIDENCE_FULL_HOUSE 0.85f
|
||||
#define POKER_WINNING_CONFIDENCE_FLUSH 0.8f
|
||||
#define POKER_WINNING_CONFIDENCE_STRAIGHT 0.7f
|
||||
#define POKER_WINNING_CONFIDENCE_THREE_OF_A_KIND 0.5f
|
||||
#define POKER_WINNING_CONFIDENCE_TWO_PAIR 0.4f
|
||||
#define POKER_WINNING_CONFIDENCE_PAIR 0.2f
|
||||
#define POKER_WINNING_CONFIDENCE_HIGH_CARD 0.1f
|
||||
|
||||
#define POKER_WORLD_DEALER_INDEX 0x02
|
||||
#define POKER_WORLD_HUMAN_INDEX 0x02
|
||||
|
||||
/** Turn Types */
|
||||
#define POKER_TURN_TYPE_OUT 0x00
|
||||
#define POKER_TURN_TYPE_FOLD 0x01
|
||||
#define POKER_TURN_TYPE_BET 0x02
|
||||
#define POKER_TURN_TYPE_CALL 0x03
|
||||
#define POKER_TURN_TYPE_ALL_IN 0x04
|
||||
#define POKER_TURN_TYPE_CALL_ALL_IN 0x04
|
||||
#define POKER_TURN_TYPE_CHECK 0x05
|
||||
|
||||
#define POKER_TURN_MAX_RAISES 0x02
|
||||
|
||||
/** How many chips each player has by defautl */
|
||||
#define POKER_BET_PLAYER_CHIPS_DEFAULT 1200
|
||||
/** The default blind cost for the big blind. */
|
||||
#define POKER_BET_BLIND_BIG_DEFAULT 600
|
||||
/** The default blind cost for the small blind. (Defaults half big blind) */
|
||||
#define POKER_BET_BLIND_SMALL_DEFAULT (POKER_BET_BLIND_BIG_DEFAULT/2)
|
||||
|
||||
/** How many cards are dealt for the flop, turn and river */
|
||||
#define POKER_FLOP_CARD_COUNT 3
|
||||
#define POKER_TURN_CARD_COUNT 1
|
||||
#define POKER_RIVER_CARD_COUNT 1
|
||||
|
||||
/** How many cards the dealer should burn before dealing the flop */
|
||||
#define POKER_FLOP_BURN_COUNT 1
|
||||
|
||||
typedef struct {
|
||||
/** Count of chips the player has */
|
||||
int32_t chips;
|
||||
|
||||
/** Cards in the players' hand */
|
||||
card_t cards[POKER_PLAYER_HAND_SIZE_MAX];
|
||||
uint8_t cardCount;
|
||||
|
||||
/** Players current state */
|
||||
uint8_t state;
|
||||
|
||||
/** Current bet that the player has done. */
|
||||
int32_t currentBet;
|
||||
|
||||
/** Count of times that the player has raised their bet */
|
||||
uint8_t timesRaised;
|
||||
} pokerplayer_t;
|
||||
|
||||
/** Holds information about a player's winning state */
|
||||
typedef struct {
|
||||
/** The full set of both the dealer and player's hand */
|
||||
card_t full[POKER_WINNING_FULL_SIZE];
|
||||
uint8_t fullSize;
|
||||
|
||||
/** Holds the winning set */
|
||||
card_t set[POKER_WINNING_SET_SIZE];
|
||||
uint8_t setSize;
|
||||
|
||||
/** Winning Type */
|
||||
uint8_t type;
|
||||
|
||||
/** If there was a kicker card it will be here, otherwise -1 for no kicker */
|
||||
card_t kicker;
|
||||
} pokerplayerwinning_t;
|
||||
|
||||
typedef struct {
|
||||
/** Current pot of chips */
|
||||
int32_t chips;
|
||||
/** Current call value for this pot */
|
||||
int32_t call;
|
||||
/** Players who are participating in the pot */
|
||||
uint8_t players[POKER_PLAYER_COUNT_MAX];
|
||||
uint8_t playerCount;
|
||||
} pokerpot_t;
|
||||
|
||||
typedef struct {
|
||||
/** What type of action the turn is */
|
||||
uint8_t type;
|
||||
/** How many chips they did in their turn (if applicable) */
|
||||
int32_t chips;
|
||||
/** How confident the AI is about their turn. 0 = none, 1 = full */
|
||||
float confidence;
|
||||
} pokerturn_t;
|
||||
|
||||
typedef struct {
|
||||
/** Current Card Deck (Dealer) */
|
||||
card_t deck[CARD_DECK_SIZE];
|
||||
uint8_t deckSize;
|
||||
|
||||
/** Card grave (where spent cards go when burned */
|
||||
card_t grave[POKER_GRAVE_SIZE_MAX];
|
||||
uint8_t graveSize;
|
||||
|
||||
/** Dealer Hand */
|
||||
card_t community[POKER_COMMUNITY_SIZE_MAX];
|
||||
uint8_t communitySize;
|
||||
|
||||
/** List of pots in the game (side pots) */
|
||||
pokerpot_t pots[POKER_POT_COUNT_MAX];
|
||||
uint8_t potCount;
|
||||
|
||||
/** Players within the game */
|
||||
pokerplayer_t players[POKER_PLAYER_COUNT_MAX];
|
||||
uint8_t playerCount;
|
||||
|
||||
/** Index of the dealer player */
|
||||
uint8_t playerDealer;
|
||||
/** Index of the small blind player */
|
||||
uint8_t playerSmallBlind;
|
||||
/** Index of the big blind player */
|
||||
uint8_t playerBigBlind;
|
||||
|
||||
/** Which player is the current active better ? */
|
||||
uint8_t better;
|
||||
|
||||
/** Size of the small blind */
|
||||
int32_t blindSmall;
|
||||
/** Size of the big blind */
|
||||
int32_t blindBig;
|
||||
} poker_t;
|
80
src/dawn/poker/dealer.c
Normal file
80
src/dawn/poker/dealer.c
Normal file
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "dealer.h"
|
||||
|
||||
void pokerDealerSet(poker_t *poker, uint8_t dealer) {
|
||||
uint8_t i, k;
|
||||
pokerplayer_t *player;
|
||||
bool foundDealer;
|
||||
bool foundSmall;
|
||||
|
||||
foundDealer = false;
|
||||
foundSmall = false;
|
||||
poker->playerDealer = dealer;
|
||||
|
||||
for(i = 0; i < poker->playerCount; i++) {
|
||||
k = (dealer + 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 pokerDealerNew(poker_t *poker) {
|
||||
pokerDealerSet(poker, poker->playerDealer + 1);
|
||||
}
|
||||
|
||||
void pokerDealerTurn(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 pokerDealerBurn(poker_t *poker, uint8_t count) {
|
||||
uint8_t i;
|
||||
for(i = 0; i < count; i++) {
|
||||
cardDeal(poker->deck, &poker->deckSize, poker->grave, &poker->graveSize);
|
||||
}
|
||||
}
|
||||
|
||||
void pokerDeal(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 pokerDealAllPlayers(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;
|
||||
}
|
||||
|
||||
pokerDeal(poker, player, 1);
|
||||
}
|
||||
}
|
||||
}
|
62
src/dawn/poker/dealer.h
Normal file
62
src/dawn/poker/dealer.h
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "common.h"
|
||||
#include "card.h"
|
||||
|
||||
/**
|
||||
* Set a next dealer. This will also select the new small and big blind players.
|
||||
* This will automatically skip out players if you provide one.
|
||||
*
|
||||
* @param poker Poker game to select a new dealer for.
|
||||
* @param dealer Dealer to become the new dealer.
|
||||
*/
|
||||
void pokerDealerSet(poker_t *poker, uint8_t dealer);
|
||||
|
||||
/**
|
||||
* Cycles to the next dealer. This will also select the new small and big blind
|
||||
* players.
|
||||
*
|
||||
* @param poker Poker game to select a new dealer for.
|
||||
*/
|
||||
void pokerDealerNew(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Turns over cards from the deck onto the table (from the deck into the dealer
|
||||
* hand)
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param count Count of cards to deal.
|
||||
*/
|
||||
void pokerDealerTurn(poker_t *poker, uint8_t count);
|
||||
|
||||
/**
|
||||
* Burns a set of cards off the top of the deck into the graveyard.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param count Count of cards to burn.
|
||||
*/
|
||||
void pokerDealerBurn(poker_t *poker, uint8_t count);
|
||||
|
||||
/**
|
||||
* Deal a card to a player.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param player Poker player to deal to.
|
||||
* @param count Count of cards to deal to the player.
|
||||
*/
|
||||
void pokerDeal(poker_t *poker, pokerplayer_t *player, uint8_t count);
|
||||
|
||||
/**
|
||||
* Deal card(s) to every active player.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param count Count of cards to deal.
|
||||
*/
|
||||
void pokerDealAllPlayers(poker_t *poker, uint8_t count);
|
59
src/dawn/poker/player.c
Normal file
59
src/dawn/poker/player.c
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "player.h"
|
||||
|
||||
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->timesRaised = 0;
|
||||
player->state = POKER_PLAYER_STATE_OUT;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void pokerPlayerChipsAdd(pokerplayer_t *player, int32_t chips) {
|
||||
player->chips += chips;
|
||||
if(player->chips > 0) {
|
||||
player->state = flagOff(player->state, POKER_PLAYER_STATE_OUT);
|
||||
}
|
||||
}
|
||||
|
||||
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 < pokerBetGetCurrentCallValue(poker)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pokerPlayerCanCheck(poker_t *poker, pokerplayer_t *player) {
|
||||
return pokerBetGetCurrentCallValue(poker) <= player->currentBet;
|
||||
}
|
||||
|
||||
void pokerPlayerGetFullHand(
|
||||
poker_t *poker, pokerplayer_t *player, card_t *cards
|
||||
) {
|
||||
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];
|
||||
}
|
||||
}
|
62
src/dawn/poker/player.h
Normal file
62
src/dawn/poker/player.h
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/flags.h"
|
||||
#include "common.h"
|
||||
#include "bet.h"
|
||||
|
||||
/**
|
||||
* Add a player to the game. The player starts in an out state (with no chips).
|
||||
*
|
||||
* @param poker Poker game instance to add to.
|
||||
* @return Player index.
|
||||
*/
|
||||
uint8_t pokerPlayerAdd(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Add chips to a player. This will also update their state if they were out
|
||||
* to ensure that they are no longer.
|
||||
*
|
||||
* @param player Player to add chips to.
|
||||
* @param chips Amount of chips to add.
|
||||
*/
|
||||
void pokerPlayerChipsAdd(pokerplayer_t *player, int32_t chips);
|
||||
|
||||
/**
|
||||
* Checks a players' state and decided whether or not the players still needs to
|
||||
* bet for the current round. This will check both whether the player has bet in
|
||||
* the current round yet, and whether or not they have met the call value of the
|
||||
* active pot.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param playerIndex Player index to check.
|
||||
* @return
|
||||
*/
|
||||
bool pokerPlayerDoesNeedToBetThisRound(poker_t *poker, uint8_t playerIndex);
|
||||
|
||||
/**
|
||||
* Determine whether or not a player CAN check, given the current max bet and
|
||||
* the players current bet.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param player Player to check.
|
||||
* @return True if the player can check, false if they need to call first.
|
||||
*/
|
||||
bool pokerPlayerCanCheck(poker_t *poker, pokerplayer_t *player);
|
||||
|
||||
/**
|
||||
* Returns the full hand for a given player including the cards on the bench.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param player Poker player to get the hand for.
|
||||
* @param cards Array to store the cards.
|
||||
*/
|
||||
void pokerPlayerGetFullHand(
|
||||
poker_t *poker, pokerplayer_t *player, card_t *cards
|
||||
);
|
96
src/dawn/poker/poker.c
Normal file
96
src/dawn/poker/poker.c
Normal file
@ -0,0 +1,96 @@
|
||||
/**
|
||||
* 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);
|
||||
pokerSetBlinds(poker, 0, 0);
|
||||
}
|
||||
|
||||
void pokerSetBlinds(poker_t *poker, int32_t blindSmall, int32_t blindBig) {
|
||||
poker->blindSmall = blindSmall;
|
||||
poker->blindBig = blindBig;
|
||||
}
|
||||
|
||||
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->timesRaised = 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);
|
||||
player->timesRaised = 0;
|
||||
}
|
||||
|
||||
// Now reset to the first player that needs to bet.
|
||||
if(poker->playerCount > 0) {
|
||||
poker->better = poker->playerBigBlind;
|
||||
} else {
|
||||
poker->better = 0x00;
|
||||
}
|
||||
|
||||
// Then we check who's remaining. We do this because the default better may
|
||||
// have folded already.
|
||||
poker->better = pokerBetGetNextPlayer(poker);
|
||||
}
|
||||
|
||||
void pokerTakeBlinds(poker_t *poker) {
|
||||
pokerplayer_t *player;
|
||||
pokerBetForPlayer(poker, poker->playerSmallBlind, poker->blindSmall);
|
||||
player = poker->players + poker->playerSmallBlind;
|
||||
player->state = flagOff(player->state, POKER_PLAYER_STATE_HAS_BET_THIS_ROUND);
|
||||
pokerBetForPlayer(poker, poker->playerBigBlind, poker->blindBig);
|
||||
player = poker->players + poker->playerBigBlind;
|
||||
player->state = flagOff(player->state, POKER_PLAYER_STATE_HAS_BET_THIS_ROUND);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
62
src/dawn/poker/poker.h
Normal file
62
src/dawn/poker/poker.h
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/flags.h"
|
||||
#include "common.h"
|
||||
#include "card.h"
|
||||
#include "pot.h"
|
||||
#include "bet.h"
|
||||
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Fucked if I know
|
||||
|
||||
/**
|
||||
* Initialize the poker game instance.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
*/
|
||||
void pokerInit(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Set the game's current blinds.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param blindSmall Small blind value.
|
||||
* @param blindBig Big blind value.
|
||||
*/
|
||||
void pokerSetBlinds(poker_t *poker, int32_t blindSmall, int32_t blindBig);
|
||||
|
||||
/**
|
||||
* Reset the poker game instance for the new round.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
*/
|
||||
void pokerResetRound(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Reset the poker betting round.
|
||||
*
|
||||
* @param poker Poker game instance to reset for.
|
||||
*/
|
||||
void pokerResetBettingRound(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Take the blinds from the blind players.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
*/
|
||||
void pokerTakeBlinds(poker_t *poker);
|
||||
|
||||
|
||||
/**
|
||||
* Gets the count of players still currently left in the round.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @return The count of players in the round.
|
||||
*/
|
||||
uint8_t pokerInRoundGetCount(poker_t *poker);
|
44
src/dawn/poker/pot.c
Normal file
44
src/dawn/poker/pot.c
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "pot.h"
|
||||
|
||||
uint8_t pokerPotAdd(poker_t *poker) {
|
||||
pokerpot_t *pot;
|
||||
uint8_t i = poker->potCount++;
|
||||
pot = poker->pots + i;
|
||||
pot->chips = 0;
|
||||
pot->playerCount = 0;
|
||||
pot->call = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
bool pokerPotHasPlayer(pokerpot_t *pot, uint8_t playerIndex) {
|
||||
return arrayContains(
|
||||
sizeof(uint8_t), pot->players, pot->playerCount, &playerIndex
|
||||
);
|
||||
}
|
||||
|
||||
void pokerPotAddPlayer(pokerpot_t *pot, uint8_t playerIndex) {
|
||||
if(pokerPotHasPlayer(pot, playerIndex)) return;
|
||||
pot->players[pot->playerCount++] = playerIndex;
|
||||
}
|
||||
|
||||
int32_t pokerPotGetSumOfChipsForPlayer(poker_t *poker, uint8_t playerIndex) {
|
||||
int32_t count;
|
||||
uint8_t i;
|
||||
pokerpot_t *pot;
|
||||
|
||||
count = 0;
|
||||
for(i = 0; i < poker->potCount; i++) {
|
||||
pot = poker->pots + i;
|
||||
if(!pokerPotHasPlayer(pot, playerIndex)) continue;
|
||||
count += pot->chips;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
47
src/dawn/poker/pot.h
Normal file
47
src/dawn/poker/pot.h
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/array.h"
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
* Adds a new pot to the poker game instance.
|
||||
*
|
||||
* @param poker Poker game instance to add a pot to.
|
||||
* @return The index of the pot within the array of pots.
|
||||
*/
|
||||
uint8_t pokerPotAdd(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Check whether or not the given player is part of the given pot.
|
||||
*
|
||||
* @param pot Pot to check.
|
||||
* @param playerIndex Player index to see if within the pot or not.
|
||||
* @return True if in the pot, otherwise false.
|
||||
*/
|
||||
bool pokerPotHasPlayer(pokerpot_t *pot, uint8_t playerIndex);
|
||||
|
||||
/**
|
||||
* Add a player to a pot. This will not let you add the same player to the pot
|
||||
* twice.
|
||||
*
|
||||
* @param pot Pot to add to.
|
||||
* @param playerIndex Players' index to add to the pot.
|
||||
*/
|
||||
void pokerPotAddPlayer(pokerpot_t *pot, uint8_t playerIndex);
|
||||
|
||||
/**
|
||||
* Returns the sum of chips in the pot(s) that the specified player is in. This
|
||||
* does not consider the pot, player or hand, just the pure sum of chips.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param playerIndex Player Index to get the sum of chips from.
|
||||
* @return The sum of chips from the pots the player is within.
|
||||
*/
|
||||
int32_t pokerPotGetSumOfChipsForPlayer(poker_t *poker, uint8_t playerIndex);
|
221
src/dawn/poker/turn.c
Normal file
221
src/dawn/poker/turn.c
Normal file
@ -0,0 +1,221 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "turn.h"
|
||||
|
||||
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 = pokerBetGetCurrentCallValue(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
|
||||
pokerWinnerGetForPlayer(poker, 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)pokerPotGetSumOfChipsForPlayer(poker, playerIndex)
|
||||
);
|
||||
} else {
|
||||
potOdds = 1.0f / (float)pokerBetGetRemainingBetterCount(poker);
|
||||
}
|
||||
|
||||
// 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 = pokerTurnBet(poker, playerIndex, amount);
|
||||
turn.confidence = confidence;
|
||||
} else if(pokerPlayerCanCheck(poker, player)) {
|
||||
turn = pokerTurnBet(poker, playerIndex, 0);
|
||||
turn.confidence = 1;
|
||||
} else {
|
||||
turn = pokerTurnFold(poker, playerIndex);
|
||||
turn.confidence = 1 - confidence;
|
||||
}
|
||||
|
||||
return turn;
|
||||
}
|
||||
|
||||
void pokerTurnAction(poker_t *poker, uint8_t playerIndex, pokerturn_t turn) {
|
||||
pokerplayer_t *player;
|
||||
player = poker->players + playerIndex;
|
||||
|
||||
switch(turn.type) {
|
||||
case POKER_TURN_TYPE_BET:
|
||||
case POKER_TURN_TYPE_CALL:
|
||||
case POKER_TURN_TYPE_ALL_IN:
|
||||
pokerBetForPlayer(poker, playerIndex, turn.chips);
|
||||
player->timesRaised++;
|
||||
break;
|
||||
|
||||
case POKER_TURN_TYPE_CHECK:
|
||||
pokerBetForPlayer(poker, playerIndex, 0);
|
||||
player->timesRaised = 0;
|
||||
break;
|
||||
|
||||
case POKER_TURN_TYPE_FOLD:
|
||||
player->state |= POKER_PLAYER_STATE_FOLDED;
|
||||
player->timesRaised = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
player->state |= POKER_PLAYER_STATE_HAS_BET_THIS_ROUND;
|
||||
}
|
52
src/dawn/poker/turn.h
Normal file
52
src/dawn/poker/turn.h
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/math.h"
|
||||
#include "common.h"
|
||||
#include "bet.h"
|
||||
#include "card.h"
|
||||
#include "winner.h"
|
||||
#include "pot.h"
|
||||
|
||||
/**
|
||||
* Return a turn action for the given player to fold.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param player Player index.
|
||||
* @return A turn for a fold action.
|
||||
*/
|
||||
pokerturn_t pokerTurnFold(poker_t *poker, uint8_t player);
|
||||
|
||||
/**
|
||||
* Perform a turn action for betting as a player.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param playerIndex Player index who is betting.
|
||||
* @param chips Chips to raise by.
|
||||
* @return A turn for a bet action.
|
||||
*/
|
||||
pokerturn_t pokerTurnBet(poker_t *poker, uint8_t playerIndex, int32_t chips);
|
||||
|
||||
/**
|
||||
* Returns the AI result for a turn done by a non human player.
|
||||
*
|
||||
* @param poker Poker game instance to use.
|
||||
* @param playerIndex Player index to get the turn for.
|
||||
* @return Some information about the move the player is trying to perform.
|
||||
*/
|
||||
pokerturn_t pokerTurnGetForPlayer(poker_t *poker, uint8_t playerIndex);
|
||||
|
||||
/**
|
||||
* Perform the turn's action.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param playerIndex Player index.
|
||||
* @param turn Turn to action.
|
||||
*/
|
||||
void pokerTurnAction(poker_t *poker, uint8_t playerIndex, pokerturn_t turn);
|
401
src/dawn/poker/winner.c
Normal file
401
src/dawn/poker/winner.c
Normal file
@ -0,0 +1,401 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
76
src/dawn/poker/winner.h
Normal file
76
src/dawn/poker/winner.h
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "card.h"
|
||||
#include "common.h"
|
||||
#include "player.h"
|
||||
|
||||
|
||||
/**
|
||||
* Fills the remaining cards for a given poker player winning hand. Essentially
|
||||
* this will just take the highest cards and slot them into the array. This also
|
||||
* sorts the cards.
|
||||
*
|
||||
* @param winning Pointer to the poker winning to fill out.
|
||||
*/
|
||||
void pokerWinnerFillRemaining(pokerplayerwinning_t *winning);
|
||||
|
||||
/**
|
||||
* Calculates and returns the winning state for a given player
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param player Player to get the state for.
|
||||
* @param winning Output winning state struct to push data in to.
|
||||
*/
|
||||
void pokerWinnerGetForPlayer(
|
||||
poker_t *poker, pokerplayer_t *player, pokerplayerwinning_t *winning
|
||||
);
|
||||
|
||||
/**
|
||||
* Compares two winning sets. The returned card is the kicker if the LEFT side
|
||||
* is the winner. If LEFT is not a winner then 0xFF will be returned.
|
||||
*
|
||||
* @param left Left winning set.
|
||||
* @param right Right winning set.
|
||||
* @return The kicker card from left's hand or 0xFF if left is not the winner.
|
||||
*/
|
||||
card_t pokerWinnerCompare(
|
||||
pokerplayerwinning_t *left, pokerplayerwinning_t *right
|
||||
);
|
||||
|
||||
/**
|
||||
* Determines the winning player for the given pot. The pot has participating
|
||||
* players, and from those participating players some will be winners. The
|
||||
* participants are only the players within the pot who haven't folded or out.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param pot Pot to get the winners for.
|
||||
* @param winners Array to store the winner state in.
|
||||
* @param winnerPlayers Array to store player indexes of each of the winners.
|
||||
* @param winnerCount Pointer to store the count of winners in.
|
||||
* @param participants Array to store player indexes of players who participate.
|
||||
* @param participantCount Pointer to store the count of participants in.
|
||||
*/
|
||||
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
|
||||
);
|
||||
|
||||
/**
|
||||
* Get the confidence of the bet for a given winning type.
|
||||
*
|
||||
* @param type Winning type type.
|
||||
* @return The confidence.
|
||||
*/
|
||||
float pokerWinnerGetTypeConfidence(uint8_t type);
|
Reference in New Issue
Block a user