Progress on poker logic
This commit is contained in:
@ -1,47 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Static Libs
|
||||
extern "C" {
|
||||
// Standard Libs
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef bool bool_t;
|
||||
typedef float float_t;
|
||||
}
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <stb_truetype.h>
|
||||
#include <memory>
|
||||
// #include <iterator>
|
||||
// #include <algorithm>
|
||||
// #include <string>
|
||||
// #include <sstream>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/ext/scalar_constants.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
/**
|
||||
* Copyright (c) 2022 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Static Libs
|
||||
extern "C" {
|
||||
// Standard Libs
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef bool bool_t;
|
||||
typedef float float_t;
|
||||
}
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <stb_truetype.h>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
// #include <iterator>
|
||||
// #include <algorithm>
|
||||
// #include <string>
|
||||
// #include <sstream>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/ext/scalar_constants.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/gtx/matrix_decompose.hpp>
|
77
src/dawn/display/animation/Easing.hpp
Normal file
77
src/dawn/display/animation/Easing.hpp
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
typedef float_t easefunction_t(float_t t);
|
||||
|
||||
/**
|
||||
* Returns the ease time for a given real time duration span.
|
||||
* @param start At what point in time the animation started
|
||||
* @param current The current point in time the animation is at.
|
||||
* @param duration The total duration on the animation.
|
||||
* @returns The easing time (0-1 time) that the animation is at.
|
||||
*/
|
||||
static inline float_t easeTimeToEase(
|
||||
float_t start,
|
||||
float_t current,
|
||||
float_t duration
|
||||
) {
|
||||
return (current - start) / duration;
|
||||
}
|
||||
|
||||
static inline float_t easeLinear(float_t t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
static inline float_t easeInQuad(float_t t) {
|
||||
return t * t;
|
||||
}
|
||||
|
||||
static inline float_t easeOutQuad(float_t t) {
|
||||
return t * (2 - t);
|
||||
}
|
||||
|
||||
static inline float_t easeOutCubic(float_t t) {
|
||||
return 1 - powf(1 - t, 3);
|
||||
}
|
||||
|
||||
static inline float_t easeInOutQuad(float_t t) {
|
||||
return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
||||
}
|
||||
|
||||
static inline float_t easeInCubic(float_t t) {
|
||||
return t * t * t;
|
||||
}
|
||||
|
||||
static inline float_t easeInOutCubic(float_t t) {
|
||||
return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
|
||||
}
|
||||
|
||||
static inline float_t easeInQuart(float_t t) {
|
||||
return t * t * t * t;
|
||||
}
|
||||
|
||||
static inline float_t easeOutQuart(float_t t) {
|
||||
return 1 - (t-1)*(t-1)*(t-1)*(t-1);
|
||||
}
|
||||
|
||||
static inline float_t easeInOutQuart(float_t t) {
|
||||
return t < .5 ? 8*t*t*t*t : 1-8*(t-1)*(t-1)*(t-1)*(t-1);
|
||||
}
|
||||
|
||||
static inline float_t easeInQuint(float_t t) {
|
||||
return t*t*t*t*t;
|
||||
}
|
||||
|
||||
static inline float_t easeOutQuint(float_t t) {
|
||||
return 1 + (t-1)*(t-1)*(t-1)*(t-1)*(t-1);
|
||||
}
|
||||
|
||||
static inline float_t easeInOutQuint(float_t t) {
|
||||
return t<.5 ? 16*t*t*t*t*t : 1+16*(t-1)*(t-1)*(t-1)*(t-1)*(t-1);
|
||||
}
|
@ -37,7 +37,7 @@ float_t TrueTypeFont::getScale(float_t scale) {
|
||||
|
||||
float_t TrueTypeFont::getSpaceSize(float_t fontSize) {
|
||||
assertTrue(fontSize > 0);
|
||||
return mathRoundFloat(this->fontSize * 0.3f);
|
||||
return mathRound<float_t>(this->fontSize * 0.3f);
|
||||
}
|
||||
|
||||
float_t TrueTypeFont::getInitialLineHeight(float_t fontSize) {
|
||||
|
@ -6,5 +6,12 @@
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
Card.cpp
|
||||
PokerPlayer.cpp
|
||||
PokerGame.cpp
|
||||
)
|
||||
PokerWinning.cpp
|
||||
PokerTurn.cpp
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(visualnovel)
|
22
src/dawn/poker/Card.cpp
Normal file
22
src/dawn/poker/Card.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "Card.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
void Card::fillDeck(std::vector<struct Card> *deck) {
|
||||
for(uint8_t i = 0; i < CARD_DECK_SIZE; i++) {
|
||||
deck->push_back(Card(i));
|
||||
}
|
||||
}
|
||||
|
||||
void Card::sort(std::vector<struct Card> *deck) {
|
||||
std::sort(deck->begin(), deck->end(), &cardSorter);
|
||||
}
|
||||
|
||||
bool_t cardSorter(struct Card left, struct Card right) {
|
||||
return left.cardValue < right.cardValue;
|
||||
}
|
@ -6,54 +6,71 @@
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
enum CardSuit {
|
||||
CLUBS = 0,
|
||||
DIAMONDS = 1,
|
||||
HEARTS = 2,
|
||||
SPADES = 3
|
||||
};
|
||||
namespace Dawn {
|
||||
enum CardSuit {
|
||||
CARD_CLUBS = 0,
|
||||
CARD_DIAMONDS = 1,
|
||||
CARD_HEARTS = 2,
|
||||
CARD_SPADES = 3
|
||||
};
|
||||
|
||||
enum CardValue {
|
||||
TWO = 0,
|
||||
THREE = 1,
|
||||
FOUR = 2,
|
||||
FIVE = 3,
|
||||
SIX = 4,
|
||||
SEVEN = 5,
|
||||
EIGHT = 6,
|
||||
NINE = 7,
|
||||
TEN = 8,
|
||||
JACK = 9,
|
||||
QUEEN = 10,
|
||||
KING = 11,
|
||||
ACE = 12
|
||||
};
|
||||
enum CardValue {
|
||||
CARD_TWO = 0,
|
||||
CARD_THREE = 1,
|
||||
CARD_FOUR = 2,
|
||||
CARD_FIVE = 3,
|
||||
CARD_SIX = 4,
|
||||
CARD_SEVEN = 5,
|
||||
CARD_EIGHT = 6,
|
||||
CARD_NINE = 7,
|
||||
CARD_TEN = 8,
|
||||
CARD_JACK = 9,
|
||||
CARD_QUEEN = 10,
|
||||
CARD_KING = 11,
|
||||
CARD_ACE = 12
|
||||
};
|
||||
|
||||
/** Count of cards in each suit */
|
||||
#define CARD_COUNT_PER_SUIT 13
|
||||
/** Count of cards in each suit */
|
||||
#define CARD_COUNT_PER_SUIT 13
|
||||
|
||||
/** Count of suits */
|
||||
#define CARD_SUIT_COUNT 4
|
||||
/** Count of suits */
|
||||
#define CARD_SUIT_COUNT 4
|
||||
|
||||
/** Standard Card Deck Size */
|
||||
#define CARD_DECK_SIZE CARD_COUNT_PER_SUIT*CARD_SUIT_COUNT
|
||||
/** Standard Card Deck Size */
|
||||
#define CARD_DECK_SIZE CARD_COUNT_PER_SUIT*CARD_SUIT_COUNT
|
||||
|
||||
struct Card {
|
||||
uint8_t cardValue;
|
||||
struct Card {
|
||||
public:
|
||||
uint8_t cardValue;
|
||||
|
||||
Card(CardSuit suit, CardValue num) :
|
||||
cardValue((suit * CARD_COUNT_PER_SUIT) + num)
|
||||
{
|
||||
}
|
||||
static void fillDeck(std::vector<struct Card> *deck);
|
||||
static void shuffle(std::vector<struct Card> *deck);
|
||||
|
||||
Card(uint8_t cv) : cardValue(cv) {
|
||||
}
|
||||
/**
|
||||
* Sort a hand of cards. Cards are ordered in descending weight, aces are
|
||||
* high. Cards will be grouped by their suits, e.g. CARD_CLUBS_TWO will
|
||||
* appear before CARD_DIAMONDS_KING.
|
||||
*
|
||||
* @param deck Hand of cards to sort.
|
||||
*/
|
||||
static void sort(std::vector<struct Card> *deck);
|
||||
|
||||
CardValue getValue() {
|
||||
return (CardValue)(cardValue % CARD_COUNT_PER_SUIT);
|
||||
}
|
||||
Card(CardSuit suit, CardValue num) :
|
||||
cardValue((suit * CARD_COUNT_PER_SUIT) + num)
|
||||
{
|
||||
}
|
||||
|
||||
CardSuit getSuit() {
|
||||
return (CardSuit)(cardValue / CARD_COUNT_PER_SUIT);
|
||||
}
|
||||
};
|
||||
Card(uint8_t cv) : cardValue(cv) {
|
||||
}
|
||||
|
||||
CardValue getValue() {
|
||||
return (CardValue)(cardValue % CARD_COUNT_PER_SUIT);
|
||||
}
|
||||
|
||||
CardSuit getSuit() {
|
||||
return (CardSuit)(cardValue / CARD_COUNT_PER_SUIT);
|
||||
}
|
||||
};
|
||||
|
||||
bool_t cardSorter(struct Card left, struct Card right);
|
||||
}
|
@ -7,6 +7,191 @@
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
PokerGame::PokerGame() {
|
||||
PokerGame::PokerGame(SceneItem *item) : SceneItemComponent(item) {
|
||||
|
||||
}
|
||||
|
||||
void PokerGame::onStart() {
|
||||
SceneItemComponent::onStart();
|
||||
|
||||
this->players = this->getScene()->findComponents<PokerPlayer>();
|
||||
assertTrue(this->players.size() > 0);
|
||||
this->newGame();
|
||||
}
|
||||
|
||||
void PokerGame::newGame() {
|
||||
this->newRound();
|
||||
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
auto player = *it;
|
||||
player->chips = POKER_PLAYER_CHIPS_DEFAULT;
|
||||
player->isOut = false;
|
||||
++it;
|
||||
}
|
||||
|
||||
this->setDealer(0x00);
|
||||
}
|
||||
|
||||
void PokerGame::newRound() {
|
||||
this->deck.clear();
|
||||
Card::fillDeck(&this->deck);
|
||||
|
||||
this->smallBlind = POKER_BLIND_SMALL_DEFAULT;
|
||||
this->bigBlind = POKER_BLIND_BIG_DEFAULT;
|
||||
this->grave.clear();
|
||||
this->community.clear();
|
||||
this->pots.clear();
|
||||
this->pots.push_back(PokerPot());
|
||||
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
auto player = *it;
|
||||
player->hand.clear();
|
||||
player->currentBet = 0;
|
||||
player->isFolded = false;
|
||||
player->isShowingHand = false;
|
||||
player->hasBetThisRound = false;
|
||||
player->timesRaised = 0;
|
||||
player->currentBet = 0;
|
||||
++it;
|
||||
}
|
||||
|
||||
this->setDealer(this->dealerIndex + 0x01);
|
||||
}
|
||||
|
||||
void PokerGame::newBettingRound() {
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
auto player = *it;
|
||||
player->hasBetThisRound = false;
|
||||
player->timesRaised = 0;
|
||||
++it;
|
||||
}
|
||||
|
||||
this->betterIndex = this->bigBlindIndex;
|
||||
this->betterIndex = this->getNextBetterIndex();
|
||||
}
|
||||
|
||||
uint8_t PokerGame::getNextBetterIndex() {
|
||||
uint8_t j, i;
|
||||
for(i = 0; i < this->players.size(); i++) {
|
||||
j = (i + this->betterIndex) % this->players.size();
|
||||
auto player = this->players[j];
|
||||
if(player->needsToBetThisRound()) return j;
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void PokerGame::takeBlinds() {
|
||||
auto playerSmallBlind = this->players[this->smallBlindIndex];
|
||||
auto playerBigBlind = this->players[this->bigBlindIndex];
|
||||
|
||||
playerSmallBlind->bet(this->smallBlind);
|
||||
playerBigBlind->bet(this->bigBlind);
|
||||
|
||||
playerSmallBlind->hasBetThisRound = false;
|
||||
playerBigBlind->hasBetThisRound = false;
|
||||
}
|
||||
|
||||
void PokerGame::setDealer(uint8_t dealer) {
|
||||
uint8_t i, k;
|
||||
PokerPlayer *player;
|
||||
bool_t foundDealer;
|
||||
bool_t foundSmall;
|
||||
|
||||
foundDealer = false;
|
||||
foundSmall = false;
|
||||
this->dealerIndex = dealer;
|
||||
|
||||
for(i = 0; i < this->players.size(); i++) {
|
||||
k = (dealer + i) % this->players.size();
|
||||
player = this->players[k];
|
||||
if(player->isOut) ;
|
||||
if(!foundDealer) {
|
||||
this->dealerIndex = k;
|
||||
foundDealer = true;
|
||||
} else if(!foundSmall) {
|
||||
this->smallBlindIndex = k;
|
||||
foundSmall = true;
|
||||
} else {
|
||||
this->bigBlindIndex = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t PokerGame::getRemainingBettersCount() {
|
||||
uint8_t count = 0;
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
if((*it)->needsToBetThisRound()) count++;
|
||||
++it;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t PokerGame::getRemainingPlayersCount() {
|
||||
uint8_t count = 0;
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
auto player = *it;
|
||||
if(!player->isFolded && !player->isOut) count++;
|
||||
++it;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int32_t PokerGame::getCurrentCallValue() {
|
||||
assertTrue(this->pots.size() > 0);
|
||||
return this->pots.back().call;
|
||||
}
|
||||
|
||||
void PokerGame::burnCard() {
|
||||
assertTrue(this->deck.size() > 0);
|
||||
auto card = this->deck.back();
|
||||
this->deck.pop_back();
|
||||
this->grave.push_back(card);
|
||||
}
|
||||
|
||||
void PokerGame::dealCard(PokerPlayer *player) {
|
||||
assertTrue(this->deck.size() > 0);
|
||||
auto card = this->deck.back();
|
||||
this->deck.pop_back();
|
||||
player->hand.push_back(card);
|
||||
}
|
||||
|
||||
void PokerGame::dealToEveryone(uint8_t count) {
|
||||
for(uint8_t i = 0; i < count; i++) {
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
this->dealCard(*it);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PokerGame::turn(uint8_t count) {
|
||||
assertTrue(this->deck.size() >= count);
|
||||
for(uint8_t i = 0; i < count; i++) {
|
||||
auto card = this->deck.back();
|
||||
this->deck.pop_back();
|
||||
this->community.push_back(card);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t PokerGame::getCountOfCardsToTurn() {
|
||||
switch(this->community.size()) {
|
||||
case 0x00:
|
||||
return POKER_FLOP_CARD_COUNT;
|
||||
|
||||
case 0x03:
|
||||
return POKER_TURN_CARD_COUNT;
|
||||
|
||||
case 0x04:
|
||||
return POKER_RIVER_CARD_COUNT;
|
||||
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
@ -4,31 +4,25 @@
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "Card.hpp"
|
||||
#include "PokerPlayer.hpp"
|
||||
|
||||
/** The default blind cost for the big blind. */
|
||||
#define POKER_BLIND_BIG_DEFAULT 600
|
||||
/** The default blind cost for the small blind. (Defaults half big blind) */
|
||||
#define POKER_BLIND_SMALL_DEFAULT (POKER_BLIND_BIG_DEFAULT/2)
|
||||
|
||||
/** How many cards are dealt for the flop, turn and river */
|
||||
#define POKER_FLOP_CARD_COUNT 3
|
||||
#define POKER_TURN_CARD_COUNT 1
|
||||
#define POKER_RIVER_CARD_COUNT 1
|
||||
|
||||
namespace Dawn {
|
||||
class PokerPlayer {
|
||||
public:
|
||||
int32_t i;
|
||||
};
|
||||
|
||||
class PokerPot {
|
||||
public:
|
||||
int32_t i;
|
||||
};
|
||||
|
||||
class PokerGame {
|
||||
class PokerGame : public SceneItemComponent {
|
||||
protected:
|
||||
std::vector<PokerPlayer> players;
|
||||
std::vector<struct Card> cards;
|
||||
std::vector<struct Card> deck;
|
||||
std::vector<struct Card> grave;
|
||||
std::vector<struct Card> community;
|
||||
std::vector<struct PokerPot> pots;
|
||||
uint8_t dealerIndex;
|
||||
uint8_t smallBlindIndex;
|
||||
uint8_t bigBlindIndex;
|
||||
@ -37,6 +31,29 @@ namespace Dawn {
|
||||
int32_t bigBlind = POKER_BLIND_BIG_DEFAULT;
|
||||
|
||||
public:
|
||||
PokerGame();
|
||||
std::vector<PokerPlayer*> players;
|
||||
|
||||
PokerGame(SceneItem *item);
|
||||
|
||||
void onStart() override;
|
||||
|
||||
void newGame();
|
||||
void newRound();
|
||||
void newBettingRound();
|
||||
void takeBlinds();
|
||||
void setBlinds(int32_t small, int32_t big);
|
||||
uint8_t getRemainingBettersCount();
|
||||
int32_t getCurrentCallValue();
|
||||
uint8_t getNextBetterIndex();
|
||||
void setDealer(uint8_t dealer);
|
||||
void newDealer();
|
||||
void burnCard();
|
||||
void dealCard(PokerPlayer *player);
|
||||
void dealToEveryone(uint8_t count);
|
||||
void turn(uint8_t count);
|
||||
uint8_t getCountOfCardsToTurn();
|
||||
uint8_t getRemainingPlayersCount();
|
||||
|
||||
friend class PokerPlayer;
|
||||
};
|
||||
}
|
432
src/dawn/poker/PokerPlayer.cpp
Normal file
432
src/dawn/poker/PokerPlayer.cpp
Normal file
@ -0,0 +1,432 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PokerPlayer.hpp"
|
||||
#include "PokerGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
PokerPlayer::PokerPlayer(SceneItem *item) : SceneItemComponent(item) {
|
||||
|
||||
}
|
||||
|
||||
void PokerPlayer::onStart() {
|
||||
SceneItemComponent::onStart();
|
||||
|
||||
this->pokerGame = this->getScene()->findComponent<PokerGame>();
|
||||
assertNotNull(this->pokerGame);
|
||||
}
|
||||
|
||||
void PokerPlayer::addChips(int32_t chips) {
|
||||
assertTrue(chips > 0);
|
||||
|
||||
this->chips += chips;
|
||||
if(this->chips > 0) this->isOut = false;
|
||||
}
|
||||
|
||||
bool_t PokerPlayer::needsToBetThisRound() {
|
||||
if(this->isFolded) return false;
|
||||
if(this->chips <= 0) return false;
|
||||
if(!this->hasBetThisRound) return true;
|
||||
if(this->currentBet < this->pokerGame->getCurrentCallValue()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void PokerPlayer::bet(struct PokerPot *pot, int32_t chips) {
|
||||
assertNotNull(pot);
|
||||
assertTrue(chips >= 0);
|
||||
assertTrue(!this->isFolded);
|
||||
assertTrue(!this->isOut);
|
||||
this->chips -= chips;
|
||||
this->currentBet += chips;
|
||||
this->hasBetThisRound = true;
|
||||
if(chips > 0) this->timesRaised++;
|
||||
|
||||
pot->chips += chips;
|
||||
pot->call = mathMax<int32_t>(pot->call, this ->currentBet);
|
||||
|
||||
auto existing = std::find(pot->players.begin(), pot->players.end(), this);
|
||||
if(existing == pot->players.end()) pot->players.push_back(this);
|
||||
}
|
||||
|
||||
void PokerPlayer::bet(int32_t chips) {
|
||||
assertTrue(this->pokerGame->pots.size() > 0);
|
||||
this->bet(&this->pokerGame->pots.back(), chips);
|
||||
}
|
||||
|
||||
bool_t PokerPlayer::canCheck() {
|
||||
return this->pokerGame->getCurrentCallValue() <= this->currentBet;
|
||||
}
|
||||
|
||||
struct PokerTurn PokerPlayer::getAITurn() {
|
||||
struct PokerTurn turn;
|
||||
float_t confidence;
|
||||
int32_t callBet;
|
||||
float_t potOdds;
|
||||
|
||||
// Can the player do anything?
|
||||
if(this->isFolded || this->isOut) {
|
||||
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(this->pokerGame->community.size() == 0) {
|
||||
assertTrue(this->hand.size() == POKER_PLAYER_HAND_SIZE_MAX);
|
||||
|
||||
// Get the hand weight
|
||||
auto cardNumber0 = this->hand[0].getValue();
|
||||
auto suitNumber0 = this->hand[0].getSuit();
|
||||
auto cardNumber1 = this->hand[1].getValue();
|
||||
auto suitNumber1 = this->hand[1].getSuit();
|
||||
|
||||
// Get delta between cards
|
||||
auto i = (uint8_t)mathAbs<int8_t>(
|
||||
(int8_t)cardNumber0 - (int8_t)cardNumber1
|
||||
);
|
||||
|
||||
// Get card weight
|
||||
float_t confidence = (float_t)cardNumber0 + (float_t)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;
|
||||
|
||||
// This may change in future, but I was finding the AI did not want to bet
|
||||
// during the preflop enough, this curves the AI to want to preflop call
|
||||
// often.
|
||||
confidence = easeOutCubic(confidence);
|
||||
} else {
|
||||
// Simulate my hand being the winning hand, use that as the confidence
|
||||
auto winning = this->getWinning();
|
||||
confidence = PokerWinning::getWinningTypeConfidence(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 = this->getCallBet();
|
||||
|
||||
// Do they need chips to call, or is it possible to check?
|
||||
if(callBet > 0) {
|
||||
potOdds = (float_t)callBet / (
|
||||
(float_t)callBet +
|
||||
(float_t)this->getSumOfChips()
|
||||
);
|
||||
} else {
|
||||
potOdds = 1.0f / (float_t)this->pokerGame->getRemainingBettersCount();
|
||||
}
|
||||
|
||||
// Now determine the expected ROI
|
||||
auto expectedGain = confidence / potOdds;
|
||||
|
||||
// Now get a random 0-100
|
||||
auto random = randomGenerate<int32_t>() % 100;
|
||||
|
||||
// Determine the max bet that the AI is willing to make
|
||||
auto maxBet = (int32_t)((float_t)this->chips / 1.75f) - (random / 2);
|
||||
maxBet -= callBet;
|
||||
|
||||
// Determine what's a good bluff bet.
|
||||
auto bluffBet = random * maxBet / 100 / 2;
|
||||
|
||||
// Now prep the output
|
||||
auto isBluff = false;
|
||||
auto 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.8f && confidence < 0.8f) {
|
||||
if(random < 85) {
|
||||
amount = 0;
|
||||
} else {
|
||||
amount = bluffBet;
|
||||
isBluff = true;
|
||||
}
|
||||
} else if ((expectedGain < 1.0f && confidence < 0.85f) || confidence < 0.1f) {
|
||||
if (random < 80) {
|
||||
amount = 0;
|
||||
} else if(random < 5) {
|
||||
amount = callBet;
|
||||
isBluff = true;
|
||||
} else {
|
||||
amount = bluffBet;
|
||||
isBluff = true;
|
||||
}
|
||||
} else if ((expectedGain < 1.3f && confidence < 0.9f) || confidence < 0.5f) {
|
||||
if (random < 60 || confidence < 0.5f) {
|
||||
amount = callBet;
|
||||
} else {
|
||||
amount = maxBet;
|
||||
}
|
||||
} else if (confidence < 0.95f || this->pokerGame->community.size() < 4) {
|
||||
if(random < 20) {
|
||||
amount = callBet;
|
||||
} else {
|
||||
amount = maxBet;
|
||||
}
|
||||
} else {
|
||||
amount = (this->chips - callBet) * 9 / 10;
|
||||
}
|
||||
|
||||
// TODO: We can nicely round the amounts here to get us to a more "human"
|
||||
// number.
|
||||
|
||||
// If this is the first round... make it a lot less likely I'll bet
|
||||
if(this->pokerGame->community.size() == 0 && amount > callBet) {
|
||||
if(random > 5) amount = callBet;
|
||||
}
|
||||
|
||||
// Did we actually bet?
|
||||
if(amount > 0) {
|
||||
std::cout << "AI is betting " << amount << " chips, bluff:" << isBluff << std::endl;
|
||||
|
||||
// Let's not get caught in a raising loop with AI.
|
||||
if(this->timesRaised >= POKER_PLAYER_MAX_RAISES) {
|
||||
amount = callBet;
|
||||
}
|
||||
|
||||
amount = mathMax<int32_t>(amount, callBet);
|
||||
turn = PokerTurn::bet(this, amount);
|
||||
turn.confidence = confidence;
|
||||
} else if(this->canCheck()) {
|
||||
turn = PokerTurn::bet(this, 0);
|
||||
turn.confidence = 1;
|
||||
} else {
|
||||
turn = PokerTurn::fold();
|
||||
turn.confidence = 1 - confidence;
|
||||
}
|
||||
|
||||
return turn;
|
||||
}
|
||||
|
||||
int32_t PokerPlayer::getCallBet() {
|
||||
return this->pokerGame->getCurrentCallValue() - this->currentBet;
|
||||
}
|
||||
|
||||
int32_t PokerPlayer::getSumOfChips() {
|
||||
int32_t count = 0;
|
||||
auto it = this->pokerGame->pots.begin();
|
||||
while(it != this->pokerGame->pots.end()) {
|
||||
if(std::find(it->players.begin(), it->players.end(), this) != it->players.end()) {
|
||||
count += it->chips;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
struct PokerWinning PokerPlayer::getWinning() {
|
||||
struct PokerWinning winning;
|
||||
|
||||
// Get the full poker hand (should be a 7 card hand, but MAY not be)
|
||||
auto itHand = this->hand.begin();
|
||||
while(itHand != this->hand.end()) {
|
||||
winning.full.push_back(*itHand);
|
||||
++itHand;
|
||||
}
|
||||
|
||||
auto itCommunity = this->pokerGame->community.begin();
|
||||
while(itCommunity != this->pokerGame->community.end()) {
|
||||
winning.full.push_back(*itCommunity);
|
||||
++itCommunity;
|
||||
}
|
||||
Card::sort(&winning.full);
|
||||
|
||||
//////////////////////// Now look for the winning set ////////////////////////
|
||||
|
||||
// Royal / Straight Flush
|
||||
auto it = winning.full.begin();
|
||||
while(it != winning.full.end()) {
|
||||
auto number = it->getValue();
|
||||
if(number < CARD_FIVE) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto suit = it->getSuit();
|
||||
winning->setSize = 1;
|
||||
|
||||
// Now look for the matching cards (Reverse order to order from A to 10)
|
||||
for(j = 1; j <= 4; j++) {
|
||||
l = number == CARD_FIVE && j == 4 ? CARD_ACE : number - j;//Ace low.
|
||||
index = cardContains(winning->full, winning->fullSize, cardGet(l, suit));
|
||||
if(index == -1) break;
|
||||
winning->set[j] = winning->full[index];
|
||||
winning->setSize++;
|
||||
}
|
||||
|
||||
// Check if has all necessary cards.
|
||||
if(winning->setSize < POKER_WINNING_SET_SIZE) continue;
|
||||
|
||||
// Add self to array
|
||||
winning->set[0] = winning->full[i];
|
||||
winning->type = (
|
||||
number == CARD_ACE ? POKER_WINNING_TYPE_ROYAL_FLUSH :
|
||||
POKER_WINNING_TYPE_STRAIGHT_FLUSH
|
||||
);
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Four of a kind.
|
||||
winning->setSize = 0;
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
card = winning->full[i];
|
||||
number = cardGetNumber(card);
|
||||
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
|
||||
if(pairCount < CARD_SUIT_COUNT) continue;
|
||||
|
||||
winning->setSize = pairCount;
|
||||
for(j = 0; j < pairCount; j++) winning->set[j] = winning->full[pairs[j]];
|
||||
winning->type = POKER_WINNING_TYPE_FOUR_OF_A_KIND;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Full House
|
||||
winning->setSize = 0;
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
// Check we haven't already added this card.
|
||||
card = winning->full[i];
|
||||
if(winning->setSize > 0 && (winning->set, winning->setSize, card) != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
number = cardGetNumber(card);
|
||||
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
|
||||
|
||||
// Did we find either two pair or three pair?
|
||||
if(pairCount != 2 && pairCount != 3) continue;
|
||||
if(winning->setSize == 3) pairCount = 2;//Clamp to 5 max.
|
||||
|
||||
// Copy found pairs.
|
||||
for(j = 0; j < pairCount; j++) {
|
||||
winning->set[winning->setSize + j] = winning->full[pairs[j]];
|
||||
}
|
||||
winning->setSize += pairCount;
|
||||
|
||||
// Winned?
|
||||
if(winning->setSize != POKER_WINNING_SET_SIZE) continue;
|
||||
winning->type = POKER_WINNING_TYPE_FULL_HOUSE;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Flush (5 same suit)
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
card = winning->full[i];
|
||||
suit = cardGetSuit(card);
|
||||
winning->setSize = 1;
|
||||
for(j = i+1; j < winning->fullSize; j++) {
|
||||
if(cardGetSuit(winning->full[j]) != suit) continue;
|
||||
winning->set[winning->setSize++] = winning->full[j];
|
||||
if(winning->setSize == POKER_WINNING_SET_SIZE) break;
|
||||
}
|
||||
if(winning->setSize < POKER_WINNING_SET_SIZE) continue;
|
||||
winning->set[0] = winning->full[i];
|
||||
winning->type = POKER_WINNING_TYPE_FLUSH;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Straight (sequence any suit)
|
||||
winning->setSize = 0;
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
card = winning->full[i];
|
||||
number = cardGetNumber(card);
|
||||
if(number < CARD_FIVE) continue;
|
||||
winning->setSize = 1;
|
||||
|
||||
for(j = 1; j <= 4; j++) {
|
||||
l = number == CARD_FIVE && j == 4 ? CARD_ACE : number - j;//Ace low.
|
||||
index = cardContainsNumber(winning->full, winning->fullSize, l);
|
||||
if(index == -1) break;
|
||||
winning->set[j] = winning->full[index];
|
||||
winning->setSize++;
|
||||
}
|
||||
|
||||
// Check if has all necessary cards.
|
||||
if(winning->setSize < POKER_WINNING_SET_SIZE) continue;
|
||||
winning->set[0] = winning->full[i];
|
||||
winning->type = POKER_WINNING_TYPE_STRAIGHT;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Three of a kind
|
||||
winning->setSize = 0;
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
card = winning->full[i];
|
||||
number = cardGetNumber(card);
|
||||
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
|
||||
if(pairCount != 3) continue;
|
||||
|
||||
winning->setSize = pairCount;
|
||||
for(j = 0; j < pairCount; j++) winning->set[j] = winning->full[pairs[j]];
|
||||
winning->type = POKER_WINNING_TYPE_THREE_OF_A_KIND;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Two Pair
|
||||
winning->setSize = 0;
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
card = winning->full[i];// Check we haven't already added this card.
|
||||
if(
|
||||
winning->setSize > 0 &&
|
||||
cardContains(winning->set, winning->setSize, card) != -1
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
number = cardGetNumber(card);
|
||||
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
|
||||
if(pairCount != 2) continue;
|
||||
|
||||
for(j = 0; j < pairCount; j++) {
|
||||
winning->set[winning->setSize+j] = winning->full[pairs[j]];
|
||||
}
|
||||
winning->setSize += pairCount;
|
||||
if(winning->setSize != 4) continue;
|
||||
|
||||
winning->type = POKER_WINNING_TYPE_TWO_PAIR;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Pair
|
||||
if(winning->setSize == 2) {
|
||||
winning->type = POKER_WINNING_TYPE_PAIR;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// High card
|
||||
winning->setSize = 0;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
winning->type = POKER_WINNING_TYPE_HIGH_CARD;
|
||||
|
||||
return;
|
||||
}
|
119
src/dawn/poker/PokerPlayer.hpp
Normal file
119
src/dawn/poker/PokerPlayer.hpp
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "Card.hpp"
|
||||
#include "scene/Scene.hpp"
|
||||
#include "PokerPot.hpp"
|
||||
#include "util/mathutils.hpp"
|
||||
#include "display/animation/Easing.hpp"
|
||||
#include "PokerWinning.hpp"
|
||||
#include "PokerTurn.hpp"
|
||||
#include "util/random.hpp"
|
||||
|
||||
#define POKER_PLAYER_CHIPS_DEFAULT 10000
|
||||
|
||||
/** Maximum cards a players' hand can hold */
|
||||
#define POKER_PLAYER_HAND_SIZE_MAX 2
|
||||
|
||||
#define POKER_PLAYER_MAX_RAISES 0x02
|
||||
|
||||
namespace Dawn {
|
||||
class PokerGame;
|
||||
|
||||
class PokerPlayer : public SceneItemComponent {
|
||||
public:
|
||||
PokerGame *pokerGame;
|
||||
int32_t chips = 0;
|
||||
int32_t currentBet = 0;
|
||||
uint8_t timesRaised = 0;
|
||||
bool_t isFolded = false;
|
||||
bool_t isOut = false;
|
||||
bool_t hasBetThisRound = false;
|
||||
bool_t isShowingHand = false;
|
||||
bool_t isHuman = false;
|
||||
std::vector<struct Card> hand;
|
||||
|
||||
/**
|
||||
* Creates a PokerPlayer instance.
|
||||
*
|
||||
* @param item Item that this poker player belongs to.
|
||||
*/
|
||||
PokerPlayer(SceneItem *item);
|
||||
|
||||
/** Override for scene item component event for init */
|
||||
void onStart() override;
|
||||
|
||||
/**
|
||||
* Adds chips to the player. This will also update the players' state.
|
||||
*
|
||||
* @param chips Count of chips to add.
|
||||
*/
|
||||
void addChips(int32_t chips);
|
||||
|
||||
/**
|
||||
* Returns true if the player still needs to bet this betting round.
|
||||
*
|
||||
* @return True if betting is still required by this player.
|
||||
*/
|
||||
bool_t needsToBetThisRound();
|
||||
|
||||
/**
|
||||
* Let a player bet chips into the pot.
|
||||
*
|
||||
* @param pot Poker pot to bet in to.
|
||||
* @param amount The amount of chips the player is betting.
|
||||
*/
|
||||
void bet(struct PokerPot *pot, int32_t amount);
|
||||
|
||||
/**
|
||||
* Let a player bet chips into the current pot.
|
||||
*
|
||||
* @param amount The amount of chips the player is betting.
|
||||
*/
|
||||
void bet(int32_t amount);
|
||||
|
||||
/**
|
||||
* Returns the AI result for a turn done by a non human player.
|
||||
*
|
||||
* @return Some information about the move the player is trying to perform
|
||||
*/
|
||||
struct PokerTurn getAITurn();
|
||||
|
||||
/**
|
||||
* Calculates and returns the winning state for a given player
|
||||
*
|
||||
* @return The winning state for this current players hand.
|
||||
*/
|
||||
struct PokerWinning getWinning();
|
||||
|
||||
/**
|
||||
* Returns the sum of chips in the pot(s) that the specified player is in.
|
||||
* This does not consider the pot, player or hand, just the pure sum of
|
||||
* chips.
|
||||
*
|
||||
* @return The sum of chips from the pots the player is within.
|
||||
*/
|
||||
int32_t getSumOfChips();
|
||||
|
||||
/**
|
||||
* Get the bet necessary for a specific player to make a call. This takes
|
||||
* the players current bet and the bet necessary to call into the pot and
|
||||
* will return the difference.
|
||||
*
|
||||
* @return The count of chips needed to call into the current active pot.
|
||||
*/
|
||||
int32_t getCallBet();
|
||||
|
||||
/**
|
||||
* Returns whether or not the player can check, or if they need to either
|
||||
* fold, call or bet.
|
||||
*
|
||||
* @return True if they can check.
|
||||
*/
|
||||
bool_t canCheck();
|
||||
};
|
||||
}
|
17
src/dawn/poker/PokerPot.hpp
Normal file
17
src/dawn/poker/PokerPot.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerPlayer;
|
||||
|
||||
struct PokerPot {
|
||||
int32_t chips;
|
||||
int32_t call;
|
||||
std::vector<PokerPlayer*> players;
|
||||
};
|
||||
}
|
46
src/dawn/poker/PokerTurn.cpp
Normal file
46
src/dawn/poker/PokerTurn.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PokerTurn.hpp"
|
||||
#include "PokerPlayer.hpp"
|
||||
#include "PokerGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
struct PokerTurn PokerTurn::bet(PokerPlayer *player, int32_t chips) {
|
||||
struct PokerTurn turn;
|
||||
int32_t i;
|
||||
|
||||
assertNotNull(player);
|
||||
assertTrue(chips >= 0);
|
||||
|
||||
turn.confidence = 1;
|
||||
|
||||
if(chips == 0) {
|
||||
turn.type = POKER_TURN_TYPE_CHECK;
|
||||
turn.chips = 0;
|
||||
} else if(player->chips <= chips) {
|
||||
turn.chips = player->chips;
|
||||
turn.type = POKER_TURN_TYPE_ALL_IN;
|
||||
} else {
|
||||
turn.chips = chips;
|
||||
turn.type = POKER_TURN_TYPE_BET;
|
||||
i = player->pokerGame->getCurrentCallValue();
|
||||
|
||||
if(chips == (i - player->currentBet)) {
|
||||
turn.type = POKER_TURN_TYPE_CALL;
|
||||
}
|
||||
}
|
||||
|
||||
return turn;
|
||||
}
|
||||
|
||||
struct PokerTurn PokerTurn::fold() {
|
||||
struct PokerTurn turn;
|
||||
turn.chips = 0;
|
||||
turn.confidence = 1;
|
||||
turn.type = POKER_TURN_TYPE_FOLD;
|
||||
return turn;
|
||||
}
|
46
src/dawn/poker/PokerTurn.hpp
Normal file
46
src/dawn/poker/PokerTurn.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerPlayer;
|
||||
|
||||
enum PokerTurnType {
|
||||
POKER_TURN_TYPE_OUT,
|
||||
POKER_TURN_TYPE_FOLD,
|
||||
POKER_TURN_TYPE_BET,
|
||||
POKER_TURN_TYPE_CALL,
|
||||
POKER_TURN_TYPE_CHECK,
|
||||
POKER_TURN_TYPE_ALL_IN
|
||||
};
|
||||
|
||||
struct PokerTurn {
|
||||
public:
|
||||
/** What type of action the turn is */
|
||||
enum PokerTurnType type;
|
||||
/** How many chips they did in their turn (if applicable) */
|
||||
int32_t chips;
|
||||
/** How confident the AI is about their turn. 0 = none, 1 = full */
|
||||
float_t confidence;
|
||||
|
||||
/**
|
||||
* Generate a turn action for betting as a player.
|
||||
*
|
||||
* @param player Player index who is betting.
|
||||
* @param chips Chips to raise by.
|
||||
* @return A turn for a bet action.
|
||||
*/
|
||||
static struct PokerTurn bet(PokerPlayer *player, int32_t chips);
|
||||
|
||||
/**
|
||||
* Return a turn action for the given player to fold.
|
||||
*
|
||||
* @return A turn for a fold action.
|
||||
*/
|
||||
static struct PokerTurn fold();
|
||||
};
|
||||
}
|
33
src/dawn/poker/PokerWinning.cpp
Normal file
33
src/dawn/poker/PokerWinning.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PokerWinning.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
float_t PokerWinning::getWinningTypeConfidence(enum PokerWinningType type) {
|
||||
switch(type) {
|
||||
case POKER_WINNING_TYPE_ROYAL_FLUSH:
|
||||
return POKER_WINNING_CONFIDENCE_ROYAL_FLUSH;
|
||||
case POKER_WINNING_TYPE_STRAIGHT_FLUSH:
|
||||
return POKER_WINNING_CONFIDENCE_STRAIGHT_FLUSH;
|
||||
case POKER_WINNING_TYPE_FOUR_OF_A_KIND:
|
||||
return POKER_WINNING_CONFIDENCE_FOUR_OF_A_KIND;
|
||||
case POKER_WINNING_TYPE_FULL_HOUSE:
|
||||
return POKER_WINNING_CONFIDENCE_FULL_HOUSE;
|
||||
case POKER_WINNING_TYPE_FLUSH:
|
||||
return POKER_WINNING_CONFIDENCE_FLUSH;
|
||||
case POKER_WINNING_TYPE_STRAIGHT:
|
||||
return POKER_WINNING_CONFIDENCE_STRAIGHT;
|
||||
case POKER_WINNING_TYPE_THREE_OF_A_KIND:
|
||||
return POKER_WINNING_CONFIDENCE_THREE_OF_A_KIND;
|
||||
case POKER_WINNING_TYPE_TWO_PAIR:
|
||||
return POKER_WINNING_CONFIDENCE_TWO_PAIR;
|
||||
case POKER_WINNING_TYPE_PAIR:
|
||||
return POKER_WINNING_CONFIDENCE_PAIR;
|
||||
default:
|
||||
return POKER_WINNING_CONFIDENCE_HIGH_CARD;
|
||||
}
|
||||
}
|
43
src/dawn/poker/PokerWinning.hpp
Normal file
43
src/dawn/poker/PokerWinning.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
#include "Card.hpp"
|
||||
|
||||
#define POKER_WINNING_CONFIDENCE_ROYAL_FLUSH 1.0f
|
||||
#define POKER_WINNING_CONFIDENCE_STRAIGHT_FLUSH 0.99f
|
||||
#define POKER_WINNING_CONFIDENCE_FOUR_OF_A_KIND 0.9f
|
||||
#define POKER_WINNING_CONFIDENCE_FULL_HOUSE 0.85f
|
||||
#define POKER_WINNING_CONFIDENCE_FLUSH 0.8f
|
||||
#define POKER_WINNING_CONFIDENCE_STRAIGHT 0.7f
|
||||
#define POKER_WINNING_CONFIDENCE_THREE_OF_A_KIND 0.5f
|
||||
#define POKER_WINNING_CONFIDENCE_TWO_PAIR 0.4f
|
||||
#define POKER_WINNING_CONFIDENCE_PAIR 0.2f
|
||||
#define POKER_WINNING_CONFIDENCE_HIGH_CARD 0.1f
|
||||
|
||||
namespace Dawn {
|
||||
enum PokerWinningType {
|
||||
POKER_WINNING_TYPE_NULL,
|
||||
POKER_WINNING_TYPE_ROYAL_FLUSH,
|
||||
POKER_WINNING_TYPE_STRAIGHT_FLUSH,
|
||||
POKER_WINNING_TYPE_FOUR_OF_A_KIND,
|
||||
POKER_WINNING_TYPE_FULL_HOUSE,
|
||||
POKER_WINNING_TYPE_FLUSH,
|
||||
POKER_WINNING_TYPE_STRAIGHT,
|
||||
POKER_WINNING_TYPE_THREE_OF_A_KIND,
|
||||
POKER_WINNING_TYPE_TWO_PAIR,
|
||||
POKER_WINNING_TYPE_PAIR,
|
||||
POKER_WINNING_TYPE_HIGH_CARD
|
||||
};
|
||||
|
||||
struct PokerWinning {
|
||||
public:
|
||||
enum PokerWinningType type;
|
||||
std::vector<struct Card> full;
|
||||
|
||||
static float_t getWinningTypeConfidence(enum PokerWinningType type);
|
||||
};
|
||||
}
|
10
src/dawn/poker/visualnovel/CMakeLists.txt
Normal file
10
src/dawn/poker/visualnovel/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
PokerDetermineBetterEvent.cpp
|
||||
)
|
35
src/dawn/poker/visualnovel/PokerAIBetEvent.hpp
Normal file
35
src/dawn/poker/visualnovel/PokerAIBetEvent.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
#define POKER_DEAL_EVENT_CARD_COUNT 2
|
||||
|
||||
namespace Dawn {
|
||||
class PokerDealEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart() override {
|
||||
PokerGameEvent::onStart();
|
||||
|
||||
auto better = this->pokerGame->getNextBetterIndex();
|
||||
this->pokerGame->better = better;
|
||||
auto player = this->pokerGame->players[better];
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
uint8_t better;
|
||||
|
||||
PokerDealEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
30
src/dawn/poker/visualnovel/PokerDealEvent.hpp
Normal file
30
src/dawn/poker/visualnovel/PokerDealEvent.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
#define POKER_DEAL_EVENT_CARD_COUNT 2
|
||||
|
||||
namespace Dawn {
|
||||
class PokerDealEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart() override {
|
||||
PokerGameEvent::onStart();
|
||||
this->pokerGame->dealToEveryone(POKER_DEAL_EVENT_CARD_COUNT);
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
PokerDealEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
74
src/dawn/poker/visualnovel/PokerDetermineBetterEvent.cpp
Normal file
74
src/dawn/poker/visualnovel/PokerDetermineBetterEvent.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PokerDetermineBetterEvent.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
PokerDetermineBetterEvent::PokerDetermineBetterEvent(VisualNovelManager *man) :
|
||||
PokerGameEvent(man)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PokerDetermineBetterEvent::onStart() {
|
||||
PokerGameEvent::onStart();
|
||||
|
||||
if(this->pokerGame->getRemainingPlayersCount() <= 1) {
|
||||
this->doNext = this->eventEveryoneFolded;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t nextBetterIndex = this->pokerGame->getNextBetterIndex();
|
||||
if(nextBetterIndex == 0xFF) {
|
||||
if(this->pokerGame->getCountOfCardsToTurn() == 0xFF) {
|
||||
this->doNext = this->eventBettingFinished;
|
||||
} else {
|
||||
this->doNext = this->eventTurn;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto nextBetter = this->pokerGame->players[nextBetterIndex];
|
||||
if(nextBetter->isHuman) {
|
||||
this->doNext = this->eventHumanBet;
|
||||
} else {
|
||||
this->doNext = this->eventAiBet;
|
||||
}
|
||||
}
|
||||
|
||||
bool_t PokerDetermineBetterEvent::onUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void PokerDetermineBetterEvent::onEnd() {
|
||||
}
|
||||
|
||||
PokerDetermineBetterEvent::~PokerDetermineBetterEvent() {
|
||||
if(
|
||||
this->eventEveryoneFolded != nullptr &&
|
||||
this->eventEveryoneFolded != this->doNext
|
||||
) delete this->eventEveryoneFolded;
|
||||
|
||||
if(
|
||||
this->eventBettingFinished != nullptr &&
|
||||
this->eventBettingFinished != this->doNext
|
||||
) delete this->eventBettingFinished;
|
||||
|
||||
if(
|
||||
this->eventTurn != nullptr &&
|
||||
this->eventTurn != this->doNext
|
||||
) delete this->eventTurn;
|
||||
|
||||
if(
|
||||
this->eventAiBet != nullptr &&
|
||||
this->eventAiBet != this->doNext
|
||||
) delete this->eventAiBet;
|
||||
|
||||
if(
|
||||
this->eventHumanBet != nullptr &&
|
||||
this->eventHumanBet != this->doNext
|
||||
) delete this->eventHumanBet;
|
||||
}
|
106
src/dawn/poker/visualnovel/PokerDetermineBetterEvent.hpp
Normal file
106
src/dawn/poker/visualnovel/PokerDetermineBetterEvent.hpp
Normal file
@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerDetermineBetterEvent : public PokerGameEvent {
|
||||
protected:
|
||||
IVisualNovelEvent * eventEveryoneFolded = nullptr;
|
||||
IVisualNovelEvent * eventBettingFinished = nullptr;
|
||||
IVisualNovelEvent * eventTurn = nullptr;
|
||||
IVisualNovelEvent * eventAiBet = nullptr;
|
||||
IVisualNovelEvent * eventHumanBet = nullptr;
|
||||
|
||||
void onStart() override;
|
||||
bool_t onUpdate() override;
|
||||
void onEnd() override;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a better determine event.
|
||||
*
|
||||
* @param manager VN manager that this event belongs to.
|
||||
*/
|
||||
PokerDetermineBetterEvent(VisualNovelManager *manager);
|
||||
|
||||
/**
|
||||
* Sets the event that is triggered when everyone is folded.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
* @return The event that was passed in.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenEveryoneFolded(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventEveryoneFolded = event;
|
||||
event->previous = this;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event that is triggered after everyone has finished betting.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
* @return The event that was passed in.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenBettingFinished(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventBettingFinished = event;
|
||||
event->previous = this;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event to trigger when all betting is finished and its time to turn the
|
||||
* next set of community cards.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
* @return The event that was passed in.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenTurn(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventTurn = event;
|
||||
event->previous = this;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event to trigger when its an AI's turn to bet.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
* @return The event that was passed in.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenAiBet(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventAiBet = event;
|
||||
event->previous = this;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event to trigger when its a human's turn to bet.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
* @return The event that was passed in.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenHumanBet(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventHumanBet = event;
|
||||
event->previous = this;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose override for the event.
|
||||
*/
|
||||
~PokerDetermineBetterEvent();
|
||||
};
|
||||
}
|
27
src/dawn/poker/visualnovel/PokerGameEvent.hpp
Normal file
27
src/dawn/poker/visualnovel/PokerGameEvent.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "visualnovel/VisualNovelManager.hpp"
|
||||
#include "poker/PokerGame.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerGameEvent : public IVisualNovelEvent {
|
||||
protected:
|
||||
PokerGame *pokerGame;
|
||||
|
||||
void onStart() override {
|
||||
pokerGame = this->manager->getScene()->findComponent<PokerGame>();
|
||||
assertNotNull(pokerGame);
|
||||
}
|
||||
|
||||
public:
|
||||
PokerGameEvent(VisualNovelManager *manager) :
|
||||
IVisualNovelEvent(manager)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
}
|
28
src/dawn/poker/visualnovel/PokerNewGameEvent.hpp
Normal file
28
src/dawn/poker/visualnovel/PokerNewGameEvent.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerNewGameEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart() override {
|
||||
PokerGameEvent::onStart();
|
||||
this->pokerGame->newGame();
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
PokerNewGameEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
28
src/dawn/poker/visualnovel/PokerNewRoundEvent.hpp
Normal file
28
src/dawn/poker/visualnovel/PokerNewRoundEvent.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerNewRoundEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart() override {
|
||||
PokerGameEvent::onStart();
|
||||
this->pokerGame->newRound();
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
PokerNewRoundEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
28
src/dawn/poker/visualnovel/PokerTakeBlindsEvent.hpp
Normal file
28
src/dawn/poker/visualnovel/PokerTakeBlindsEvent.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerTakeBlindsEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart() override {
|
||||
PokerGameEvent::onStart();
|
||||
this->pokerGame->takeBlinds();
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
PokerTakeBlindsEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
34
src/dawn/poker/visualnovel/PokerTurnEvent.hpp
Normal file
34
src/dawn/poker/visualnovel/PokerTurnEvent.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerTurnEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart() override {
|
||||
PokerGameEvent::onStart();
|
||||
|
||||
this->cardsTurned = this->pokerGame->getCountOfCardsToTurn();
|
||||
assertTrue(this->cardsTurned != 0xFF);
|
||||
|
||||
this->pokerGame->turn(this->cardsTurned);
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
uint8_t cardsTurned;
|
||||
|
||||
PokerTurnEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
@ -1,105 +1,117 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
#define MATH_PI 3.1415926535897f
|
||||
|
||||
/**
|
||||
* Returns the largest of the two provided int32 numbers.
|
||||
*
|
||||
* @param left Left number to get the largest of.
|
||||
* @param right Right number to get the largest of.
|
||||
* @return The larger of the two numbers
|
||||
*/
|
||||
template<typename T>
|
||||
static inline T mathMax(T left, T right) {
|
||||
return left < right ? right : left;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the smallest of two provided int32 numbers.
|
||||
*
|
||||
* @param left Left number to get the smallest of.
|
||||
* @param right Right number to get the smallest of.
|
||||
* @return Smaller of the two numbers.
|
||||
*/
|
||||
template<typename T>
|
||||
static inline T mathMin(T left, T right) {
|
||||
return left < right ? left : right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the input value, constrained between the min and max values, so that
|
||||
* the value cannot underceed the min, and cannot exceed the max.
|
||||
*
|
||||
* @param val Value to get the clamp for.
|
||||
* @param min Minimum clamping value.
|
||||
* @param max Maximum clamping value.
|
||||
* @return The value, or the closest clamped value.
|
||||
*/
|
||||
template<typename T>
|
||||
static inline T mathClamp(T val, T min, T max) {
|
||||
return mathMin<T>(mathMax<T>(val, min), max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute value (the non-negative representation of) for the given
|
||||
* int32 number.Abs values will be -value if value < 0.
|
||||
*
|
||||
* @param value Value to get the absolute value for.
|
||||
* @return The absolute value (-value if value < 0)
|
||||
*/
|
||||
template<typename T>
|
||||
static inline T mathAbs(T value) {
|
||||
return value < 0 ? -value : value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline int32_t mathMod(T value, T modulo) {
|
||||
return ((value % modulo) + modulo) % modulo;
|
||||
}
|
||||
|
||||
// Float-specific
|
||||
|
||||
/**
|
||||
* Convert degrees to radians.
|
||||
*
|
||||
* @param n Degrees to convert.
|
||||
* @returns The number in radians.
|
||||
*/
|
||||
static inline float_t mathDeg2Rad(float_t degrees) {
|
||||
return degrees * (MATH_PI / 180.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert radians to degrees.
|
||||
* @param n Radians to convert.
|
||||
* @returns The number in degrees.
|
||||
*/
|
||||
static inline float_t mathRad2Deg(float_t n) {
|
||||
return (n * 180.0f) / MATH_PI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Round a number to the nearest whole number.
|
||||
* @param n Number to round.
|
||||
* @return Rounded number.
|
||||
*/
|
||||
static inline float_t mathRoundFloat(float_t n) {
|
||||
return roundf(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds the number down to the nearest whole number.
|
||||
* @param n Number to round down.
|
||||
* @return Rounded number.
|
||||
*/
|
||||
static inline float_t mathFloorFloat(float_t n) {
|
||||
return floorf(n);
|
||||
/**
|
||||
* Copyright (c) 2022 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
#define MATH_PI 3.1415926535897f
|
||||
|
||||
namespace Dawn {
|
||||
/**
|
||||
* Returns the largest of the two provided int32 numbers.
|
||||
*
|
||||
* @param left Left number to get the largest of.
|
||||
* @param right Right number to get the largest of.
|
||||
* @return The larger of the two numbers
|
||||
*/
|
||||
template<typename T>
|
||||
static T mathMax(T left, T right) {
|
||||
return left < right ? right : left;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the smallest of two provided int32 numbers.
|
||||
*
|
||||
* @param left Left number to get the smallest of.
|
||||
* @param right Right number to get the smallest of.
|
||||
* @return Smaller of the two numbers.
|
||||
*/
|
||||
template<typename T>
|
||||
static T mathMin(T left, T right) {
|
||||
return left < right ? left : right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the input value, constrained between the min and max values, so that
|
||||
* the value cannot underceed the min, and cannot exceed the max.
|
||||
*
|
||||
* @param val Value to get the clamp for.
|
||||
* @param min Minimum clamping value.
|
||||
* @param max Maximum clamping value.
|
||||
* @return The value, or the closest clamped value.
|
||||
*/
|
||||
template<typename T>
|
||||
static T mathClamp(T val, T min, T max) {
|
||||
return mathMin<T>(mathMax<T>(val, min), max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute value (the non-negative representation of) for the given
|
||||
* int32 number.Abs values will be -value if value < 0.
|
||||
*
|
||||
* @param value Value to get the absolute value for.
|
||||
* @return The absolute value (-value if value < 0)
|
||||
*/
|
||||
template<typename T>
|
||||
static T mathAbs(T value) {
|
||||
return value < 0 ? -value : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the modulous a result for b. Works for floating point numbers.
|
||||
*
|
||||
* @param a Number to modulo against. (a % b)
|
||||
* @param b Number to modulo with. (a % b)
|
||||
* @returns The modulo result.
|
||||
*/
|
||||
static float_t mathMod(float_t value, float_t modulo) {
|
||||
return (float_t)fmod(value, modulo);
|
||||
}
|
||||
|
||||
static int32_t mathMod(int32_t value, int32_t modulo) {
|
||||
return ((value % modulo) + modulo) % modulo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert degrees to radians.
|
||||
*
|
||||
* @param n Degrees to convert.
|
||||
* @returns The number in radians.
|
||||
*/
|
||||
static float_t mathDeg2Rad(float_t degrees) {
|
||||
return degrees * (MATH_PI / 180.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert radians to degrees.
|
||||
* @param n Radians to convert.
|
||||
* @returns The number in degrees.
|
||||
*/
|
||||
static float_t mathRad2Deg(float_t n) {
|
||||
return (n * 180.0f) / MATH_PI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Round a number to the nearest whole number.
|
||||
* @param n Number to round.
|
||||
* @return Rounded number.
|
||||
*/
|
||||
template<typename T>
|
||||
static T mathRound(float_t n) {
|
||||
return (T)roundf(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds the number down to the nearest whole number.
|
||||
* @param n Number to round down.
|
||||
* @return Rounded number.
|
||||
*/
|
||||
template<typename T>
|
||||
static T mathFloor(float_t n) {
|
||||
return (T)floorf(n);
|
||||
}
|
||||
}
|
43
src/dawn/util/random.hpp
Normal file
43
src/dawn/util/random.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
#include "mathutils.hpp"
|
||||
|
||||
/**
|
||||
* Seed the random number generator
|
||||
* @param seed Seed to use for the seeded random number generator.
|
||||
*/
|
||||
static void randSeed(int32_t seed) {
|
||||
srand(seed);
|
||||
}
|
||||
|
||||
static int32_t randomGeneratei32() {
|
||||
return (int32_t)rand();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random number.
|
||||
* @returns A random number.
|
||||
*/
|
||||
template<typename T>
|
||||
static T randomGenerate() {
|
||||
return (T)((float_t)randomGeneratei32() * MATH_PI);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Clamps a random number generation.
|
||||
*
|
||||
* @param min Minimum value to generate from. (Inclusive)
|
||||
* @param max Maximum value to generate to. (Exclusive)
|
||||
* @return Random number between min and max.
|
||||
*/
|
||||
template<typename T>
|
||||
static inline T randRange(T min, T max) {
|
||||
return mathMod(randomGenerate<T>(), (max - min)) + min;
|
||||
}
|
@ -66,13 +66,12 @@ IVisualNovelEvent * IVisualNovelEvent::end() {
|
||||
|
||||
if(this->doNext != nullptr) {
|
||||
auto next = this->doNext;
|
||||
this->doNext = nullptr;
|
||||
return next;
|
||||
}
|
||||
}
|
||||
|
||||
IVisualNovelEvent::~IVisualNovelEvent() {
|
||||
if(this->doNext != nullptr) {
|
||||
if(!this->hasStarted && this->doNext != nullptr) {
|
||||
delete this->doNext;
|
||||
}
|
||||
}
|
@ -67,12 +67,15 @@ namespace Dawn {
|
||||
virtual void onEnd() = 0;
|
||||
|
||||
public:
|
||||
IVisualNovelEvent *previous = nullptr;
|
||||
|
||||
IVisualNovelEvent(VisualNovelManager *manager);
|
||||
|
||||
template<class T>
|
||||
T * then(T *next) {
|
||||
assertNotNull(next);
|
||||
this->doNext = next;
|
||||
next->previous = this;
|
||||
return next;
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,6 @@ void VisualNovelTextbox::show() {
|
||||
if(this->isVisible()) return;
|
||||
this->visible = true;
|
||||
this->addChild(&this->selfParent);
|
||||
std::cout << "Showing" << std::endl;
|
||||
}
|
||||
|
||||
void VisualNovelTextbox::hide() {
|
||||
@ -114,13 +113,13 @@ void VisualNovelTextbox::textboxOnSceneUpdate() {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lastTimeCharacter = (int32_t)mathFloorFloat(this->timeCharacter);
|
||||
auto lastTimeCharacter = mathFloor<int32_t>(this->timeCharacter);
|
||||
if(game->inputManager.isDown(INPUT_BIND_ACCEPT)) {
|
||||
this->timeCharacter += game->timeManager.delta * VISUAL_NOVEL_TEXTBOX_SPEED_FASTER;
|
||||
} else {
|
||||
this->timeCharacter += game->timeManager.delta * VISUAL_NOVEL_TEXTBOX_SPEED;
|
||||
}
|
||||
auto newTimeCharacter = (int32_t)mathFloorFloat(this->timeCharacter);
|
||||
auto newTimeCharacter = mathFloor<int32_t>(this->timeCharacter);
|
||||
if(newTimeCharacter == lastTimeCharacter) return;
|
||||
|
||||
this->label.quadCount = newTimeCharacter;
|
||||
@ -187,7 +186,7 @@ bool_t VisualNovelTextbox::hasRevealedAllCurrentCharacters() {
|
||||
) {
|
||||
quadsTotal += this->label.measure.getQuadsOnLine(i);
|
||||
}
|
||||
return mathFloorFloat(this->timeCharacter) >= quadsTotal;
|
||||
return mathFloor<int32_t>(this->timeCharacter) >= quadsTotal;
|
||||
}
|
||||
|
||||
bool_t VisualNovelTextbox::hasRevealedAllCharacters() {
|
||||
|
@ -10,6 +10,13 @@
|
||||
#include "ui/PokerGameTextbox.hpp"
|
||||
#include "visualnovel/VisualNovelManager.hpp"
|
||||
#include "visualnovel/events/VisualNovelTextboxEvent.hpp"
|
||||
#include "poker/PokerGame.hpp"
|
||||
#include "poker/visualnovel/PokerNewGameEvent.hpp"
|
||||
#include "poker/visualnovel/PokerNewRoundEvent.hpp"
|
||||
#include "poker/visualnovel/PokerTakeBlindsEvent.hpp"
|
||||
#include "poker/visualnovel/PokerDealEvent.hpp"
|
||||
#include "poker/visualnovel/PokerTurnEvent.hpp"
|
||||
#include "poker/visualnovel/PokerDetermineBetterEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class TestScene {
|
||||
@ -26,12 +33,44 @@ namespace Dawn {
|
||||
auto textbox = PokerGameTextbox::create(canvas);
|
||||
|
||||
// VN Manager
|
||||
auto item = scene->createSceneItem();
|
||||
auto vnManager = item->addComponent<VisualNovelManager>();
|
||||
auto vnManagerItem = scene->createSceneItem();
|
||||
auto vnManager = vnManagerItem->addComponent<VisualNovelManager>();
|
||||
|
||||
vnManager
|
||||
->setEvent(new VisualNovelTextboxEvent(vnManager, "Bruh event"))
|
||||
->then(new VisualNovelTextboxEvent(vnManager, "Bruh event 2"))
|
||||
// Poker Test
|
||||
auto pokerGameItem = scene->createSceneItem();
|
||||
auto pokerGame = pokerGameItem->addComponent<PokerGame>();
|
||||
|
||||
for(int32_t i = 0; i < 4; i++) {
|
||||
auto pokerPlayerInstance = scene->createSceneItem();
|
||||
auto pokerPlayer = pokerPlayerInstance->addComponent<PokerPlayer>();
|
||||
}
|
||||
|
||||
auto betting = vnManager
|
||||
->setEvent(new VisualNovelTextboxEvent(vnManager, "Starting Game"))
|
||||
->then(new PokerNewGameEvent(vnManager))
|
||||
->then(new VisualNovelTextboxEvent(vnManager, "Game Started"))
|
||||
->then(new PokerNewRoundEvent(vnManager))
|
||||
->then(new VisualNovelTextboxEvent(vnManager, "Round Started"))
|
||||
->then(new PokerTakeBlindsEvent(vnManager))
|
||||
->then(new VisualNovelTextboxEvent(vnManager, "Blinds Taken"))
|
||||
->then(new PokerDealEvent(vnManager))
|
||||
->then(new VisualNovelTextboxEvent(vnManager, "Cards Dealt"))
|
||||
->then(new PokerDetermineBetterEvent(vnManager))
|
||||
;
|
||||
betting
|
||||
->whenEveryoneFolded(new VisualNovelTextboxEvent(vnManager, "Everyone Folded"))
|
||||
;
|
||||
betting
|
||||
->whenBettingFinished(new VisualNovelTextboxEvent(vnManager, "Betting Finished"))
|
||||
;
|
||||
betting
|
||||
->whenTurn(new VisualNovelTextboxEvent(vnManager, "Turn Time"))
|
||||
;
|
||||
betting
|
||||
->whenAiBet(new VisualNovelTextboxEvent(vnManager, "AI Bet"))
|
||||
;
|
||||
betting
|
||||
->whenHumanBet(new VisualNovelTextboxEvent(vnManager, "Human Bet"))
|
||||
;
|
||||
|
||||
return scene;
|
||||
|
Reference in New Issue
Block a user