Started merging new poker code in.

This commit is contained in:
2021-10-09 15:43:26 -07:00
parent aff317b904
commit 131c59fbf6
41 changed files with 1380 additions and 1083 deletions

View File

@ -7,9 +7,6 @@
#pragma once
#include "../../../libs.h"
#include "../../../poker/actions/flop.h"
#include "../../../poker/turn.h"
#include "../../../poker/bet.h"
#include "../pokerdiscussion.h"
#include "action.h"
#include "restack.h"

View File

@ -7,9 +7,6 @@
#pragma once
#include "../../../libs.h"
#include "../../../poker/actions/flop.h"
#include "../../../poker/turn.h"
#include "../../../poker/bet.h"
#include "../pokerdiscussion.h"
#include "action.h"
#include "restack.h"

View File

@ -11,9 +11,6 @@
#include "action.h"
#include "../pokergame.h"
#include "../../../display/animation/queue.h"
#include "../../../poker/turn.h"
#include "../../../poker/bet.h"
#include "../../../poker/actions/flop.h"
/** Callback for when the queue restack action stars. */
void _pokerGameActionRestackOnStart(

View File

@ -6,10 +6,6 @@
#pragma once
#include "../../../libs.h"
#include "action.h"
#include "../../../poker/bet.h"
#include "../../../poker/actions/round.h"
#include "../../../poker/actions/blinds.h"
#include "../../../poker/actions/deal.h"
#include "../pokerdiscussion.h"
#include "bet.h"

View File

@ -18,7 +18,7 @@ void _pokerGameActionStartOnEnd(queue_t *queue,queueaction_t *action,uint8_t i){
pokergame_t *game = (pokergame_t *)action->data;
// Begin the match
pokerActionMatchAdd(&game->scene.conversation.actionQueue, &game->poker);
pokerInit(&game->poker);
// Say that.
data.poker = game;

View File

@ -9,7 +9,6 @@
#include "../../../libs.h"
#include "../../../vn/conversation/talk.h"
#include "../../../display/animation/queue.h"
#include "../../../poker/actions/match.h"
#include "../pokerdiscussion.h"
#include "round.h"
#include "action.h"

View File

@ -7,8 +7,6 @@
#pragma once
#include "../../../libs.h"
#include "../../../poker/winner.h"
#include "../../../poker/poker.h"
#include "../pokerdiscussion.h"
#include "action.h"
#include "round.h"

View File

@ -20,7 +20,7 @@ void pokerDiscussionGet(
case POKER_DISCUSSION_REASON_MATCH_START:
discussion->count++;
discussion->messages[0] = "Match Start";
discussion->players[0] = POKER_DEALER_INDEX;
discussion->players[0] = POKER_WORLD_DEALER_INDEX;
discussion->emotions[0] = VN_CHARACTER_EMOTION_BORED;
break;
@ -28,7 +28,7 @@ void pokerDiscussionGet(
case POKER_DISCUSSION_REASON_ROUND_START:
discussion->count++;
discussion->messages[0] = "Round Start";
discussion->players[0] = POKER_DEALER_INDEX;
discussion->players[0] = POKER_WORLD_DEALER_INDEX;
discussion->emotions[0] = VN_CHARACTER_EMOTION_BORED;
break;
@ -36,7 +36,7 @@ void pokerDiscussionGet(
case POKER_DISCUSSION_REASON_BLINDS_TAKEN:
discussion->count++;
discussion->messages[0] = "Blinds\nhave been taken.";
discussion->players[0] = POKER_DEALER_INDEX;
discussion->players[0] = POKER_WORLD_DEALER_INDEX;
discussion->emotions[0] = VN_CHARACTER_EMOTION_BORED;
break;
@ -44,7 +44,7 @@ void pokerDiscussionGet(
case POKER_DISCUSSION_REASON_DEAL:
discussion->count++;
discussion->messages[0] = "Cards dealt.";
discussion->players[0] = POKER_DEALER_INDEX;
discussion->players[0] = POKER_WORLD_DEALER_INDEX;
discussion->emotions[0] = VN_CHARACTER_EMOTION_BORED;
break;
@ -88,14 +88,14 @@ void pokerDiscussionGet(
case POKER_DISCUSSION_REASON_FLOP:
discussion->count++;
discussion->messages[0] = "Doing the flop.";
discussion->players[0] = POKER_DEALER_INDEX;
discussion->players[0] = POKER_WORLD_DEALER_INDEX;
discussion->emotions[0] = VN_CHARACTER_EMOTION_ANIME_MOM;
break;
case POKER_DISCUSSION_REASON_BETTING_DONE:
discussion->count++;
discussion->messages[0] = "Winner Winner Chicken Dinner";
discussion->players[0] = POKER_DEALER_INDEX;
discussion->players[0] = POKER_WORLD_DEALER_INDEX;
discussion->emotions[0] = VN_CHARACTER_EMOTION_SMUG_VERY;
break;
@ -103,7 +103,7 @@ void pokerDiscussionGet(
default:
discussion->count++;
discussion->messages[0] = "Hmm, this seems to be an error message.";
discussion->players[0] = POKER_DEALER_INDEX;
discussion->players[0] = POKER_WORLD_DEALER_INDEX;
discussion->emotions[0] = VN_CHARACTER_EMOTION_CONCERNED_WORRIED;
break;
}

View File

@ -10,7 +10,6 @@
#include "../../vn/conversation/vnconversation.h"
#include "../../vn/conversation/talk.h"
#include "actions/look.h"
#include "../../poker/turn.h"
/** Maximum number of messages that the discussion buffer can hold */
#define POKER_DISCUSSION_MESSAGE_COUNT_MAX 32

View File

@ -35,7 +35,7 @@ void pokerUiInit(pokerui_t *ui) {
labelInit(&ui->label);
// Initialize the frames for each player.
for(i = 0; i < POKER_PLAYER_COUNT; i++) {
for(i = 0; i < POKER_PLAYER_COUNT_MAX; i++) {
frameBufferInit(ui->frames + i,
POKER_UI_PLAYER_IMAGE_RESOLUTION,
POKER_UI_PLAYER_IMAGE_RESOLUTION
@ -65,7 +65,7 @@ void pokerUiUpdate(
// Render the face of each player.
j = 0;
shaderUse(shader);
for(i = 0; i < POKER_PLAYER_COUNT; i++) {
for(i = 0; i < POKER_PLAYER_COUNT_MAX; i++) {
player = players + j;
// Locate the XYZ position of the camera to look at the player
@ -108,100 +108,102 @@ void pokerUiRender(
scale = fontGetScale(FONT_SIZE_DEFAULT);
// <testing>
if(poker->state >= POKER_STATE_DEALING) {
for(j = 0; j < POKER_PLAYER_COUNT; j++) {
player = poker->players + j;
for(i = 0; i < player->cardCount; i++) {
pokerUiSetImageToCard(&ui->card,&assets->cardTexture,player->cards[i]);
imageRender(&ui->card, &assets->shader, i * 64.0f, j * 100.0f);
}
}
// if(poker->state >= POKER_STATE_DEALING) {
// for(j = 0; j < POKER_PLAYER_COUNT_MAX; j++) {
// player = poker->players + j;
// for(i = 0; i < player->cardCount; i++) {
// pokerUiSetImageToCard(&ui->card,&assets->cardTexture,player->cards[i]);
// imageRender(&ui->card, &assets->shader, i * 64.0f, j * 100.0f);
// }
// }
for(j = 0; j < poker->dealer.cardsFacing; j++) {
pokerUiSetImageToCard(
&ui->card, &assets->cardTexture, poker->dealer.cards[j]
);
imageRender(&ui->card, &assets->shader, 200, j * 100.0f);
}
}
// for(j = 0; j < poker->communitySize; j++) {
// pokerUiSetImageToCard(
// &ui->card, &assets->cardTexture, poker->community[j]
// );
// imageRender(&ui->card, &assets->shader, 200, j * 100.0f);
// }
// // }
// Betting UI
if(ui->betShow) {
sprintf(message, "Press down to fold, up to raise, right to check/call.");
labelSetText(&ui->label, &assets->font, message);
labelRender(&ui->label, &assets->shader, 300, 100);
// // Betting UI
// if(ui->betShow) {
// sprintf(message, "Press down to fold, up to raise, right to check/call.");
// labelSetText(&ui->label, &assets->font, message);
// labelRender(&ui->label, &assets->shader, 300, 100);
if(inputIsPressed(&engine->input, INPUT_DOWN)) {
ui->betTurn = pokerTurnFold(poker, poker->bet.better);
ui->betTurnMade = true;
} else if(inputIsPressed(&engine->input, INPUT_RIGHT)) {
if(pokerTurnCanPlayerCheck(poker, poker->bet.better)) {
ui->betTurn = pokerTurnCheck(poker, poker->bet.better);
} else {
ui->betTurn = pokerTurnCall(poker, poker->bet.better);
}
ui->betTurnMade = true;
}
// if(inputIsPressed(&engine->input, INPUT_DOWN)) {
// ui->betTurn = pokerTurnFold(poker, poker->bet.better);
// ui->betTurnMade = true;
// } else if(inputIsPressed(&engine->input, INPUT_RIGHT)) {
// if(pokerTurnCanPlayerCheck(poker, poker->bet.better)) {
// ui->betTurn = pokerTurnCheck(poker, poker->bet.better);
// } else {
// ui->betTurn = pokerTurnCall(poker, poker->bet.better);
// }
// ui->betTurnMade = true;
// }
if(ui->betTurnMade) ui->betShow = false;
}
// if(ui->betTurnMade) ui->betShow = false;
// }
// Player UI
j = 0;
for(i = 0; i < POKER_PLAYER_COUNT; i++) {
// Get the player.
player = poker->players + i;
// // Player UI
// j = 0;
// for(i = 0; i < POKER_PLAYER_COUNT; i++) {
// // Get the player.
// player = poker->players + i;
// Position the grid itself.
x = engine->render.width - POKER_UI_PLAYER_WIDTH;
y = (float)(POKER_UI_PLAYER_HEIGHT * j);
// // Position the grid itself.
// x = engine->render.width - POKER_UI_PLAYER_WIDTH;
// y = (float)(POKER_UI_PLAYER_HEIGHT * j);
// Render face
gridGetChild(&ui->grid, 1, 0, 1, 2, &gx, &gy, &gw, &gh);
shaderUseTexture(&assets->shader, &(ui->frames + j)->texture);
shaderUsePosition(&assets->shader, x + gx, y + gy, 0, 0,0,0);
primitiveDraw(&ui->quad, 0, -1);
// // Render face
// gridGetChild(&ui->grid, 1, 0, 1, 2, &gx, &gy, &gw, &gh);
// shaderUseTexture(&assets->shader, &(ui->frames + j)->texture);
// shaderUsePosition(&assets->shader, x + gx, y + gy, 0, 0,0,0);
// primitiveDraw(&ui->quad, 0, -1);
// Render chips
sprintf(message, "$%i", player->chips);
ui->label.maxWidth = -1;
labelSetText(&ui->label, &assets->font, message);
align = gridGetAndAlignChild(
&ui->grid, 0, 0, 1, 1,
ALIGN_POS_END|ALIGN_SIZE_ORIGINAL, ALIGN_POS_CENTER|ALIGN_SIZE_ORIGINAL,
ui->label.info.width, ui->label.info.height
);
labelRender(&ui->label, &assets->shader, x+align.x, y+align.y);
// // Render chips
// sprintf(message, "$%i", player->chips);
// ui->label.maxWidth = -1;
// labelSetText(&ui->label, &assets->font, message);
// align = gridGetAndAlignChild(
// &ui->grid, 0, 0, 1, 1,
// ALIGN_POS_END|ALIGN_SIZE_ORIGINAL, ALIGN_POS_CENTER|ALIGN_SIZE_ORIGINAL,
// ui->label.info.width, ui->label.info.height
// );
// labelRender(&ui->label, &assets->shader, x+align.x, y+align.y);
// Render state
if(player->state & POKER_PLAYER_STATE_OUT) {
sprintf(message, "Out");
} else if(player->state & POKER_PLAYER_STATE_FOLDED) {
sprintf(message, "Folded");
} else if(player->state & POKER_PLAYER_STATE_SHOWING) {
sprintf(message, "Showing");
} else if(poker->bet.better == j) {
sprintf(message, "Thinking");
} else {
sprintf(message, "Whatever");
}
labelSetText(&ui->label, &assets->font, message);
align = gridGetAndAlignChild(
&ui->grid, 0, 1, 1, 1,
ALIGN_POS_END | ALIGN_SIZE_ORIGINAL, ALIGN_POS_CENTER | ALIGN_SIZE_ORIGINAL,
ui->label.info.width, ui->label.info.height
);
labelRender(&ui->label, &assets->shader, x+align.x, y+align.y);
// // Render state
// if(player->state & POKER_PLAYER_STATE_OUT) {
// sprintf(message, "Out");
// } else if(player->state & POKER_PLAYER_STATE_FOLDED) {
// sprintf(message, "Folded");
// } else if(player->state & POKER_PLAYER_STATE_SHOWING) {
// sprintf(message, "Showing");
// } else if(poker->bet.better == j) {
// sprintf(message, "Thinking");
// } else {
// sprintf(message, "Whatever");
// }
// labelSetText(&ui->label, &assets->font, message);
// align = gridGetAndAlignChild(
// &ui->grid, 0, 1, 1, 1,
// ALIGN_POS_END | ALIGN_SIZE_ORIGINAL, ALIGN_POS_CENTER | ALIGN_SIZE_ORIGINAL,
// ui->label.info.width, ui->label.info.height
// );
// labelRender(&ui->label, &assets->shader, x+align.x, y+align.y);
// Increment.
j++;
}
// // Increment.
// j++;
// }
}
void pokerUiDispose(pokerui_t *ui) {
uint8_t i;
for(i = 0; i < POKER_PLAYER_COUNT; i++) frameBufferDispose(ui->frames + i);
for(i = 0; i < POKER_PLAYER_COUNT_MAX; i++) {
frameBufferDispose(ui->frames + i);
}
labelDispose(&ui->label);
primitiveDispose(&ui->quad);
imageDispose(&ui->card);

View File

@ -20,11 +20,8 @@
#include "../../vn/vncharacter.h"
#include "../../ui/grid.h"
#include "../../ui/align.h"
#include "../../poker/player.h"
#include "../../poker/poker.h"
#include "../../poker/bet.h"
#include "../../poker/turn.h"
#include "../../vn/vnscene.h"
#include "../../poker/poker.h"
#include "pokerworld.h"
#include "pokergameassets.h"
@ -47,7 +44,7 @@ typedef struct {
label_t label;
grid_t grid;
image_t card;
framebuffer_t frames[POKER_PLAYER_COUNT];
framebuffer_t frames[POKER_PLAYER_COUNT_MAX];
/** Betting UI */
bool betShow;

View File

@ -22,7 +22,7 @@ void pokerWorldInit(
skywallInit(&world->skywall);
// Initialize the players
for(i = 0x00; i < POKER_PLAYER_COUNT; i++) {
for(i = 0x00; i < POKER_PLAYER_COUNT_MAX; i++) {
character = scene->characters + scene->characterCount;
vnCharacterInit(character, &assets->pennyTexture,
POKER_WORLD_PENNY_BASE_WIDTH, POKER_WORLD_PENNY_BASE_HEIGHT,

View File

@ -13,9 +13,8 @@
#include "../../display/primitives/skywall.h"
#include "../../vn/vnscene.h"
#include "../../vn/vncharacter.h"
#include "../../poker/player.h"
#include "../../poker/dealer.h"
#include "../../engine/engine.h"
#include "../../poker/poker.h"
#include "pokergameassets.h"
/** How far away from the camera are the characters distanced */
@ -39,14 +38,16 @@
#define POKER_WORLD_SEAT_COUNT 8
/** The seat index for a given player index */
#define POKER_WORLD_SEAT_FOR_PLAYER(p) (p - (POKER_PLAYER_COUNT/2))
#define POKER_WORLD_SEAT_FOR_PLAYER(p) (p - (POKER_PLAYER_COUNT_MAX/2))
/** The seat that the dealer occupies */
#define POKER_WORLD_SEAT_DEALER POKER_WORLD_SEAT_FOR_PLAYER(POKER_DEALER_INDEX)
#define POKER_WORLD_SEAT_DEALER POKER_WORLD_SEAT_FOR_PLAYER(\
POKER_WORLD_DEALER_INDEX\
)
/** The seat index for a given character index */
#define pokerWorldSeatFromIndex(i) (\
i == POKER_DEALER_INDEX ? \
i == POKER_WORLD_DEALER_INDEX ? \
POKER_WORLD_SEAT_DEALER : \
POKER_WORLD_SEAT_FOR_PLAYER(i) \
)

View File

@ -1,31 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "blinds.h"
void _pokerActionBlindsOnStart(queue_t *queue,queueaction_t *action,uint8_t i) {
poker_t *poker;
poker = (poker_t *)action->data;
poker->state = POKER_STATE_TAKING_BLINDS;
pokerBetTakeBlinds(
&poker->bet,
poker->players,
poker->roundSmallBlind,
poker->roundBigBlind
);
printf("Taken Blinds\n");
queueNext(queue);
}
queueaction_t * pokerActionBlindsAdd(queue_t *queue, poker_t *poker) {
queueaction_t *action;
action = queueAdd(queue);
action->data = (void *)poker;
action->onStart = &_pokerActionBlindsOnStart;
return action;
}

View File

@ -1,24 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "../bet.h"
#include "../poker.h"
#include "../../libs.h"
#include "../../display/animation/queue.h"
/** Callback for the blinds action */
void _pokerActionBlindsOnStart(queue_t *queue,queueaction_t *action,uint8_t i);
/**
* Adds a blinds action onto the specified queue.
*
* @param queue Queue to add to.
* @param poker Poker game instance to deal.
* @return The queued action.
*/
queueaction_t * pokerActionBlindsAdd(queue_t *queue, poker_t *poker);

View File

@ -1,30 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "deal.h"
void _pokerActionDealOnStart(queue_t *queue, queueaction_t *action, uint8_t i) {
poker_t *poker;
poker = (poker_t *)action->data;
// Shuffle the deck
poker->state = POKER_STATE_DEALING;
cardShuffle(poker->dealer.deck, CARD_DECK_SIZE);
// Deal 2 card to each player
pokerDealerDealAll(&poker->dealer, poker->players, POKER_DEAL_CARD_EACH);
queueNext(queue);
}
queueaction_t * pokerActionDealAdd(queue_t *queue, poker_t *poker) {
queueaction_t *action;
action = queueAdd(queue);
action->data = (void *)poker;
action->onStart = &_pokerActionDealOnStart;
return action;
}

View File

@ -1,24 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "../../libs.h"
#include "../../display/animation/queue.h"
#include "../dealer.h"
#include "../poker.h"
/** Callback for the deal action */
void _pokerActionDealOnStart(queue_t *queue, queueaction_t *action, uint8_t i);
/**
* Adds a deal action onto the specified queue.
*
* @param queue Queue to add to.
* @param poker Poker game instance to deal.
* @return The queued action.
*/
queueaction_t * pokerActionDealAdd(queue_t *queue, poker_t *poker);

View File

@ -1,73 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "flop.h"
void _pokerActionFlopDo(queue_t *queue, queueaction_t *action, uint8_t count) {
poker_t *poker;
poker = (poker_t *)action->data;
poker->state = POKER_STATE_CARDS_FLOPPING;
pokerDealerBurn(&poker->dealer, POKER_FLOP_BURN_COUNT);
pokerDealerTurn(&poker->dealer, count);
printf("Turned %u cards\n", count);
queueNext(queue);
}
void _pokerActionFlopOnStart(queue_t *queue, queueaction_t *action, uint8_t i) {
_pokerActionFlopDo(queue, action, POKER_FLOP_CARD_COUNT);
}
void _pokerActionTurnOnStart(queue_t *queue, queueaction_t *action, uint8_t i) {
_pokerActionFlopDo(queue, action, POKER_TURN_CARD_COUNT);
}
void _pokerActionRiverOnStart(queue_t *queue, queueaction_t *action, uint8_t i) {
_pokerActionFlopDo(queue, action, POKER_RIVER_CARD_COUNT);
}
queueaction_t * pokerActionFlopAdd(queue_t *queue, poker_t *poker) {
queueaction_t *action;
action = queueAdd(queue);
action->data = (void *)poker;
action->onStart = &_pokerActionFlopOnStart;
return action;
}
queueaction_t * pokerActionTurnAdd(queue_t *queue, poker_t *poker) {
queueaction_t *action;
action = queueAdd(queue);
action->data = (void *)poker;
action->onStart = &_pokerActionTurnOnStart;
return action;
}
queueaction_t * pokerActionRiverAdd(queue_t *queue, poker_t *poker) {
queueaction_t *action;
action = queueAdd(queue);
action->data = (void *)poker;
action->onStart = &_pokerActionRiverOnStart;
return action;
}
queueaction_t * pokerActionNextFlopAdd(queue_t *queue, poker_t *poker) {
switch(poker->dealer.cardsFacing) {
case 0:
return pokerActionFlopAdd(queue, poker);
case POKER_FLOP_CARD_COUNT:
return pokerActionTurnAdd(queue, poker);
case POKER_FLOP_CARD_COUNT+POKER_TURN_CARD_COUNT:
return pokerActionRiverAdd(queue, poker);
default:
return NULL;
}
}

View File

@ -1,68 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "../../libs.h"
#include "../../display/animation/queue.h"
#include "../dealer.h"
#include "../poker.h"
#include "../turn.h"
/** How many cards the dealer should burn before dealing the flop */
#define POKER_FLOP_BURN_COUNT 1
/**
* Shorthand action callback parser. Takes the queue, action and the intended
* turn count to complete the action.
*
* @param queue Queue that fired the action.
* @param action Action that was fired.
* @param count Count of cards to turn over from the deck.
*/
void _pokerActionFlopDo(queue_t *queue, queueaction_t *action, uint8_t count);
/** Callbacks for River, Turn and Flop Actions */
void _pokerActionFlopOnStart(queue_t *queue, queueaction_t *action, uint8_t i);
void _pokerActionTurnOnStart(queue_t *queue, queueaction_t *action, uint8_t i);
void _pokerActionRiverOnStart(queue_t *queue, queueaction_t *action, uint8_t i);
/**
* Queues a flop action onto the queue.
*
* @param queue Queue to add to.
* @param poker Poker game instance to flop.
* @return The queued action.
*/
queueaction_t * pokerActionFlopAdd(queue_t *queue, poker_t *poker);
/**
* Queues a turn action onto the queue.
*
* @param queue Queue to add to.
* @param poker Poker game instance to turn.
* @return The queued action.
*/
queueaction_t * pokerActionTurnAdd(queue_t *queue, poker_t *poker);
/**
* Queues a river action onto the queue.
*
* @param queue Queue to add to.
* @param poker Poker game instance to river.
* @return The queued action.
*/
queueaction_t * pokerActionRiverAdd(queue_t *queue, poker_t *poker);
/**
* Queues the next type of flop action onto the queue. This will automatically
* select River, Flop or Turn depending on what's happened already.
*
* @param queue Queue to add to.
* @param poker Poker game instance
* @return The queued action.
*/
queueaction_t * pokerActionNextFlopAdd(queue_t *queue, poker_t *poker);

View File

@ -1,36 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "match.h"
void _pokerActionMatchOnStart(queue_t *queue, queueaction_t *action, uint8_t i){
poker_t *poker;
uint8_t x;
poker = (poker_t *)action->data;
poker->state = POKER_STATE_STARTING_MATCH;
// Reset the main game state. This does not init the round.
pokerBetInit(&poker->bet);
poker->roundDealer = POKER_PLAYER_COUNT-2;
// Reset the players
for(x = 0; x < POKER_PLAYER_COUNT; x++) {
poker->players[x].state = 0x00;
poker->players[x].chips = POKER_BET_PLAYER_CHIPS_DEFAULT;
}
queueNext(queue);
}
queueaction_t * pokerActionMatchAdd(queue_t *queue, poker_t *poker) {
queueaction_t *action;
action = queueAdd(queue);
action->data = (void *)poker;
action->onStart = &_pokerActionMatchOnStart;
return action;
}

View File

@ -1,22 +0,0 @@
// Copyright (c) 2021 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "../../libs.h"
#include "../../display/animation/queue.h"
#include "../bet.h"
#include "../poker.h"
/** Callback for when the poker match aciton starts */
void _pokerActionMatchOnStart(queue_t *queue, queueaction_t *action, uint8_t i);
/**
* Adds a Poker Match Begin Action onto a queue.
*
* @param queue Queue to add to
* @param poker Poker game instance to use.
* @return The queued match start action.
*/
queueaction_t * pokerActionMatchAdd(queue_t *queue, poker_t *poker);

View File

@ -1,68 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "round.h"
void _pokerActionRoundOnStart(queue_t *queue, queueaction_t *action ,uint8_t i){
uint8_t j, indexDealer, indexSmallBlind, indexBigBlind;
bool foundDealer, foundSmallBlind;
pokerplayer_t *player;
poker_t *poker;
poker = (poker_t *)action->data;
// Update game state.
poker->state = POKER_STATE_STARTING_ROUND;
// Prepare the initial game state
pokerBetReset(&poker->bet);
pokerDealerInit(&poker->dealer);
// Reset the players
for(i = 0; i < POKER_PLAYER_COUNT; i++) {
pokerPlayerReset(poker->players + i);
}
// Decide on the dealer
poker->roundDealer = (poker->roundDealer+1) % POKER_PLAYER_COUNT;
// Find (and kill) the players.
j = poker->roundDealer;
foundDealer = false;
foundSmallBlind = false;
while(true) {
player = poker->players + j;
if(!pokerPlayerIsInRound(player)) continue;
if(!foundDealer) {
indexDealer = j;
foundDealer = true;
} else if(!foundSmallBlind) {
indexSmallBlind = j;
foundSmallBlind = true;
} else {
indexBigBlind = j;
break;
}
j = (j + 1) % POKER_PLAYER_COUNT;
}
// Update players for the round.
poker->roundDealer = indexDealer;
poker->roundBigBlind = indexBigBlind;
poker->roundSmallBlind = indexSmallBlind;
queueNext(queue);
}
queueaction_t * pokerActionRoundAdd(queue_t *queue, poker_t *poker) {
queueaction_t *action;
action = queueAdd(queue);
action->data = (void *)poker;
action->onStart = &_pokerActionRoundOnStart;
return action;
}

View File

@ -1,27 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "../../libs.h"
#include "../../display/animation/queue.h"
#include "../dealer.h"
#include "../bet.h"
#include "../player.h"
#include "../poker.h"
/** Callback for when the poker round start aciton begins. */
void _pokerActionRoundOnStart(queue_t *queue, queueaction_t *action, uint8_t i);
/**
* Queues the round action onto a queue. Round action should be queued at the
* start of every poker round.
*
* @param queue Queue to add to.
* @param poker Poker game instance.
* @return The queued action.
*/
queueaction_t * pokerActionRoundAdd(queue_t *queue, poker_t *poker);

View File

@ -1,105 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "bet.h"
// Done
void pokerBetInit(pokerbet_t *bet) {
bet->blindBig = POKER_BET_BLIND_BIG_DEFAULT;
bet->blindSmall = POKER_BET_BLIND_SMALL_DEFAULT;
}
// Done
void pokerBetReset(pokerbet_t *bet) {
bet->pot = 0;
bet->currentBet = 0;
}
// Not needed
uint8_t pokerBetGetRoundPlayerDefault(uint8_t roundSmallBlind) {
return (roundSmallBlind + 1) % POKER_PLAYER_COUNT;
}
// Done
void pokerBetPlayer(pokerbet_t *bet, pokerplayer_t *player, int32_t chips) {
bet->pot += chips;
player->chips -= chips;
player->currentBet += chips;
bet->currentBet = mathMax(bet->currentBet, player->currentBet);
}
// Doneish
void pokerBetResetBetter(
pokerbet_t *bet, pokerplayer_t *players, uint8_t roundSmallBlind
) {
uint8_t i;
pokerplayer_t *player;
// Reset the round betting state.
for(i = 0; i < POKER_PLAYER_COUNT; i++) {
player = players + i;
player->state = flagOff(player->state, POKER_PLAYER_STATE_ROUND_MOVE);
}
// Now reset to the first player that needs to bet.
// We do this step first to reset the better
bet->better = pokerBetGetRoundPlayerDefault(roundSmallBlind);
// Then we check who's remaining. We do this because the default better may
// have folded already.
bet->better = pokerBetGetRemainingPlayer(bet, players, roundSmallBlind);
}
// Doneish
bool pokerBetPlayerCanBet(pokerbet_t *bet, pokerplayer_t *player) {
// Is the player out?
if(!pokerPlayerIsInRound(player)) return false;
// Is the player broke?
if(player->chips <= 0) return false;
// Does the player still need to act yet?
if(player->state & POKER_PLAYER_STATE_ROUND_MOVE) {
if(player->currentBet >= bet->currentBet) return false;
}
return true;
}
uint8_t pokerBetGetRemainingPlayer(
pokerbet_t *bet, pokerplayer_t *players, uint8_t roundSmallBlind
) {
uint8_t def, j, pi;
def = bet->better;
// Now check for any remaining players
for(j = 0; j < POKER_PLAYER_COUNT; j++) {
pi = ((def + j) % POKER_PLAYER_COUNT);
if(!pokerBetPlayerCanBet(bet, players + pi)) continue;
return pi;
}
return 0xFF;
}
uint8_t pokerBetGetRemainingPlayerCount(pokerbet_t *bet,pokerplayer_t *players){
uint8_t i, c;
c = 0;
for(i = 0; i < POKER_PLAYER_COUNT; i++) {
if(!pokerBetPlayerCanBet(bet, players + i)) continue;
c++;
}
return c;
}
void pokerBetTakeBlinds(
pokerbet_t *bet, pokerplayer_t *players,
uint8_t roundSmallBlind, uint8_t roundBigBlind
) {
pokerBetPlayer(bet, players + roundSmallBlind, bet->blindSmall);
pokerBetPlayer(bet, players + roundBigBlind, bet->blindBig);
}

View File

@ -1,117 +0,0 @@
// Copyright (c) 2021 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "../libs.h"
#include "player.h"
#include "../util/math.h"
#include "../util/array.h"
/** 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)
typedef struct {
/** Blinds */
int32_t blindSmall, blindBig;
/** How big the current bet is for the round. */
int32_t currentBet;
/** For Betting round, which player is currently betting */
uint8_t better;
/** Current pot of chips */
int32_t pot;
} pokerbet_t;
/**
* Initializes/resets the poker bet context.
*
* @param bet Poker bet instance.
*/
void pokerBetInit(pokerbet_t *bet);
/**
* Resets the bet state (for a new round).
*
* @param bet Betting stating.
*/
void pokerBetReset(pokerbet_t *bet);
/**
* The default betting player for the round.
*
* @param roundSmallBlind Current round small blind player index.
* @return The Poker round default betting player index.
*/
uint8_t pokerBetGetRoundPlayerDefault(uint8_t roundSmallBlind);
/**
* Let a player bet chips into the pot.
*
* @param bet Poker bet instance.
* @param player Poker player instance.
* @param chips Chips to bet.
*/
void pokerBetPlayer(pokerbet_t *bet, pokerplayer_t *player, int32_t chips);
/**
* Reset the current better back to the round/turns default. The better will
* always be the player to the right of the small blind player.
*
* @param bet Poker betting structure.
* @param player Array of poker players.
* @param roundSmallBlind Current round small blind player index.
*/
void pokerBetResetBetter(
pokerbet_t *poker, pokerplayer_t *players, uint8_t roundSmallBlind
);
/**
* Returns whether or not a player can bet for the current round.
*
* @param bet Game bet state.
* @param player Player to check.
* @return True if the player can bet, otherwise false.
*/
bool pokerBetPlayerCanBet(pokerbet_t *bet, pokerplayer_t *player);
/**
* Returns the index of the first player that remains to bet for the current
* round.
*
* @param bet Poker betting structure.
* @param player Array of poker players.
* @param roundSmallBlind Current round small blind player index.
* @return The player index of the remaining player, otherwise 0xFF.
*/
uint8_t pokerBetGetRemainingPlayer(
pokerbet_t *bet, pokerplayer_t *players, uint8_t roundSmallBlind
);
/**
* Returns the count of players who are still needing to bet.
*
* @param bet Betting instance
* @param players Players array.
* @return Count of players who can still bet.
*/
uint8_t pokerBetGetRemainingPlayerCount(pokerbet_t *bet,pokerplayer_t *players);
/**
* Takes the current blinds from the correct players.
*
* @param poker Poker game to take the blinds from.
*/
void pokerBetTakeBlinds(
pokerbet_t *bet, pokerplayer_t *players,
uint8_t roundSmallBlind, uint8_t roundBigBlind
);

View File

@ -1,60 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "dealer.h"
//Not needed
void pokerDealerInit(pokerdealer_t *dealer) {
uint8_t i;
dealer->graveSize = 0;
dealer->cardsFacing = 0;
dealer->deckSize = CARD_DECK_SIZE;
for(i = 0; i < CARD_DECK_SIZE; i++) dealer->deck[i] = i;
}
// Done
void pokerDealerTurn(pokerdealer_t *dealer, uint8_t count) {
uint8_t i;
for(i = 0; i < count; i++) {
cardDeal(
dealer->deck, &dealer->deckSize,
dealer->cards, &dealer->cardsFacing
);
}
}
// Done
void pokerDealerBurn(pokerdealer_t *dealer, uint8_t count) {
uint8_t i;
for(i = 0; i < count; i++) {
cardDeal(
dealer->deck, &dealer->deckSize,
dealer->grave, &dealer->graveSize
);
}
}
// Done
void pokerDealerDeal(pokerdealer_t *dealer, pokerplayer_t *player) {
cardDeal(dealer->deck, &dealer->deckSize, player->cards, &player->cardCount);
}
// Done
void pokerDealerDealAll(
pokerdealer_t *dealer, pokerplayer_t *players, uint8_t count
) {
uint8_t x, y;
pokerplayer_t *player;
for(y = 0; y < count; y++) {
for(x = 0; x < POKER_PLAYER_COUNT; x++) {
player = players + x;
if(!pokerPlayerIsInRound(player)) continue;
pokerDealerDeal(dealer, player);
}
}
}

View File

@ -1,76 +0,0 @@
// 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 "player.h"
/** How many cards the dealer can hold in their hand */
#define POKER_DEALER_HAND_SIZE 5
/** How many cards the grave can hold */
#define POKER_DEALER_GRAVE_SIZE CARD_DECK_SIZE
/** Which VN Character index is the dealer */
#define POKER_DEALER_INDEX POKER_PLAYER_HUMAN_INDEX
/** Representation of the dealer state */
typedef struct {
/** Current Card Deck */
card_t deck[CARD_DECK_SIZE];
uint8_t deckSize;
/** Dealer Hand */
card_t cards[POKER_DEALER_HAND_SIZE];
uint8_t cardsFacing;
/** Card grave (where spent cards go when burned */
card_t grave[POKER_DEALER_GRAVE_SIZE];
uint8_t graveSize;
} pokerdealer_t;
/**
* Initializes/Resets a dealer state.
*
* @param dealer Dealer's state to reset.
*/
void pokerDealerInit(pokerdealer_t *dealer);
/**
* Turns over cards from the deck onto the table (from the deck into the dealer
* hand)
*
* @param dealer Poker dealer instance.
* @param count Count of cards to deal.
*/
void pokerDealerTurn(pokerdealer_t *dealer, uint8_t count);
/**
* Burns a set of cards off the top of the deck into the graveyard.
*
* @param dealer Poker dealer instance.
* @param count Count of cards to burn.
*/
void pokerDealerBurn(pokerdealer_t *dealer, uint8_t count);
/**
* Deal a card to a player.
*
* @param dealer Poker dealer instance.
* @param player Poker player to deal to.
*/
void pokerDealerDeal(pokerdealer_t *dealer, pokerplayer_t *player);
/**
* Deal card(s) to every active player.
*
* @param dealer Poker dealer instance.
* @param players Array of poker players.
* @param count Count of cards to deal.
*/
void pokerDealerDealAll(
pokerdealer_t *dealer, pokerplayer_t *players, uint8_t count
);

View File

@ -1,35 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "player.h"
bool pokerPlayerIsInRound(pokerplayer_t *player) {
return !(
player->state & (POKER_PLAYER_STATE_FOLDED|POKER_PLAYER_STATE_OUT)
);
}
uint8_t pokerPlayerGetCountInRound(pokerplayer_t *players) {
return (uint8_t)arraySum(
sizeof(pokerplayer_t),
players,
POKER_PLAYER_COUNT,
(arraysumcallback_t *)(&pokerPlayerIsInRound)
);
}
void pokerPlayerReset(pokerplayer_t *player) {
player->cardCount = 0;
player->currentBet = 0;
player->timesRaised = 0;
// Invert then bitwise AND to turn off.
player->state &= ~(
POKER_PLAYER_STATE_FOLDED |
POKER_PLAYER_STATE_SHOWING
);
}

View File

@ -1,87 +0,0 @@
/**
* 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 "../util/array.h"
#include "card.h"
/** How many cards a player can hold in their hand */
#define POKER_PLAYER_HAND 2
/** How many players in a poker game (excludes dealer) */
#define POKER_PLAYER_COUNT 5
////////////////////////////////////////////////////////////////////////////////
// Player States
////////////////////////////////////////////////////////////////////////////////
/** State for whether or not a player has folded */
#define POKER_PLAYER_STATE_FOLDED flagDefine(0)
/** State for whether or not a player is showing their hand */
#define POKER_PLAYER_STATE_SHOWING flagDefine(1)
/** State for whether or not the player is out */
#define POKER_PLAYER_STATE_OUT flagDefine(2)
/** Flag that is reset at the start of each round, and set when move occurs. */
#define POKER_PLAYER_STATE_ROUND_MOVE flagDefine(3)
/** The index that the player who is the human... is */
#define POKER_PLAYER_HUMAN_INDEX 0x02
////////////////////////////////////////////////////////////////////////////////
// Player Definition
////////////////////////////////////////////////////////////////////////////////
/** Poker Player State */
typedef struct {
/** Cards in the players' hand */
card_t cards[POKER_PLAYER_HAND];
uint8_t cardCount;
/** Current State of player */
uint8_t state;
/** Chips in players' posession */
int32_t chips;
/** Current bet in current round player has placed */
int32_t currentBet;
/** How many times for the current flop that the player has raised */
int32_t timesRaised;
} pokerplayer_t;
/**
* Returns whether or not the player is in the current round. This does not
* consider anything about whether they can/have bet or not, simply whether or
* not they can even partake in the round.
*
* @param player
* @return true
* @return false
*/
bool pokerPlayerIsInRound(pokerplayer_t *player);
/**
* Returns the count of players who remain in the current round. This is a sum
* of pokerPlayerIsInRound.
*
* @param players
* @return uint8_t
*/
uint8_t pokerPlayerGetCountInRound(pokerplayer_t *players);
/**
* Resets a poker player's state (for a new round).
*
* @param player Player to reset.
*/
void pokerPlayerReset(pokerplayer_t *player);

View File

@ -7,33 +7,628 @@
#include "poker.h"
void pokerGameWin(poker_t *poker) {
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;
pokerplayerwinning_t *winning;
pokerplayer_t *player;
int32_t chipsRounded, chipsDifferent;
float chipsEach;
poker->state = POKER_STATE_DECIDING_WINNER;
poker->deckSize = cardWriteDeck(poker->deck);
poker->graveSize = 0;
poker->communitySize = 0;
poker->potCount = 0;
pokerPotAdd(poker);
// Get the chips each.
chipsEach = poker->bet.pot / ((float)poker->winner.winnerCount);
// Now work out the rounded offset chips.
chipsRounded = (int32_t)mathFloor(chipsEach);
chipsDifferent = poker->bet.pot - chipsRounded;
// Let's start by rewarding the winnings to the players.
for(i = 0; i < poker->winner.winnerCount; i++) {
player = poker->players + poker->winner.winners[i];
winning = poker->winner.winnings + i;
player->chips += chipsRounded;
if(i == 0) player->chips += chipsDifferent;
}
// Now kill the players who are terrible low life gamblers.
for(i = 0; i < POKER_PLAYER_COUNT; i++) {
for(i = 0; i < poker->playerCount; i++) {
player = poker->players + i;
if(player->chips <= 0) player->state &= POKER_PLAYER_STATE_OUT;
player->cardCount = 0;
player->currentBet = 0;
player->state &= ~(
POKER_PLAYER_STATE_FOLDED |
POKER_PLAYER_STATE_HAS_BET_THIS_ROUND |
POKER_PLAYER_STATE_SHOWING
);
}
}
}
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->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;
}
// 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;
}
// 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;
}

View File

@ -7,54 +7,431 @@
#pragma once
#include "../libs.h"
#include "bet.h"
#include "dealer.h"
#include "winner.h"
#include "../util/flags.h"
#include "../util/array.h"
#include "../util/math.h"
#include "card.h"
/** How many cards to deal each player during the deal round */
#define POKER_DEAL_CARD_EACH 2
/** 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
/** 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
/** 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
#define POKER_STATE_NULL 0x00
#define POKER_STATE_STARTING_MATCH 0x01
#define POKER_STATE_STARTING_ROUND 0x02
#define POKER_STATE_TAKING_BLINDS 0x03
#define POKER_STATE_DEALING 0x04
#define POKER_STATE_CARDS_FLOPPING 0x05
#define POKER_STATE_BETTING 0x06
#define POKER_STATE_DECIDING_WINNER 0x07
/** 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
/** 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)
typedef struct {
/** Poker betting state */
pokerbet_t bet;
/** Player States */
pokerdealer_t dealer;
pokerplayer_t players[POKER_PLAYER_COUNT];
/** Count of chips the player has */
int32_t chips;
/** Winning player states */
pokerwinner_t winner;
/** The current player that is the dealer */
uint8_t roundDealer;
/** Which player is the small blind for this round */
uint8_t roundSmallBlind;
/** Which player is the big blind for this round */
uint8_t roundBigBlind;
/** 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;
} 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;
/** 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;
} poker_t;
/**
* Action the poker game winning state after it has been calculated previously.
* Initialize the poker game instance.
*
* @param poker Poker game to action the winning state of.
* @param poker Poker game instance.
*/
void pokerGameWin(poker_t *poker);
void pokerInit(poker_t *poker);
/**
* Reset the poker game instance for the new round.
*
* @param poker Poker game instance.
*/
void pokerResetRound(poker_t *poker);
/**
* 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 pokerNewDealer(poker_t *poker);
/**
* Take the blinds from the blind players.
*
* @param poker Poker game instance.
* @param small Small blind amount.
* @param big Big blind amount.
*/
void pokerTakeBlinds(poker_t *poker, int32_t small, int32_t big);
/**
* 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 pokerGetCallValue(poker_t *poker);
/**
* 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);
/**
* 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);
/**
* 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 pokerTurn(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 pokerBurn(poker_t *poker, uint8_t count);
/**
* 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);
/**
* 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 pokerPlayerDeal(poker_t *poker, pokerplayer_t *player, uint8_t count);
/**
* 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);
/**
* Deal card(s) to every active player.
*
* @param poker Poker game instance.
* @param count Count of cards to deal.
*/
void pokerPlayerDealAll(poker_t *poker, uint8_t count);
/**
* 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);
/**
* Returns the index of the first player that remains to bet for the current
* round.
*
* @param poker Poker game instance.
* @return The player index of the remaining player, otherwise 0xFF.
*/
uint8_t pokerPlayerGetRemainingBetter(poker_t *poker);
/**
* 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 pokerPlayerGetNextBetter(poker_t *poker, uint8_t current);
/**
* 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);
/**
* 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 pokerPlayerBetPot(
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 pokerPlayerBet(poker_t *poker, uint8_t playerIndex, int32_t chips);
/**
* 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);
/**
* 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 full hand for a given player including the best 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 pokerHandGetFull(
poker_t *poker, pokerplayer_t *player, card_t cards[POKER_WINNING_FULL_SIZE]
);
/**
* 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
);

View File

@ -1,237 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "turn.h"
pokerturn_t pokerTurnGet(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)) {
return pokerTurnOut(poker, playerIndex);
}
// 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->dealer.cardsFacing == 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->dealer, 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 = poker->bet.currentBet - player->currentBet;
// 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->dealer.cardsFacing < 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->dealer.cardsFacing == 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;
}
void pokerTurnAction(poker_t *poker, pokerplayer_t *player, pokerturn_t *turn) {
switch(turn->type) {
case POKER_TURN_TYPE_BET:
case POKER_TURN_TYPE_CALL:
case POKER_TURN_TYPE_ALL_IN:
pokerBetPlayer(&poker->bet, player, turn->chips);
player->timesRaised++;
break;
case POKER_TURN_TYPE_CHECK:
pokerBetPlayer(&poker->bet, player, 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_ROUND_MOVE;
}
pokerturn_t pokerTurnOut(poker_t *poker, uint8_t player) {
pokerturn_t turn;
turn.type = POKER_TURN_TYPE_OUT;
return turn;
}
pokerturn_t pokerTurnFold(poker_t *poker, uint8_t player) {
pokerturn_t turn;
turn.type = POKER_TURN_TYPE_FOLD;
return turn;
}
pokerturn_t pokerTurnCheck(poker_t *poker, uint8_t player) {
return pokerTurnRaise(poker, player, 0);
}
pokerturn_t pokerTurnCall(poker_t *poker, uint8_t playerIndex) {
pokerturn_t turn;
pokerplayer_t *player;
player = poker->players + playerIndex;
turn = pokerTurnRaise(
poker, playerIndex, poker->bet.currentBet - player->currentBet
);
return turn;
}
pokerturn_t pokerTurnRaise(poker_t *poker, uint8_t playerIndex, int32_t chips) {
pokerturn_t turn;
pokerplayer_t *player;
player = poker->players + playerIndex;
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;
if(chips == (poker->bet.currentBet - player->currentBet)) {
turn.type = POKER_TURN_TYPE_CALL;
}
}
return turn;
}
bool pokerTurnCanPlayerCheck(poker_t *poker, uint8_t playerIndex) {
return (poker->players + playerIndex)->currentBet >= poker->bet.currentBet;
}

View File

@ -1,106 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "../libs.h"
#include "poker.h"
#include "winner.h"
#include "../util/rand.h"
#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
/** The turn that a player/the AI decided to do for its turn */
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;
/**
* 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 pokerTurnGet(poker_t *poker, uint8_t playerIndex);
/**
* Perform the turn's action.
*
* @param poker Poker game instance.
* @param player Player instance.
* @param turn Turn to action.
*/
void pokerTurnAction(poker_t *poker, pokerplayer_t *player, pokerturn_t *turn);
/**
* Return a turn action for the player being out.
*
* @param poker Poker game instance.
* @param player Player index.
* @return A turn for an out action.
*/
pokerturn_t pokerTurnOut(poker_t *poker, uint8_t player);
/**
* 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 check as a player.
*
* @param poker Poker game instance.
* @param player Player index for who is checking.
* @return A turn for a check action.
*/
pokerturn_t pokerTurnCheck(poker_t *poker, uint8_t player);
/**
* Perform a call as a player
*
* @param poker Poker game instance.
* @param player Player index who is calling.
* @return A turn for a call action.
*/
pokerturn_t pokerTurnCall(poker_t *poker, uint8_t player);
/**
* Perform a bet 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 pokerTurnRaise(poker_t *poker, uint8_t playerIndex, int32_t chips);
/**
* Determine whether or not a player CAN check, given the current max bet and
* the players current bet.
*
* @param poker Poker game instance.
* @param playerIndex Poker player index.
* @return True if the player can check, false if they need to call first.
*/
bool pokerTurnCanPlayerCheck(poker_t *poker, uint8_t playerIndex);

View File

@ -1,434 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "winner.h"
void pokerWinnerHandGetFull(
pokerdealer_t *dealer, pokerplayer_t *player, card_t *cards
) {
uint8_t i;
// Add the dealer hand
for(i = 0; i < dealer->cardsFacing; i++) {
cards[i] = dealer->cards[i];
}
// Add the player hand
for(i = 0; i < player->cardCount; i++) {
cards[i+dealer->cardsFacing] = player->cards[i];
}
// Sort by card value
cardHandSort(cards, dealer->cardsFacing + player->cardCount);
}
void pokerWinnerPlayerGet(
pokerdealer_t *dealer, pokerplayer_t *player, pokerplayerwinning_t *winning
) {
uint8_t i, j, l;
int32_t index;
card_t card;
uint8_t number, suit, pairCount;
int32_t pairs[CARD_SUIT_COUNT];
// Get the full poker hand (should be a 7 card hand, but MAY not be)
winning->fullSize = dealer->cardsFacing + player->cardCount;
pokerWinnerHandGetFull(dealer, player, winning->full);
// Reset the winning status.
winning->setSize = 0;
//////////////////////// Now look for the winning set ////////////////////////
// Royal / Straight Flush
for(i = 0; i < winning->fullSize; i++) {
card = winning->full[i];
number = cardGetNumber(card);
if(number < CARD_FIVE) continue;
suit = cardGetSuit(card);
winning->setSize = 1;
// Now look for the matching cards (Reverse order to order from A to 10)
for(j = 1; j <= 4; j++) {
l = number == CARD_FIVE && j == 4 ? CARD_ACE : number - j;//Ace low.
index = cardContains(winning->full, winning->fullSize, cardGet(l, suit));
if(index == -1) break;
winning->set[j] = winning->full[index];
winning->setSize++;
}
// Check if has all necessary cards.
if(winning->setSize < POKER_WINNING_SET_SIZE) continue;
// Add self to array
winning->set[0] = winning->full[i];
winning->type = (
number == CARD_ACE ? POKER_WINNING_TYPE_ROYAL_FLUSH :
POKER_WINNING_TYPE_STRAIGHT_FLUSH
);
return;
}
// Four of a kind.
winning->setSize = 0;
for(i = 0; i < winning->fullSize; i++) {
card = winning->full[i];
number = cardGetNumber(card);
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
if(pairCount < CARD_SUIT_COUNT) continue;
winning->setSize = pairCount;
for(j = 0; j < pairCount; j++) winning->set[j] = winning->full[pairs[j]];
winning->type = POKER_WINNING_TYPE_FOUR_OF_A_KIND;
_pokerWinnerFillRemaining(winning);
return;
}
// Full House
winning->setSize = 0;
for(i = 0; i < winning->fullSize; i++) {
// Check we haven't already added this card.
card = winning->full[i];
if(cardContains(winning->set, winning->setSize, card) != -1) continue;
number = cardGetNumber(card);
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
// Did we find either two pair or three pair?
if(pairCount != 2 && pairCount != 3) continue;
if(winning->setSize == 3) pairCount = 2;//Clamp to 5 max.
// Copy found pairs.
for(j = 0; j < pairCount; j++) {
winning->set[winning->setSize + j] = winning->full[pairs[j]];
}
winning->setSize += pairCount;
// Winned?
if(winning->setSize != POKER_WINNING_SET_SIZE) continue;
winning->type = POKER_WINNING_TYPE_FULL_HOUSE;
printf("Full House\n");
return;
}
// Flush (5 same suit)
for(i = 0; i < winning->fullSize; i++) {
card = winning->full[i];
suit = cardGetSuit(card);
winning->setSize = 1;
for(j = i+1; j < winning->fullSize; j++) {
if(cardGetSuit(winning->full[j]) != suit) continue;
winning->set[winning->setSize] = winning->full[j];
winning->setSize++;
if(winning->setSize == POKER_WINNING_SET_SIZE) break;
}
if(winning->setSize < POKER_WINNING_SET_SIZE) continue;
winning->set[0] = winning->full[0];
winning->type = POKER_WINNING_TYPE_FLUSH;
return;
}
// Straight (sequence any suit)
winning->setSize = 0;
for(i = 0; i < winning->fullSize; i++) {
card = winning->full[i];
number = cardGetNumber(card);
if(number < CARD_FIVE) continue;
winning->setSize = 1;
for(j = 1; j <= 4; j++) {
l = number == CARD_FIVE && j == 4 ? CARD_ACE : number - j;//Ace low.
index = cardContainsNumber(winning->full, winning->fullSize, l);
if(index == -1) break;
winning->set[j] = winning->full[index];
winning->setSize++;
}
// Check if has all necessary cards.
if(winning->setSize < POKER_WINNING_SET_SIZE) continue;
winning->set[0] = winning->full[i];
winning->type = POKER_WINNING_TYPE_STRAIGHT;
return;
}
// Three of a kind
winning->setSize = 0;
for(i = 0; i < winning->fullSize; i++) {
card = winning->full[i];
number = cardGetNumber(card);
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
if(pairCount != 3) continue;
winning->setSize = pairCount;
for(j = 0; j < pairCount; j++) winning->set[j] = winning->full[pairs[j]];
winning->type = POKER_WINNING_TYPE_THREE_OF_A_KIND;
_pokerWinnerFillRemaining(winning);
return;
}
// Two Pair
winning->setSize = 0;
for(i = 0; i < winning->fullSize; i++) {
card = winning->full[i];// Check we haven't already added this card.
if(cardContains(winning->set, winning->setSize, card) != -1) {
continue;
}
number = cardGetNumber(card);
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
if(pairCount != 2) continue;
for(j = 0; j < pairCount; j++) {
winning->set[j] = winning->full[winning->setSize + pairs[j]];
}
// arrayCopy(sizeof(int32_t), pairs, pairCount, winning->set+winning->setSize);
winning->setSize += pairCount;
if(winning->setSize != 4) continue;
winning->type = POKER_WINNING_TYPE_TWO_PAIR;
_pokerWinnerFillRemaining(winning);
return;
}
// Pair
if(winning->setSize == 2) {
winning->type = POKER_WINNING_TYPE_PAIR;
_pokerWinnerFillRemaining(winning);
return;
}
// High card
winning->setSize = 0;
_pokerWinnerFillRemaining(winning);
winning->type = POKER_WINNNIG_TYPE_HIGH_CARD;
return;
}
void _pokerWinnerFillRemaining(pokerplayerwinning_t *winning) {
uint8_t i, highest, current;
card_t highestCard, currentCard;
// Set the kicker
winning->kicker = 0xFF;
// Fill the remaining cards
while(winning->setSize < POKER_WINNING_SET_SIZE) {
highest = 0xFF;
for(i = 0; i < winning->fullSize; i++) {
currentCard = winning->full[i];
if(cardContains(winning->set, winning->setSize, currentCard) != -1) {
continue;
}
if(highest == 0xFF) {
highestCard = currentCard;
highest = cardGetNumber(highestCard);
} else {
current = cardGetNumber(currentCard);
if(current != CARD_ACE && current < highest) continue;
highestCard = currentCard;
highest = current;
}
}
if(highest == 0xFF) break;
winning->set[winning->setSize++] = highestCard;
}
cardHandSort(winning->set, winning->setSize);
}
card_t pokerWinnerCompare(pokerplayerwinning_t *left, pokerplayerwinning_t *right) {
uint8_t i, number;
card_t card;
int32_t index;
uint8_t countCardsSame;
card_t highCardLeft, highCardRight;
uint8_t highNumberLeft, highNumberRight;
highNumberLeft = 0xFF;
highNumberRight = 0xFF;
countCardsSame = 0;
for(i = 0; i < left->setSize; i++) {
card = left->set[i];
number = cardGetNumber(card);
if(highNumberLeft != 0xFF && number < highNumberLeft) continue;// Quick check
// Check if this number is within the other hand or not
index = cardContainsNumber(right->set, right->setSize, number);
if(index != -1) {
// This number IS within the other hand, let's check that the EXACT card
// is a match/isn't a match.
index = cardContains(right->set, right->setSize, card);
// Exact card match
if(index != -1) {
countCardsSame++;
continue;
}
// Not exact card match.. ?
}
if(highNumberLeft == 0xFF||number == CARD_ACE||highNumberLeft < number) {
highNumberLeft = number;
highCardLeft = card;
}
}
for(i = 0; i < right->setSize; i++) {
card = right->set[i];
number = cardGetNumber(card);
if(highNumberRight != 0xFF && number < highNumberRight) continue;
index = cardContainsNumber(left->set, left->setSize, number);
if(index != -1) {
index = cardContains(left->set, left->setSize, card);
if(index != -1) continue;
}
if(highNumberRight == 0xFF||number == CARD_ACE||highNumberRight < number) {
highNumberRight = number;
highCardRight = card;
}
}
if(countCardsSame == left->setSize) {
for(i = 0; i < left->setSize; i++) {
card = left->set[i];
number = cardGetNumber(card);
if(highNumberLeft == 0xFF||number == CARD_ACE||highNumberLeft < number) {
highNumberLeft = number;
highCardLeft = card;
}
}
return highCardLeft;
}
if(highCardLeft == 0xFF) return 0xFF;
if(highNumberLeft < highNumberRight) return 0xFF;
return highCardLeft;//Greater or Equal to.
}
void pokerWinnerCalculate(
pokerwinner_t *winner, pokerdealer_t *dealer, pokerplayer_t *players
) {
uint8_t i, j, number, highNumber;
pokerplayerwinning_t *left, *right;
pokerplayer_t *player;
card_t card, highCard;
bool isWinner;
winner->winnerCount = 0;
highCard = 0xFF;
// Get winning sets
for(i = 0; i < POKER_PLAYER_COUNT; i++) {
left = winner->winnings + i;
left->type = POKER_WINNING_TYPE_NULL;
player = players + i;
if(!pokerPlayerIsInRound(player)) continue;
// Get the players' winning state.
pokerWinnerPlayerGet(dealer, player, left);
}
// Compare against each player
for(i = 0; i < POKER_PLAYER_COUNT; i++) {
left = winner->winnings + i;
if(left->type == POKER_WINNING_TYPE_NULL) continue;
isWinner = true;
highNumber = 0xFF;
for(j = 0; j < POKER_PLAYER_COUNT; j++) {
if(i == j) continue;
right = winner->winnings + j;
if(right->type == POKER_WINNING_TYPE_NULL) continue;
// Am I the better hand / Is it the better hand?
if(left->type < right->type) continue;
if(left->type > right->type) {
isWinner = false;
break;
}
// Equal, compare hands.
card = pokerWinnerCompare(left, right);
if(card == 0xFF) {
isWinner = false;
break;
}
// Determine high card.
number = cardGetNumber(card);
if(highNumber == 0xFF || number == CARD_ACE || number > highNumber) {
highCard = card;
highNumber = number;
}
}
if(!isWinner) continue;
left->kicker = highCard;
winner->winners[winner->winnerCount++] = i;
}
}
card_t pokerWinnerGetBestCard(card_t *cards, uint8_t cardCount) {
uint8_t i, number, bestNumber;
card_t card, bestCard;
bestNumber = 0xFF;
for(i = 0; i < cardCount; i++) {
card = cards[i];
number = cardGetNumber(card);
if(number == CARD_ACE) return card;
if(bestNumber != 0xFF && number <= bestNumber) continue;
bestCard = card;
bestNumber = number;
}
return bestNumber;
}
float pokerWinnerGetTypeConfidence(uint8_t type) {
switch(type) {
case POKER_WINNING_TYPE_ROYAL_FLUSH:
return POKER_WINNNIG_CONFIDENCE_ROYAL_FLUSH;
case POKER_WINNING_TYPE_STRAIGHT_FLUSH:
return POKER_WINNNIG_CONFIDENCE_STRAIGHT_FLUSH;
case POKER_WINNING_TYPE_FOUR_OF_A_KIND:
return POKER_WINNNIG_CONFIDENCE_FOUR_OF_A_KIND;
case POKER_WINNING_TYPE_FULL_HOUSE:
return POKER_WINNNIG_CONFIDENCE_FULL_HOUSE;
case POKER_WINNING_TYPE_FLUSH:
return POKER_WINNNIG_CONFIDENCE_FLUSH;
case POKER_WINNING_TYPE_STRAIGHT:
return POKER_WINNNIG_CONFIDENCE_STRAIGHT;
case POKER_WINNING_TYPE_THREE_OF_A_KIND:
return POKER_WINNNIG_CONFIDENCE_THREE_OF_A_KIND;
case POKER_WINNING_TYPE_TWO_PAIR:
return POKER_WINNNIG_CONFIDENCE_TWO_PAIR;
case POKER_WINNING_TYPE_PAIR:
return POKER_WINNNIG_CONFIDENCE_PAIR;
default:
return POKER_WINNNIG_CONFIDENCE_HIGH_CARD;
}
}
float pokerWinnerGetCardWeight(card_t card) {
uint8_t number;
number = cardGetNumber(card);
return ((float)number + 1)/((float)CARD_ACE + 1);
}

View File

@ -1,148 +0,0 @@
/**
* 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 "player.h"
#include "winner.h"
#include "dealer.h"
/** Size of the FULL hand used to calculate a winning. */
#define POKER_WINNING_FULL_SIZE POKER_PLAYER_HAND+POKER_DEALER_HAND_SIZE
/** How many cards make a 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_WINNNIG_TYPE_HIGH_CARD 0x0A
#define POKER_WINNNIG_CONFIDENCE_ROYAL_FLUSH 1.0f
#define POKER_WINNNIG_CONFIDENCE_STRAIGHT_FLUSH 0.99f
#define POKER_WINNNIG_CONFIDENCE_FOUR_OF_A_KIND 0.9f
#define POKER_WINNNIG_CONFIDENCE_FULL_HOUSE 0.85f
#define POKER_WINNNIG_CONFIDENCE_FLUSH 0.8f
#define POKER_WINNNIG_CONFIDENCE_STRAIGHT 0.7f
#define POKER_WINNNIG_CONFIDENCE_THREE_OF_A_KIND 0.5f
#define POKER_WINNNIG_CONFIDENCE_TWO_PAIR 0.4f
#define POKER_WINNNIG_CONFIDENCE_PAIR 0.2f
#define POKER_WINNNIG_CONFIDENCE_HIGH_CARD 0.1f
/** 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 {
/** Winning States */
pokerplayerwinning_t winnings[POKER_PLAYER_COUNT];
uint8_t winners[POKER_PLAYER_COUNT];
uint8_t winnerCount;
} pokerwinner_t;
/**
* Returns the full hand for a given player including the best cards on the
* bench.
*
* @param dealer Poker game dealer instance.
* @param player Poker player game instance.
* @param cards Array of at least 7 length to store the array.
*/
void pokerWinnerHandGetFull(
pokerdealer_t *dealer, pokerplayer_t *player, card_t *cards
);
/**
* Calculates and returns the winning state for a given player
*
* @param dealer Poker game dealer instance.
* @param players Array of poker players.
* @param winning Pointer to the poker winning to fill out.
* @return The winning state for this player.
*/
void pokerWinnerPlayerGet(
pokerdealer_t *dealer, pokerplayer_t *player, pokerplayerwinning_t *winning
);
/**
* 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.
* @param winning Pointer to the poker winning to fill out.
*/
void _pokerWinnerFillRemaining(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 game. Values will be stored back into
* the poker winning state.
*
* @param winner Location to store the winner state.
* @param dealer Poker game dealer instance.
* @param players Array of poker players.
*/
void pokerWinnerCalculate(
pokerwinner_t *winner, pokerdealer_t *dealer, pokerplayer_t *players
);
/**
* Get the best valued card from a given hand.
*
* @param cards Array of cards.
* @param cardCount Count of cards in the array
* @return The best card within the array.
*/
card_t pokerWinnerGetBestCard(card_t *cards, uint8_t cardCount);
/**
* Get the confidence of the bet for a given winning type.
*
* @param type Winning type type.
* @return The confidence.
*/
float pokerWinnerGetTypeConfidence(uint8_t type);
/**
* Get the weight of a card.
*
* @param card Card to get the weight of.
* @return The cards' weight.
*/
float pokerWinnerGetCardWeight(card_t card);

View File

@ -1,633 +0,0 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "poker.h"
void pokerInit(poker2_t *poker) {
poker->playerCount = 0;
poker->playerDealer = 0;
poker->playerSmallBlind = 0;
poker->playerBigBlind = 0;
pokerResetRound(poker);
}
void pokerResetRound(poker2_t *poker) {
uint8_t i;
poker2player_t *player;
poker->deckSize = cardWriteDeck(poker->deck);
poker->graveSize = 0;
poker->communitySize = 0;
poker->potCount = 0;
pokerPotAdd(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
);
}
}
void pokerNewDealer(poker2_t *poker) {
uint8_t i, j, k;
poker2player_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(poker2_t *poker, int32_t small, int32_t big) {
pokerPlayerBet(poker, poker->playerSmallBlind, small);
pokerPlayerBet(poker, poker->playerBigBlind, big);
}
int32_t pokerGetCallValue(poker2_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(poker2_t *poker) {
poker2pot_t *pot;
uint8_t i = poker->potCount++;
pot = poker->pots + i;
pot->chips = 0;
pot->playerCount = 0;
return i;
}
void pokerPotAddPlayer(poker2pot_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(poker2_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(poker2_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(poker2_t *poker) {
poker2player_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(poker2_t *poker, poker2player_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(poker2player_t *player, int32_t chips) {
player->chips += chips;
if(player->chips > 0) {
player->state = flagOff(player->state, POKER_PLAYER_STATE_OUT);
}
}
void pokerPlayerDealAll(poker2_t *poker, uint8_t count) {
uint8_t i, j;
poker2player_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(poker2_t *poker, uint8_t playerIndex) {
poker2player_t *player;
player = poker->players + playerIndex;
if(player->state & POKER_PLAYER_STATE_FOLDED) 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(poker2_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(poker2_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(poker2_t *poker, poker2player_t *player) {
return pokerGetCallValue(poker) - player->currentBet;
}
// Betting
void pokerPlayerBetPot(
poker2_t *poker, poker2pot_t *pot, uint8_t playerIndex, int32_t chips
) {
poker2player_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(poker2_t *poker, uint8_t playerIndex, int32_t chips) {
pokerPlayerBetPot(
poker, poker->pots + (poker->potCount - 1), playerIndex, chips
);
}
bool pokerPlayerCanCheck(poker2_t *poker, poker2player_t *player) {
return pokerGetCallValue(poker) <= player->currentBet;
}
poker2turn_t pokerTurnFold(poker2_t *poker, uint8_t player) {
return (poker2turn_t){
.chips = 0,
.confidence = 1,
.type = POKER_TURN_TYPE_FOLD
};
}
poker2turn_t pokerTurnBet(poker2_t *poker, uint8_t playerIndex, int32_t chips) {
poker2turn_t turn;
poker2player_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;
}
// Winning
void pokerHandGetFull(
poker2_t *poker, poker2player_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 debug_WinnerFillRemaining(poker2playerwinning_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(
poker2_t *poker, poker2player_t *player, poker2playerwinning_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
);
debug_WinnerFillRemaining(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;
debug_WinnerFillRemaining(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;
debug_WinnerFillRemaining(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;
debug_WinnerFillRemaining(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;
debug_WinnerFillRemaining(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;
debug_WinnerFillRemaining(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;
debug_WinnerFillRemaining(winning);
return;
}
// Pair
if(winning->setSize == 2) {
winning->type = POKER_WINNING_TYPE_PAIR;
debug_WinnerFillRemaining(winning);
return;
}
// High card
winning->setSize = 0;
debug_WinnerFillRemaining(winning);
winning->type = POKER_WINNING_TYPE_HIGH_CARD;
return;
}
card_t debug_pokerWinnerCompare(poker2playerwinning_t *left, poker2playerwinning_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(
poker2_t *poker,
poker2pot_t *pot,
poker2playerwinning_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;
poker2playerwinning_t *left, *right;
poker2player_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 = debug_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;
}

View File

@ -1,171 +0,0 @@
/**
* 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 "../util/array.h"
#include "../util/math.h"
#include "../poker/card.h"
#define POKER_PLAYER_COUNT_MAX 5
#define POKER_PLAYER_HAND_SIZE_MAX 2
#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_GRAVE_SIZE_MAX CARD_DECK_SIZE
#define POKER_COMMUNITY_SIZE_MAX 5
#define POKER_POT_COUNT_MAX POKER_PLAYER_COUNT_MAX
#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_WINNING_FULL_SIZE (\
POKER_PLAYER_HAND_SIZE_MAX+POKER_COMMUNITY_SIZE_MAX\
)
#define POKER_WINNING_SET_SIZE 5
#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
typedef struct {
int32_t chips;
card_t cards[POKER_PLAYER_HAND_SIZE_MAX];
uint8_t cardCount;
uint8_t state;
int32_t currentBet;
} poker2player_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;
} poker2playerwinning_t;
typedef struct {
int32_t chips;
uint8_t players[POKER_PLAYER_COUNT_MAX];
uint8_t playerCount;
} poker2pot_t;
typedef struct {
uint8_t type;
int32_t chips;
float confidence;
} poker2turn_t;
typedef struct {
card_t deck[CARD_DECK_SIZE];
uint8_t deckSize;
card_t grave[POKER_GRAVE_SIZE_MAX];
uint8_t graveSize;
card_t community[POKER_COMMUNITY_SIZE_MAX];
uint8_t communitySize;
poker2pot_t pots[POKER_POT_COUNT_MAX];
uint8_t potCount;
poker2player_t players[POKER_PLAYER_COUNT_MAX];
uint8_t playerCount;
uint8_t playerDealer;
uint8_t playerSmallBlind;
uint8_t playerBigBlind;
} poker2_t;
void pokerInit(poker2_t *poker);
void pokerResetRound(poker2_t *poker);
void pokerNewDealer(poker2_t *poker);
void pokerTakeBlinds(poker2_t *poker, int32_t small, int32_t big);
int32_t pokerGetCallValue(poker2_t *poker);
uint8_t pokerPotAdd(poker2_t *poker);
void pokerPotAddPlayer(poker2pot_t *pot, uint8_t playerIndex);
void pokerTurn(poker2_t *poker, uint8_t count);
void pokerBurn(poker2_t *poker, uint8_t count);
uint8_t pokerPlayerAdd(poker2_t *poker);
void pokerPlayerDeal(poker2_t *poker, poker2player_t *player, uint8_t count);
void pokerPlayerChipsAdd(poker2player_t *player, int32_t chips);
void pokerPlayerDealAll(poker2_t *poker, uint8_t count);
bool pokerPlayerDoesNeedToBetThisRound(poker2_t *poker, uint8_t playerIndex);
uint8_t pokerPlayerGetRemainingBetter(poker2_t *poker);
uint8_t pokerPlayerGetNextBetter(poker2_t *poker, uint8_t current);
int32_t pokerPlayerGetCallBet(poker2_t *poker, poker2player_t *player);
void pokerPlayerBetPot(
poker2_t *poker, poker2pot_t *pot, uint8_t playerIndex, int32_t chips
);
void pokerPlayerBet(poker2_t *poker, uint8_t playerIndex, int32_t chips);
bool pokerPlayerCanCheck(poker2_t *poker, poker2player_t *player);
poker2turn_t pokerTurnFold(poker2_t *poker, uint8_t player);
poker2turn_t pokerTurnBet(poker2_t *poker, uint8_t playerIndex, int32_t chips);
void pokerHandGetFull(
poker2_t *poker, poker2player_t *player, card_t cards[POKER_WINNING_FULL_SIZE]
);
void debug_WinnerFillRemaining(poker2playerwinning_t *winning);
void pokerWinnerGetForPlayer(
poker2_t *poker, poker2player_t *player, poker2playerwinning_t *winning
);
card_t debug_pokerWinnerCompare(poker2playerwinning_t *left, poker2playerwinning_t *right);
void pokerWinnerDetermineForPot(
poker2_t *poker,
poker2pot_t *pot,
poker2playerwinning_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
);