Working on AI
This commit is contained in:
		@@ -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 };
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
							
								
								
									
										58
									
								
								src/poker/winner.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/poker/winner.h
									
									
									
									
									
										Normal 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;
 | 
			
		||||
		Reference in New Issue
	
	Block a user