Working on AI

This commit is contained in:
2022-01-15 09:42:47 -08:00
parent 31a6271f27
commit 4d9152a6a3
6 changed files with 185 additions and 41 deletions

View File

@@ -11,7 +11,17 @@ const GAME_STRINGS = {
'POKER_GAME_CARDS_RIVERED': 'Cards river', 'POKER_GAME_CARDS_RIVERED': 'Cards river',
'DEBUG_WINNER_DECIDED': 'DEBUG WINNER', '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 }; module.exports = { GAME_STRINGS };

View File

@@ -33,19 +33,70 @@ void conversationQueueDealCards() {
} }
void conversationQueueBeginBetting() { void conversationQueueBeginBetting() {
pokerturn_t turn;
turn.chips = 0;
// Begin the betting process. First we need to decide if the player or the // 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. // AI is betting, then based on that we decide what to do next.
// TODO: Actually bet. // TODO: Actually bet.
if(POKER_PLAYER_BETTER == POKER_HUMAN_INDEX) { if(POKER_PLAYER_BETTER == POKER_HUMAN_INDEX) {
// This is the human player. // 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 { } else {
// This is an AI player. // This is an AI player, get their turn.
BGB_MESSAGE("AI turn to bet"); 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; QUEUE_ITEM = QUEUE_NEXT_BETTER;
conversationPause(1);
} }
void conversationQueueNextBetter() { void conversationQueueNextBetter() {
@@ -70,10 +121,7 @@ void conversationQueueNextBetter() {
// If we reach this point then we either need to begin the betting round, or // If we reach this point then we either need to begin the betting round, or
// we are going to move to the winning decider. // we are going to move to the winning decider.
if( if(POKER_COMMUNITY_SIZE_MAX == POKER_COMMUNITY_SIZE) {
i == POKER_PLAYER_COUNT_MAX ||
POKER_COMMUNITY_SIZE_MAX == POKER_COMMUNITY_SIZE
) {
QUEUE_ITEM = QUEUE_WINNER_DECIDE; QUEUE_ITEM = QUEUE_WINNER_DECIDE;
conversationQueueNext(); conversationQueueNext();
return; return;
@@ -127,6 +175,12 @@ void conversationQueueWinnerDecide() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void conversationQueueAiFold() {
}
////////////////////////////////////////////////////////////////////////////////
queuecallback_t *QUEUE_CALLBACKS[] = { queuecallback_t *QUEUE_CALLBACKS[] = {
// 0 // 0
NULL, NULL,

View File

@@ -66,12 +66,12 @@ void pokerNewRound() {
POKER_DECK_SIZE = CARD_DECK_SIZE; POKER_DECK_SIZE = CARD_DECK_SIZE;
// Shuffle Deck // Shuffle Deck
for(i = CARD_DECK_SIZE-1; i > 0; i--) { // for(i = CARD_DECK_SIZE-1; i > 0; i--) {
k = POKER_DECK[i]; // k = POKER_DECK[i];
j = rand() % (i+1); // j = rand() % (i+1);
POKER_DECK[i] = POKER_DECK[j]; // POKER_DECK[i] = POKER_DECK[j];
POKER_DECK[j] = k; // POKER_DECK[j] = k;
} // }
// Reset Players and decide new blinds. // Reset Players and decide new blinds.
found = 0; found = 0;
@@ -146,7 +146,6 @@ void pokerAi(uint8_t player, pokerturn_t *turn) {
uint8_t i, cardNumber0, cardNumber1, suitNumber0, suitNumber1; uint8_t i, cardNumber0, cardNumber1, suitNumber0, suitNumber1;
uint16_t callBet, maxBet, amount, bluffBet; uint16_t callBet, maxBet, amount, bluffBet;
uint8_t random;// TODO: Determine type. uint8_t random;// TODO: Determine type.
bool isBluff;
uint16_t confidence, expectedGain, potOdds; uint16_t confidence, expectedGain, potOdds;
pokerplayer_t *plyr = POKER_PLAYERS + player; 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 // they are expected to win from those games, but I'm just going to use the
// odds of the hand being the winning hand. // odds of the hand being the winning hand.
// Is this preflop? // Is this preflop?
if(POKER_COMMUNITY_SIZE == 0) { if(POKER_COMMUNITY_SIZE == 0) {
// Get the hand weight // 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 // 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 // could I win if I win this hand". e.g. Desirable hands will have an
// expected gain much higher than the callbet. // expected gain much higher than the callbet.
//TODO: not float potOdds = plyr->chips / 1000;
potOdds = callBet / (callBet + expectedGain); potOdds = MATH_MAX((callBet + expectedGain), 1) / MATH_MAX(potOdds, 1);
} else { } else {
// If the call bet is zero then there's fairly equal odds, so let's just // 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. // take the chances out of the remainig player count.
potOdds = 1000 / pokerGetRemainingBetterCount(); potOdds = 1000 / pokerGetRemainingBetterCount() * 2;// 0 - 1000
} }
// Now determine the expected ROI // Now determine the expected ROI
// TODO: not float //TODO: I think these values are a bit odd.
expectedGain = confidence / potOdds; expectedGain = (confidence*100) / (potOdds / 10);
// Now get a random number 0-100. // Now get a random number 0-100.
random = rand() % 100; random = rand() % 100;
// Determine the max bet that the AI is willing to make. This is valued as // Determine the max bet that the AI is willing to make. The max bet is
// "3/4 chips remaining - random(0-50)" and subtract the callbet. I will // basically how high the AI is willing to bet.
// probably chance this since the random 0-50 is.. random maxBet = plyr->chips;// TODO: Replace with below code and test, just running
// TODO: Rewrite this // With this for now.
maxBet = plyr->chips - (random / 2); // maxBet = plyr->chips / MATH_MAX(random / 10, 1);
maxBet -= callBet; // maxBet -= callBet;
// BGB_printf("Rand %u, Max Bet %u", random, callBet);
// Determine what's a good bluff bet. // Determine what's a good bluff bet.
// TODO: not float // TODO: not float
bluffBet = random * maxBet / 100 / 2; bluffBet = maxBet;
// bluffBet = ((random * 100) / maxBet) * plyr->chips;
// Now prep the output // Now prep the output
isBluff = false; turn->bluff = false;
amount = 0; amount = 0;
// Now the actual AI can happen. This is basically a weight to confidence // 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; amount = 0;
} else { } else {
amount = bluffBet; amount = bluffBet;
isBluff = true; turn->bluff = true;
} }
} else if ((expectedGain < 1000 && confidence < 850) || confidence < 100) { } else if ((expectedGain < 1000 && confidence < 850) || confidence < 100) {
if (random < 80) { if (random < 80) {
amount = 0; amount = 0;
} else if(random < 5) { } else if(random < 5) {
amount = callBet; amount = callBet;
isBluff = true; turn->bluff = true;
} else { } else {
amount = bluffBet; amount = bluffBet;
isBluff = true; turn->bluff = true;
} }
} else if ((expectedGain < 1300 && confidence < 900) || confidence < 500) { } else if ((expectedGain < 1300 && confidence < 900) || confidence < 500) {
if (random < 60 || confidence < 500) { if (random < 60 || confidence < 500) {
@@ -274,6 +274,7 @@ void pokerAi(uint8_t player, pokerturn_t *turn) {
amount = maxBet; amount = maxBet;
} }
} else { } else {
// TODO: check this
amount = (plyr->chips - callBet) * 9 / 10; amount = (plyr->chips - callBet) * 9 / 10;
} }
@@ -282,21 +283,31 @@ void pokerAi(uint8_t player, pokerturn_t *turn) {
if(random > 5) amount = callBet; if(random > 5) amount = callBet;
} }
// Did we actually bet? // Did we actually bet?
if(amount > 0) { if(amount > 0) {
// Let's not get caught in a raising loop with AI. // Let's not get caught in a raising loop with AI.
if(plyr->timesRaised >= POKER_TURN_MAX_RAISES) { if(plyr->timesRaised >= POKER_TURN_MAX_RAISES) amount = callBet;
amount = callBet; amount = MATH_MAX(amount, callBet);
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;
} }
amount = MATH_MAX(amount, callBet);
// turn = pokerTurnBet(poker, playerIndex, amount);
turn->confidence = confidence;
} else if(pokerCanPlayerCheck(player)) { } else if(pokerCanPlayerCheck(player)) {
// turn = pokerTurnBet(poker, playerIndex, 0); turn->type = POKER_TURN_TYPE_CHECK;
turn->chips = 0;
turn->confidence = 1000; turn->confidence = 1000;
} else { } else {
// turn = pokerTurnFold(poker, playerIndex); turn->type = POKER_TURN_TYPE_FOLD;
turn->chips = 0;
turn->confidence = 1000 - confidence; turn->confidence = 1000 - confidence;
} }
} }

View File

@@ -12,6 +12,7 @@
#include "player.h" #include "player.h"
#include "pot.h" #include "pot.h"
#include "turn.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_HUMAN_INDEX 0x00

View File

@@ -10,11 +10,21 @@
#define POKER_TURN_MAX_RAISES 0x02 #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 { typedef struct {
/** What type of action the turn is */ /** What type of action the turn is */
uint8_t type; uint8_t type;
/** How many chips they did in their turn (if applicable) */ /** How many chips they did in their turn (if applicable) */
uint16_t chips; 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; uint16_t confidence;
/** Is this turn a bluff? */
bool bluff;
} pokerturn_t; } pokerturn_t;

58
src/poker/winner.h Normal file
View File

@@ -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;