Brought over unfinished ai code.
This commit is contained in:
@@ -58,41 +58,7 @@ void conversationQueueNextBetter() {
|
||||
|
||||
// Next better is the better to the right of the current better.
|
||||
j = (POKER_PLAYER_BETTER + i) % POKER_PLAYER_COUNT_MAX;
|
||||
|
||||
|
||||
// Can this player even participate?
|
||||
if(
|
||||
(
|
||||
POKER_PLAYERS[j].state & (
|
||||
POKER_PLAYER_STATE_FOLDED|POKER_PLAYER_STATE_OUT
|
||||
)
|
||||
) != 0 || POKER_PLAYERS[j].chips == 0
|
||||
) continue;
|
||||
|
||||
// Has the player bet? If so are they in the current pot?
|
||||
if((
|
||||
POKER_PLAYERS[j].state &
|
||||
POKER_PLAYER_STATE_HAS_BET_THIS_ROUND
|
||||
) != 0) {
|
||||
//TODO: Refer to pokerbet function, but basically I can't let the player
|
||||
//bet if they have bet more money than the second richest player.
|
||||
|
||||
// Check each pot, if the pot is inactive or the player is CALLED/CHECKED
|
||||
for(k = 0; k < POKER_POT_COUNT_MAX; k++) {
|
||||
// Is this pot active?
|
||||
if(POKER_POTS[k].chips == 0) {
|
||||
k = POKER_POT_COUNT_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
// Is the player called into this pot all the way?
|
||||
if(POKER_POTS[k].players[j] == POKER_POTS[k].call) continue;
|
||||
break;
|
||||
}
|
||||
|
||||
// Then skip to next player.
|
||||
if(k == POKER_POT_COUNT_MAX) continue;
|
||||
}
|
||||
if(!pokerDoesPlayerNeedToBet(j)) continue;
|
||||
|
||||
// They haven't bet yet, make them the "next better"
|
||||
POKER_PLAYER_BETTER = j;
|
||||
@@ -113,11 +79,6 @@ void conversationQueueNextBetter() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset the players betting state so that they may bet next round.
|
||||
for(i = 0; i < POKER_PLAYER_COUNT_MAX; i++) {
|
||||
POKER_PLAYERS[i].state &= ~POKER_PLAYER_STATE_HAS_BET_THIS_ROUND;
|
||||
}
|
||||
|
||||
QUEUE_ITEM = QUEUE_FLOP;
|
||||
conversationQueueNext();
|
||||
}
|
||||
@@ -144,6 +105,12 @@ void conversationQueueFlopTurnRiver() {
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset each players required to bet state
|
||||
for(i = 0; i < POKER_PLAYER_COUNT_MAX; i++) {
|
||||
POKER_PLAYERS[i].state &= ~POKER_PLAYER_STATE_HAS_BET_THIS_ROUND;
|
||||
POKER_PLAYERS[i].timesRaised = 0;
|
||||
}
|
||||
|
||||
// In reality we'd burn the top card but that would waste some CPU I need.
|
||||
// Deal the top cards.
|
||||
for(i = 0; i < count; i++) {
|
||||
|
16
src/poker/card.c
Normal file
16
src/poker/card.c
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "card.h"
|
||||
|
||||
inline uint8_t cardGetNumber(uint8_t card) {
|
||||
return card % CARD_COUNT_PER_SUIT;
|
||||
}
|
||||
|
||||
inline uint8_t cardGetSuit(uint8_t card) {
|
||||
return card / CARD_SUIT_COUNT;
|
||||
}
|
@@ -104,4 +104,7 @@
|
||||
#define CARD_SUIT_COUNT 4
|
||||
|
||||
/** Standard Card Deck Size */
|
||||
#define CARD_DECK_SIZE 52
|
||||
#define CARD_DECK_SIZE 52
|
||||
|
||||
inline uint8_t cardGetNumber(uint8_t card);
|
||||
inline uint8_t cardGetSuit(uint8_t card);
|
@@ -9,7 +9,7 @@
|
||||
#include "../libs.h"
|
||||
#include "card.h"
|
||||
|
||||
#define POKER_PLAYER_COUNT_MAX 4
|
||||
#define POKER_PLAYER_COUNT_MAX 5
|
||||
#define POKER_PLAYER_HAND_SIZE_MAX 2
|
||||
|
||||
#define POKER_PLAYER_STATE_FOLDED 1 << 0
|
||||
@@ -21,9 +21,7 @@ typedef struct {
|
||||
uint16_t chips;
|
||||
uint8_t hand[POKER_PLAYER_HAND_SIZE_MAX];
|
||||
uint8_t state;
|
||||
|
||||
// int32_t currentBet;
|
||||
// uint8_t timesRaised;
|
||||
uint8_t timesRaised;
|
||||
} pokerplayer_t;
|
||||
|
||||
extern pokerplayer_t POKER_PLAYERS[];
|
@@ -82,6 +82,7 @@ void pokerNewRound() {
|
||||
POKER_PLAYER_STATE_FOLDED |
|
||||
POKER_PLAYER_STATE_HAS_BET_THIS_ROUND
|
||||
);
|
||||
POKER_PLAYERS[i].timesRaised = 0;
|
||||
|
||||
// Have we found the dealer, small blind, and big blind players?
|
||||
if(found != 3 && (POKER_PLAYERS[i].state & POKER_PLAYER_STATE_OUT) == 0){
|
||||
@@ -137,14 +138,16 @@ inline void pokerBet(uint8_t player, uint16_t amount) {
|
||||
inline uint8_t pokerGetCallBet(uint8_t player) {
|
||||
return (
|
||||
POKER_POTS[POKER_POT_CURRENT].call -
|
||||
POKER_POTS[POKER_POT_CURRENT].players[POKER_PLAYER_BETTER]
|
||||
POKER_POTS[POKER_POT_CURRENT].players[player]
|
||||
);
|
||||
}
|
||||
|
||||
void pokerAi(uint8_t player) {
|
||||
void pokerAi(uint8_t player, pokerturn_t *turn) {
|
||||
uint8_t i, cardNumber0, cardNumber1, suitNumber0, suitNumber1;
|
||||
uint16_t callBet;
|
||||
uint8_t confidence;// TODO: Determine type.
|
||||
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;
|
||||
|
||||
// The following logic is heavily inspired by;
|
||||
@@ -180,12 +183,169 @@ void pokerAi(uint8_t player) {
|
||||
} else if(i > 2) {
|
||||
confidence -= i;
|
||||
}
|
||||
|
||||
// Confidence is now a value between 0-30 (inclusive). Multiply by 1000
|
||||
confidence = (confidence * 1000) / 30;
|
||||
// Now do over 30 to get the value represented as 0-1000
|
||||
} else {
|
||||
// Simulate my hand being the winning hand, use that as the confidence
|
||||
// TODO: Repurpose old code lmao. Just take it from Dawn-C
|
||||
confidence = 0;
|
||||
}
|
||||
|
||||
// Now we know how confident the AI is, let's put a chip value to that weight
|
||||
// How many chips to call?
|
||||
callBet = pokerGetCallBet(player);
|
||||
|
||||
// Do they need chips to call, or is it possible to check?
|
||||
if(callBet > 0) {
|
||||
// Work out how many chips the player could possibly win. This is a number
|
||||
// between 0 and player count * initial chips, at the time of writing that
|
||||
// is around 50,000.
|
||||
expectedGain = 0;
|
||||
for(i = 0; i < POKER_POT_COUNT; i++) {
|
||||
if(POKER_POTS[i].players[player] == 0) break;
|
||||
expectedGain += POKER_POTS[i].chips;
|
||||
}
|
||||
|
||||
// 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);
|
||||
} 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();
|
||||
}
|
||||
|
||||
// Now determine the expected ROI
|
||||
// TODO: not float
|
||||
expectedGain = confidence / potOdds;
|
||||
|
||||
// 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 what's a good bluff bet.
|
||||
// TODO: not float
|
||||
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 < 800 && confidence < 800) {
|
||||
if(random < 95) {
|
||||
amount = 0;
|
||||
} else {
|
||||
amount = bluffBet;
|
||||
isBluff = true;
|
||||
}
|
||||
} else if ((expectedGain < 1000 && confidence < 850) || confidence < 100) {
|
||||
if (random < 80) {
|
||||
amount = 0;
|
||||
} else if(random < 5) {
|
||||
amount = callBet;
|
||||
isBluff = true;
|
||||
} else {
|
||||
amount = bluffBet;
|
||||
isBluff = true;
|
||||
}
|
||||
} else if ((expectedGain < 1300 && confidence < 900) || confidence < 500) {
|
||||
if (random < 60 || confidence < 500) {
|
||||
amount = callBet;
|
||||
} else {
|
||||
amount = maxBet;
|
||||
}
|
||||
} else if (confidence < 950 || POKER_COMMUNITY_SIZE < 0x04) {
|
||||
if(random < 20) {
|
||||
amount = callBet;
|
||||
} else {
|
||||
amount = maxBet;
|
||||
}
|
||||
} else {
|
||||
amount = (plyr->chips - callBet) * 9 / 10;
|
||||
}
|
||||
|
||||
// If this is the first round... make it a lot less likely I'll bet
|
||||
if(POKER_COMMUNITY_SIZE == 0x00 && amount > callBet) {
|
||||
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;
|
||||
}
|
||||
|
||||
amount = MATH_MAX(amount, callBet);
|
||||
// turn = pokerTurnBet(poker, playerIndex, amount);
|
||||
turn->confidence = confidence;
|
||||
} else if(pokerCanPlayerCheck(player)) {
|
||||
// turn = pokerTurnBet(poker, playerIndex, 0);
|
||||
turn->confidence = 1000;
|
||||
} else {
|
||||
// turn = pokerTurnFold(poker, playerIndex);
|
||||
turn->confidence = 1000 - confidence;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool pokerCanPlayerCheck(uint8_t player) {
|
||||
return (
|
||||
POKER_POTS[POKER_POT_CURRENT].players[player] ==
|
||||
POKER_POTS[POKER_POT_CURRENT].call
|
||||
);
|
||||
}
|
||||
|
||||
inline bool pokerDoesPlayerNeedToBet(uint8_t playerIndex) {
|
||||
uint8_t i;
|
||||
pokerplayer_t *player = POKER_PLAYERS + playerIndex;
|
||||
|
||||
// Can this player even participate?
|
||||
if(
|
||||
(player->state & (POKER_PLAYER_STATE_FOLDED|POKER_PLAYER_STATE_OUT)) != 0 ||
|
||||
player->chips == 0
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Has the player bet? If so are they in the current pot?
|
||||
if((player->state & POKER_PLAYER_STATE_HAS_BET_THIS_ROUND) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//TODO: Refer to pokerbet function, but basically I can't let the player
|
||||
//bet if they have bet more money than the second richest player.
|
||||
|
||||
// Check each pot, if the pot is inactive or the player is CALLED/CHECKED
|
||||
for(i = 0; i < POKER_POT_COUNT_MAX; i++) {
|
||||
// Is this pot active?
|
||||
if(POKER_POTS[i].chips == 0) break;
|
||||
|
||||
// Is the player called into this pot all the way?
|
||||
if(POKER_POTS[i].players[playerIndex] == POKER_POTS[i].call) continue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline uint8_t pokerGetRemainingBetterCount() {
|
||||
uint8_t i, count;
|
||||
count = 0;
|
||||
for(i = 0 ; i < POKER_PLAYER_COUNT_MAX; i++) {
|
||||
if(pokerDoesPlayerNeedToBet(i)) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
@@ -11,6 +11,7 @@
|
||||
#include "card.h"
|
||||
#include "player.h"
|
||||
#include "pot.h"
|
||||
#include "turn.h"
|
||||
|
||||
#define POKER_COMMUNITY_SIZE_MAX 5
|
||||
#define POKER_HUMAN_INDEX 0x00
|
||||
@@ -32,9 +33,10 @@ extern uint8_t POKER_PLAYER_BETTER;
|
||||
extern uint16_t POKER_GAME_BLINDS_CURRENT;
|
||||
|
||||
void pokerInit();
|
||||
|
||||
void pokerNewRound();
|
||||
|
||||
inline void pokerBet(uint8_t player, uint16_t amount);
|
||||
|
||||
inline uint8_t pokerGetCallBet(uint8_t player);
|
||||
inline uint8_t pokerGetCallBet(uint8_t player);
|
||||
inline bool pokerCanPlayerCheck(uint8_t player);
|
||||
inline bool pokerDoesPlayerNeedToBet(uint8_t playerIndex);
|
||||
inline uint8_t pokerGetRemainingBetterCount();
|
||||
void pokerAi(uint8_t player, pokerturn_t *turn);
|
20
src/poker/turn.h
Normal file
20
src/poker/turn.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
|
||||
#define POKER_TURN_MAX_RAISES 0x02
|
||||
|
||||
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 */
|
||||
uint16_t confidence;
|
||||
} pokerturn_t;
|
Reference in New Issue
Block a user