Working on restoring betting code.

This commit is contained in:
2021-10-11 08:14:03 -07:00
parent c1c5e7fb06
commit 43bef266aa
6 changed files with 248 additions and 39 deletions

View File

@ -11,7 +11,7 @@ project(Dawn VERSION 1.0)
set(GAME_NAME DawnGame) set(GAME_NAME DawnGame)
set(GAME_VERSION 1.0) set(GAME_VERSION 1.0)
set(TARGET_GROUP test) set(TARGET_GROUP production)
##################################### LIBS ##################################### ##################################### LIBS #####################################
add_subdirectory(lib) add_subdirectory(lib)

View File

@ -13,9 +13,8 @@ void _pokerGameActionBetOnStart(
bool isHuman; bool isHuman;
pokergame_t *game = (pokergame_t *)action->data; pokergame_t *game = (pokergame_t *)action->data;
//TODO: Fix this whole filee
// Reset the UI state. // Reset the UI state.
// isHuman = game->poker.bet.better == POKER_PLAYER_HUMAN_INDEX; isHuman = game->poker.better == POKER_WORLD_HUMAN_INDEX;
// if(isHuman) pokerUiBetShow(&game->ui); // if(isHuman) pokerUiBetShow(&game->ui);
} }
@ -23,37 +22,37 @@ void _pokerGameActionBetOnUpdate(
queue_t *queue, queueaction_t *action, uint8_t i queue_t *queue, queueaction_t *action, uint8_t i
) { ) {
// Restack // Restack
// bool isHuman; bool isHuman;
// bool turnMade = false; bool turnMade = false;
// pokerturn_t turn; pokerturn_t turn;
// pokergame_t *game = (pokergame_t *)action->data; pokergame_t *game = (pokergame_t *)action->data;
// pokerplayer_t *player; pokerplayer_t *player;
// pokerdiscussiondata_t discussion; pokerdiscussiondata_t discussion;
// // Are they human? // Are they human?
// player = game->poker.players + game->poker.bet.better; player = game->poker.players + game->poker.better;
// isHuman = game->poker.bet.better == POKER_PLAYER_HUMAN_INDEX; isHuman = game->poker.better == POKER_WORLD_HUMAN_INDEX;
// // Handle as an AI // Handle as an AI
// if(isHuman) { if(isHuman) {
// turn = game->ui.betTurn; // turn = game->ui.betTurn;
// turnMade = game->ui.betTurnMade; // turnMade = game->ui.betTurnMade;
// } else { } else {
// turn = pokerTurnGet(&game->poker, game->poker.bet.better); turn = pokerTurnGetForPlayer(&game->poker, game->poker.better);
// turnMade = true; turnMade = true;
// } }
// // Now decide if we should do something. // Now decide if we should do something.
// if(!turnMade) return; if(!turnMade) return;
// // Perform the action // Perform the action
// pokerTurnAction(&game->poker, player, &turn); // pokerTurnAction(&game->poker, player, &turn);
// // Speak // Speak
// discussion.reason = pokerDiscussionGetTypeFromTurnType(turn.type); // discussion.reason = pokerDiscussionGetTypeFromTurnType(turn.type);
// discussion.poker = game; discussion.poker = game;
// discussion.playerCause = game->poker.bet.better; discussion.playerCause = game->poker.better;
// pokerDiscussionQueue(&discussion); pokerDiscussionQueue(&discussion);
// Next. // Next.
queueNext(queue); queueNext(queue);

View File

@ -37,16 +37,15 @@ void _pokerGameActionFlopOnStart(
// Now, get the count of players left to bet. If "everyone is all in" then // Now, get the count of players left to bet. If "everyone is all in" then
// this will be 0 and no actual betting needs to happen. // this will be 0 and no actual betting needs to happen.
// if(pokerBetGetRemainingPlayerCount( if(nextBetter != 0xFF) {
// &game->poker.bet, game->poker.players // Begin betting.
// ) > 1) { game->poker.better = nextBetter;
// // Begin betting. pokerGameActionLookAdd(game, nextBetter);
// pokerGameActionLookAdd(game, game->poker.bet.better); pokerGameActionBetAdd(game);
// pokerGameActionBetAdd(game); } else {
// } else { //No actual players to bet, so add the following flop instead.
// //No actual players to bet, so add the following flop instead. pokerGameActionFlopAdd(game);
// pokerGameActionFlopAdd(game); }
// }
// Do next action. // Do next action.
queueNext(queue); queueNext(queue);

View File

@ -188,6 +188,7 @@ bool pokerPlayerDoesNeedToBetThisRound(poker_t *poker, uint8_t playerIndex) {
pokerplayer_t *player; pokerplayer_t *player;
player = poker->players + playerIndex; player = poker->players + playerIndex;
if(player->state & POKER_PLAYER_STATE_FOLDED) return false; if(player->state & POKER_PLAYER_STATE_FOLDED) return false;
if(player->chips <= 0) return false;
if(!(player->state & POKER_PLAYER_STATE_HAS_BET_THIS_ROUND)) return true; if(!(player->state & POKER_PLAYER_STATE_HAS_BET_THIS_ROUND)) return true;
if(player->currentBet < pokerGetCallValue(poker)) return true; if(player->currentBet < pokerGetCallValue(poker)) return true;
return false; return false;
@ -233,6 +234,16 @@ uint8_t pokerInRoundGetCount(poker_t *poker) {
return count; return count;
} }
uint8_t pokerPlayerGetRemainingBetterCount(poker_t *poker) {
uint8_t i, count;
count = 0;
for(i = 0; i < poker->playerCount; i++) {
if(!pokerPlayerDoesNeedToBetThisRound(poker, i)) continue;
count++;
}
return count;
}
// Betting // Betting
void pokerPlayerBetPot( void pokerPlayerBetPot(
poker_t *poker, pokerpot_t *pot, uint8_t playerIndex, int32_t chips poker_t *poker, pokerpot_t *pot, uint8_t playerIndex, int32_t chips
@ -290,6 +301,160 @@ pokerturn_t pokerTurnBet(poker_t *poker, uint8_t playerIndex, int32_t chips) {
return turn; return turn;
} }
pokerturn_t pokerTurnGetForPlayer(poker_t *poker, uint8_t playerIndex) {
int32_t random, maxBet, bluffBet, callBet;
float confidence, expectedGain, potOdds;
bool isBluff;
int32_t amount;
pokerplayer_t *player;
pokerplayerwinning_t winning;
uint8_t i, cardNumber0, cardNumber1, suitNumber0, suitNumber1;
pokerturn_t turn;
player = poker->players + playerIndex;
// Can the player do anything?
if(player->state & (POKER_PLAYER_STATE_FOLDED | POKER_PLAYER_STATE_OUT)) {
turn.type = POKER_TURN_TYPE_OUT;
return turn;
}
// The following logic is heavily inspired by;
// https://github.com/gorel/C-Poker-AI/blob/master/src/common/pokerai.c
// But with some changes and smarts added by me. The original source code will
// essentially just run a crap tun of simulated games and get the times that
// they are expected to win from those games, but I'm just going to use the
// odds of the winning hand.
// Is this preflop?
if(poker->communitySize == 0 && player->cardCount >= 2) {
// Get the hand weight
cardNumber0 = cardGetNumber(player->cards[0]);
cardNumber1 = cardGetNumber(player->cards[1]);
suitNumber0 = cardGetSuit(player->cards[0]);
suitNumber1 = cardGetSuit(player->cards[1]);
// Get delta between cards
i = mathAbs(cardNumber0 - cardNumber1);
// Get card weight
confidence = (float)cardNumber0 + (float)cardNumber1;
if(cardNumber0 == cardNumber1) {// Pairs
confidence += 6;
} else if(suitNumber0 == suitNumber1) {// Same suit
confidence += 4;
}
// Get difference from cards for guessing flush
if(i > 4) {
confidence -= 4;
} else if(i > 2) {
confidence -= i;
}
// Get the confidence delta 0-1
confidence = confidence / 30.0f;
} else {
// Simulate my hand being the winning hand, use that as the confidence
// pokerWinnerPlayerGet(&poker->community, player, &winning);
// confidence = pokerWinnerGetTypeConfidence(winning.type);
}
// Now we know how confident the AI is, let's put a chip value to that weight
// How many chips to call?
callBet = pokerPlayerGetCallBet(poker, player);
// Do they need chips to call, or is it possible to check?
// if(callBet > 0) {
// potOdds = (float)callBet / ((float)callBet + (float)poker->bet.pot);
// } else {
// potOdds = (
// 1.0f / (float)pokerBetGetRemainingPlayerCount(&poker->bet, poker->players)
// );
// }
// Now determine the expected ROI
expectedGain = confidence / potOdds;
// Now get a random 0-100
random = randInt32() % 100;
// Determine the max bet that the AI is willing to make
maxBet = (int32_t)((float)player->chips / 1.75f) - (random / 2);
maxBet -= callBet;
// Determine what's a good bluff bet.
bluffBet = random * maxBet / 100 / 2;
// Now prep the output
isBluff = false;
amount = 0;
// Now the actual AI can happen. This is basically a weight to confidence
// ratio. The higher the gains and the confidence then the more likely the AI
// is to betting. There are also bluff chances within here.
if(expectedGain < 0.8 && confidence < 0.8) {
if(random < 95) {
amount = 0;
} else {
amount = bluffBet;
isBluff = true;
}
} else if ((expectedGain < 1.0 && confidence < 0.85) || confidence < 0.1) {
if (random < 80) {
amount = 0;
} else if(random < 5) {
amount = callBet;
isBluff = true;
} else {
amount = bluffBet;
isBluff = true;
}
} else if ((expectedGain < 1.3 && confidence < 0.9) || confidence < 0.5) {
if (random < 60 || confidence < 0.5) {
amount = callBet;
} else {
amount = maxBet;
}
} else if (confidence < 0.95 || poker->communitySize < 0x04) {
if(random < 20) {
amount = callBet;
} else {
amount = maxBet;
}
} else {
amount = (player->chips - callBet) * 9 / 10;
}
// If this is the first round... make it a lot less likely I'll bet
if(poker->communitySize == 0x00 && amount > callBet) {
if(random > 5) amount = callBet;
}
// Did we actually bet?
// if(amount > 0) {
// printf("AI is betting %i chips, bluff: %i\n", amount, isBluff);
// // Let's not get caught in a raising loop with AI.
// if(player->timesRaised >= POKER_TURN_MAX_RAISES) {
// amount = callBet;
// }
// amount = mathMax(amount, callBet);
// turn = pokerTurnRaise(poker, playerIndex, amount);
// turn.confidence = confidence;
// } else if(pokerTurnCanPlayerCheck(poker, playerIndex)) {
// turn = pokerTurnCheck(poker, playerIndex);
// turn.confidence = 1;
// } else {
// turn = pokerTurnFold(poker, playerIndex);
// turn.confidence = 1 - confidence;
// }
return turn;
}
// Winning // Winning
void pokerHandGetFull( void pokerHandGetFull(
poker_t *poker, pokerplayer_t *player, card_t cards[POKER_WINNING_FULL_SIZE] poker_t *poker, pokerplayer_t *player, card_t cards[POKER_WINNING_FULL_SIZE]

View File

@ -340,6 +340,14 @@ int32_t pokerPlayerGetCallBet(poker_t *poker, pokerplayer_t *player);
*/ */
uint8_t pokerInRoundGetCount(poker_t *poker); uint8_t pokerInRoundGetCount(poker_t *poker);
/**
* Returns the count of players remaining to bet.
*
* @param poker Poker game instance.
* @return Count of players left to bet.
*/
uint8_t pokerPlayerGetRemainingBetterCount(poker_t *poker);
/** /**
* Let a player bet chips into the pot. * Let a player bet chips into the pot.
* *
@ -391,6 +399,15 @@ pokerturn_t pokerTurnFold(poker_t *poker, uint8_t player);
*/ */
pokerturn_t pokerTurnBet(poker_t *poker, uint8_t playerIndex, int32_t chips); pokerturn_t pokerTurnBet(poker_t *poker, uint8_t playerIndex, int32_t chips);
/**
* Returns the AI result for a turn done by a non human player.
*
* @param poker Poker game instance to use.
* @param playerIndex Player index to get the turn for.
* @return Some information about the move the player is trying to perform.
*/
pokerturn_t pokerTurnGetForPlayer(poker_t *poker, uint8_t playerIndex);
/** /**
* Returns the full hand for a given player including the best cards on the * Returns the full hand for a given player including the best cards on the
* bench. * bench.

View File

@ -700,7 +700,7 @@ void test_pokerPlayerGetCallBet_should_GetCallBet(void) {
TEST_ASSERT_EQUAL_INT32(0, pokerPlayerGetCallBet(&poker,poker.players+p2)); TEST_ASSERT_EQUAL_INT32(0, pokerPlayerGetCallBet(&poker,poker.players+p2));
} }
void test_pokerInRoundGetCount(void) { void test_pokerInRoundGetCount_should_ReturnCountOfPlayersInRound(void) {
poker_t poker; poker_t poker;
uint8_t p0, p1, p2; uint8_t p0, p1, p2;
@ -726,6 +726,32 @@ void test_pokerInRoundGetCount(void) {
TEST_ASSERT_EQUAL_UINT8(0x00, pokerInRoundGetCount(&poker)); TEST_ASSERT_EQUAL_UINT8(0x00, pokerInRoundGetCount(&poker));
} }
void test_pokerPlayerGetRemainintBetterCount_should_ReturnCountNeedsToBet(void){
poker_t poker;
uint8_t p0, p1, p2;
pokerInit(&poker);
p0 = pokerPlayerAdd(&poker);
p1 = pokerPlayerAdd(&poker);
p2 = pokerPlayerAdd(&poker);
TEST_ASSERT_EQUAL_UINT8(0x00, pokerPlayerGetRemainingBetterCount(&poker));
pokerPlayerChipsAdd(poker.players + p0, 1000);
TEST_ASSERT_EQUAL_UINT8(0x01, pokerPlayerGetRemainingBetterCount(&poker));
pokerPlayerChipsAdd(poker.players + p2, 1000);
TEST_ASSERT_EQUAL_UINT8(0x02, pokerPlayerGetRemainingBetterCount(&poker));
pokerPlayerChipsAdd(poker.players + p1, 1000);
TEST_ASSERT_EQUAL_UINT8(0x03, pokerPlayerGetRemainingBetterCount(&poker));
poker.players[0].state |= POKER_PLAYER_STATE_FOLDED;
TEST_ASSERT_EQUAL_UINT8(0x02, pokerPlayerGetRemainingBetterCount(&poker));
poker.players[1].state |= POKER_PLAYER_STATE_HAS_BET_THIS_ROUND;
TEST_ASSERT_EQUAL_UINT8(0x01, pokerPlayerGetRemainingBetterCount(&poker));
poker.players[2].chips = 0;
TEST_ASSERT_EQUAL_UINT8(0x00, pokerPlayerGetRemainingBetterCount(&poker));
}
void test_pokerPlayerBetPot_should_AddChipsToThePot(void) { void test_pokerPlayerBetPot_should_AddChipsToThePot(void) {
poker_t poker; poker_t poker;
pokerpot_t *pot; pokerpot_t *pot;
@ -1497,7 +1523,10 @@ int test_poker() {
RUN_TEST(test_pokerPlayerGetRemainingBetter_should_ReturnRemainingBetters); RUN_TEST(test_pokerPlayerGetRemainingBetter_should_ReturnRemainingBetters);
RUN_TEST(test_pokerPlayerGetNextBetter_should_GetTheNextBetter); RUN_TEST(test_pokerPlayerGetNextBetter_should_GetTheNextBetter);
RUN_TEST(test_pokerPlayerGetCallBet_should_GetCallBet); RUN_TEST(test_pokerPlayerGetCallBet_should_GetCallBet);
RUN_TEST(test_pokerInRoundGetCount); RUN_TEST(test_pokerInRoundGetCount_should_ReturnCountOfPlayersInRound);
RUN_TEST(
test_pokerPlayerGetRemainintBetterCount_should_ReturnCountNeedsToBet
);
RUN_TEST(test_pokerPlayerBetPot_should_AddChipsToThePot); RUN_TEST(test_pokerPlayerBetPot_should_AddChipsToThePot);
RUN_TEST(test_pokerPlayerBetPot_should_UpdatePlayerState); RUN_TEST(test_pokerPlayerBetPot_should_UpdatePlayerState);
RUN_TEST(test_pokerPlayerBet_should_BetToTheActivePot); RUN_TEST(test_pokerPlayerBet_should_BetToTheActivePot);