From 4d9152a6a3bb14f28578674c669497727412a5d8 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Sat, 15 Jan 2022 09:42:47 -0800 Subject: [PATCH] Working on AI --- assets/strings.js | 12 ++++++- src/conversation/queue.c | 68 +++++++++++++++++++++++++++++++++---- src/poker/poker.c | 73 +++++++++++++++++++++++----------------- src/poker/poker.h | 3 +- src/poker/turn.h | 12 ++++++- src/poker/winner.h | 58 +++++++++++++++++++++++++++++++ 6 files changed, 185 insertions(+), 41 deletions(-) create mode 100644 src/poker/winner.h diff --git a/assets/strings.js b/assets/strings.js index 19c9912..32e9621 100644 --- a/assets/strings.js +++ b/assets/strings.js @@ -11,7 +11,17 @@ const GAME_STRINGS = { 'POKER_GAME_CARDS_RIVERED': 'Cards river', 'DEBUG_WINNER_DECIDED': 'DEBUG WINNER', - 'BURNOUT': 'Burnout gey\nlmao.' + 'DEBUG_PLAYER': 'DEBUG PLAYER', + + 'POKER_GAME_AI_FOLD': 'AI Folding', + 'POKER_GAME_AI_RAISE': 'AI Raise', + 'POKER_GAME_AI_RAISE_BLUFF': 'AI Raise\nBut Bluffing', + 'POKER_GAME_AI_CALL': 'AI Calling', + 'POKER_GAME_AI_CALL_BLUFF': 'AI Calling\nBut Bluffing', + 'POKER_GAME_AI_ALL_IN': 'AI All In', + 'POKER_GAME_AI_ALL_IN_BLUFF': 'AI All In\nBut Bluffing', + 'POKER_GAME_AI_CHECK': 'AI Checking', + 'POKER_GAME_AI_CHECK_BLUFF': 'AI Checking\nBut Bluffing', }; module.exports = { GAME_STRINGS }; \ No newline at end of file diff --git a/src/conversation/queue.c b/src/conversation/queue.c index 1da1722..0c035d7 100644 --- a/src/conversation/queue.c +++ b/src/conversation/queue.c @@ -33,19 +33,70 @@ void conversationQueueDealCards() { } void conversationQueueBeginBetting() { + pokerturn_t turn; + turn.chips = 0; // Begin the betting process. First we need to decide if the player or the // AI is betting, then based on that we decide what to do next. // TODO: Actually bet. if(POKER_PLAYER_BETTER == POKER_HUMAN_INDEX) { // This is the human player. - BGB_MESSAGE("Player betting."); + BGB_MESSAGE("Player folding."); + conversationTextboxString(DEBUG_PLAYER); + POKER_PLAYERS[POKER_PLAYER_BETTER].state |= POKER_PLAYER_STATE_FOLDED; } else { - // This is an AI player. + // This is an AI player, get their turn. BGB_MESSAGE("AI turn to bet"); + pokerAi(POKER_PLAYER_BETTER, &turn); + + BGB_printf("AI Decided to %u, with %u chips and %u confidence, bluffin: %u", turn.type, turn.chips, turn.confidence, turn.bluff); + + switch(turn.type) { + case POKER_TURN_TYPE_FOLD: + POKER_PLAYERS[POKER_PLAYER_BETTER].state |= POKER_PLAYER_STATE_FOLDED; + conversationTextboxString(POKER_GAME_AI_FOLD); + break; + + case POKER_TURN_TYPE_BET: + if(turn.bluff) { + conversationTextboxString(POKER_GAME_AI_RAISE_BLUFF); + } else { + conversationTextboxString(POKER_GAME_AI_RAISE); + } + break; + + case POKER_TURN_TYPE_CALL: + if(turn.bluff) { + conversationTextboxString(POKER_GAME_AI_CALL_BLUFF); + } else { + conversationTextboxString(POKER_GAME_AI_CALL); + } + break; + + case POKER_TURN_TYPE_ALL_IN: + if(turn.bluff) { + conversationTextboxString(POKER_GAME_AI_ALL_IN_BLUFF); + } else { + conversationTextboxString(POKER_GAME_AI_ALL_IN); + } + + case POKER_TURN_TYPE_CHECK: + if(turn.bluff) { + conversationTextboxString(POKER_GAME_AI_CHECK_BLUFF); + } else { + conversationTextboxString(POKER_GAME_AI_CHECK); + } + break; + } + + // Now we have their turn, decide what to say based on that. } + + if(turn.chips > 0) { + pokerBet(POKER_PLAYER_BETTER, turn.chips); + } + QUEUE_ITEM = QUEUE_NEXT_BETTER; - conversationPause(1); } void conversationQueueNextBetter() { @@ -70,10 +121,7 @@ void conversationQueueNextBetter() { // If we reach this point then we either need to begin the betting round, or // we are going to move to the winning decider. - if( - i == POKER_PLAYER_COUNT_MAX || - POKER_COMMUNITY_SIZE_MAX == POKER_COMMUNITY_SIZE - ) { + if(POKER_COMMUNITY_SIZE_MAX == POKER_COMMUNITY_SIZE) { QUEUE_ITEM = QUEUE_WINNER_DECIDE; conversationQueueNext(); return; @@ -127,6 +175,12 @@ void conversationQueueWinnerDecide() { //////////////////////////////////////////////////////////////////////////////// +void conversationQueueAiFold() { + +} + +//////////////////////////////////////////////////////////////////////////////// + queuecallback_t *QUEUE_CALLBACKS[] = { // 0 NULL, diff --git a/src/poker/poker.c b/src/poker/poker.c index 5d61db4..075c927 100644 --- a/src/poker/poker.c +++ b/src/poker/poker.c @@ -66,12 +66,12 @@ void pokerNewRound() { POKER_DECK_SIZE = CARD_DECK_SIZE; // Shuffle Deck - for(i = CARD_DECK_SIZE-1; i > 0; i--) { - k = POKER_DECK[i]; - j = rand() % (i+1); - POKER_DECK[i] = POKER_DECK[j]; - POKER_DECK[j] = k; - } + // for(i = CARD_DECK_SIZE-1; i > 0; i--) { + // k = POKER_DECK[i]; + // j = rand() % (i+1); + // POKER_DECK[i] = POKER_DECK[j]; + // POKER_DECK[j] = k; + // } // Reset Players and decide new blinds. found = 0; @@ -146,7 +146,6 @@ void pokerAi(uint8_t player, pokerturn_t *turn) { uint8_t i, cardNumber0, cardNumber1, suitNumber0, suitNumber1; uint16_t callBet, maxBet, amount, bluffBet; uint8_t random;// TODO: Determine type. - bool isBluff; uint16_t confidence, expectedGain, potOdds; pokerplayer_t *plyr = POKER_PLAYERS + player; @@ -157,7 +156,6 @@ void pokerAi(uint8_t player, pokerturn_t *turn) { // they are expected to win from those games, but I'm just going to use the // odds of the hand being the winning hand. - // Is this preflop? if(POKER_COMMUNITY_SIZE == 0) { // Get the hand weight @@ -211,34 +209,36 @@ void pokerAi(uint8_t player, pokerturn_t *turn) { // Now work out the pot odds, this is basically "how many times the callbet // could I win if I win this hand". e.g. Desirable hands will have an // expected gain much higher than the callbet. - //TODO: not float - potOdds = callBet / (callBet + expectedGain); + potOdds = plyr->chips / 1000; + potOdds = MATH_MAX((callBet + expectedGain), 1) / MATH_MAX(potOdds, 1); } else { // If the call bet is zero then there's fairly equal odds, so let's just // take the chances out of the remainig player count. - potOdds = 1000 / pokerGetRemainingBetterCount(); + potOdds = 1000 / pokerGetRemainingBetterCount() * 2;// 0 - 1000 } // Now determine the expected ROI - // TODO: not float - expectedGain = confidence / potOdds; + //TODO: I think these values are a bit odd. + expectedGain = (confidence*100) / (potOdds / 10); // Now get a random number 0-100. random = rand() % 100; - // Determine the max bet that the AI is willing to make. This is valued as - // "3/4 chips remaining - random(0-50)" and subtract the callbet. I will - // probably chance this since the random 0-50 is.. random - // TODO: Rewrite this - maxBet = plyr->chips - (random / 2); - maxBet -= callBet; + // Determine the max bet that the AI is willing to make. The max bet is + // basically how high the AI is willing to bet. + maxBet = plyr->chips;// TODO: Replace with below code and test, just running + // With this for now. + // maxBet = plyr->chips / MATH_MAX(random / 10, 1); + // maxBet -= callBet; + // BGB_printf("Rand %u, Max Bet %u", random, callBet); // Determine what's a good bluff bet. // TODO: not float - bluffBet = random * maxBet / 100 / 2; + bluffBet = maxBet; + // bluffBet = ((random * 100) / maxBet) * plyr->chips; // Now prep the output - isBluff = false; + turn->bluff = false; amount = 0; // Now the actual AI can happen. This is basically a weight to confidence @@ -249,17 +249,17 @@ void pokerAi(uint8_t player, pokerturn_t *turn) { amount = 0; } else { amount = bluffBet; - isBluff = true; + turn->bluff = true; } } else if ((expectedGain < 1000 && confidence < 850) || confidence < 100) { if (random < 80) { amount = 0; } else if(random < 5) { amount = callBet; - isBluff = true; + turn->bluff = true; } else { amount = bluffBet; - isBluff = true; + turn->bluff = true; } } else if ((expectedGain < 1300 && confidence < 900) || confidence < 500) { if (random < 60 || confidence < 500) { @@ -274,6 +274,7 @@ void pokerAi(uint8_t player, pokerturn_t *turn) { amount = maxBet; } } else { + // TODO: check this amount = (plyr->chips - callBet) * 9 / 10; } @@ -282,21 +283,31 @@ void pokerAi(uint8_t player, pokerturn_t *turn) { if(random > 5) amount = callBet; } + // Did we actually bet? if(amount > 0) { // Let's not get caught in a raising loop with AI. - if(plyr->timesRaised >= POKER_TURN_MAX_RAISES) { - amount = callBet; - } - + if(plyr->timesRaised >= POKER_TURN_MAX_RAISES) amount = callBet; amount = MATH_MAX(amount, callBet); - // turn = pokerTurnBet(poker, playerIndex, amount); + amount = MATH_MIN(amount, plyr->chips); + turn->chips = amount; turn->confidence = confidence; + + if(amount == plyr->chips) { + turn->type == POKER_TURN_TYPE_ALL_IN; + } else if(amount == callBet) { + turn->type = POKER_TURN_TYPE_CALL; + } else { + turn->type == POKER_TURN_TYPE_BET; + } + } else if(pokerCanPlayerCheck(player)) { - // turn = pokerTurnBet(poker, playerIndex, 0); + turn->type = POKER_TURN_TYPE_CHECK; + turn->chips = 0; turn->confidence = 1000; } else { - // turn = pokerTurnFold(poker, playerIndex); + turn->type = POKER_TURN_TYPE_FOLD; + turn->chips = 0; turn->confidence = 1000 - confidence; } } diff --git a/src/poker/poker.h b/src/poker/poker.h index 9349260..8eac90c 100644 --- a/src/poker/poker.h +++ b/src/poker/poker.h @@ -12,8 +12,9 @@ #include "player.h" #include "pot.h" #include "turn.h" +#include "winner.h" -#define POKER_COMMUNITY_SIZE_MAX 5 +#define POKER_COMMUNITY_SIZE_MAX 5 #define POKER_HUMAN_INDEX 0x00 #define POKER_COUNT_FLOP 0x03 diff --git a/src/poker/turn.h b/src/poker/turn.h index 7881d42..d8c411f 100644 --- a/src/poker/turn.h +++ b/src/poker/turn.h @@ -10,11 +10,21 @@ #define POKER_TURN_MAX_RAISES 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_CHECK 0x05 + typedef struct { /** What type of action the turn is */ uint8_t type; /** How many chips they did in their turn (if applicable) */ uint16_t chips; - /** How confident the AI is about their turn. 0 = none, 1 = full */ + /** How confident the AI is about their turn. 0 = none, 1000 = full */ uint16_t confidence; + /** Is this turn a bluff? */ + bool bluff; } pokerturn_t; \ No newline at end of file diff --git a/src/poker/winner.h b/src/poker/winner.h new file mode 100644 index 0000000..9db5c63 --- /dev/null +++ b/src/poker/winner.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2022 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "../libs.h" +#include "card.h" + +/** Maximum number of cards a winning state can hold. */ +#define POKER_WINNING_FULL_SIZE 0x07 + +/** How many cards in the winning set */ +#define POKER_WINNING_SET_SIZE 0x05 + +/** 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 + +/** Confidences of winning based on the current hand type */ +#define POKER_WINNING_CONFIDENCE_ROYAL_FLUSH 1000 +#define POKER_WINNING_CONFIDENCE_STRAIGHT_FLUSH 990 +#define POKER_WINNING_CONFIDENCE_FOUR_OF_A_KIND 900 +#define POKER_WINNING_CONFIDENCE_FULL_HOUSE 850 +#define POKER_WINNING_CONFIDENCE_FLUSH 800 +#define POKER_WINNING_CONFIDENCE_STRAIGHT 700 +#define POKER_WINNING_CONFIDENCE_THREE_OF_A_KIND 500 +#define POKER_WINNING_CONFIDENCE_TWO_PAIR 400 +#define POKER_WINNING_CONFIDENCE_PAIR 200 +#define POKER_WINNING_CONFIDENCE_HIGH_CARD 100 + +/** Holds information about a player's winning state */ +typedef struct { + /** The full set of both the dealer and player's hand */ + uint8_t full[POKER_WINNING_FULL_SIZE]; + uint8_t fullSize; + + /** Holds the winning set */ + uint8_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 */ + uint8_t kicker; +} pokerplayerwinning_t; \ No newline at end of file