Poker
Source: src/poker.c · 222 lines · 43 functions.
Screen captures
Views of this part running on the Mini Arcade.

Module entry points
These functions are exposed to the rest of the project. Open one to follow its decisions and the helpers it calls.
How to read these diagrams
Each function has its own expandable diagram using the actual expressions and statements from this file. Decisions split into True and False; loop bodies are indented. Returns end the function immediately; break and continue follow their C meanings. Arrows between statements show their order when execution reaches them.
These are structural source diagrams before preprocessing, not runtime traces. Conditional compilation and macros remain source expressions. Ternary choices remain inside their statement. Calls are linked separately; callback execution and task scheduling are not inferred.
Functions in this file
currentBet() · source line 43
static uint32_t currentBet(void)
- Exit this function
return player_bet > cpu_bet ? player_bet : cpu_bet;
Read original function source
static uint32_t currentBet(void) { return player_bet > cpu_bet ? player_bet : cpu_bet; }compareRanks() · source line 44
static int8_t compareRanks(hand_rank_t a, hand_rank_t b)
- Decision
a.value != b.valueTrue- Exit this function
return a.value > b.value ? 1 : -1;
FalseContinue after this decision.
- FOR loop
uint8_t i = 0; i < 5U; ++iRepeat body while the loop condition permits; then continue below.
- Decision
a.tie[i] != b.tie[i]True- Exit this function
return a.tie[i] > b.tie[i] ? 1 : -1;
FalseContinue after this decision.
- Exit this function
return 0;
Read original function source
static int8_t compareRanks(hand_rank_t a, hand_rank_t b) {
if (a.value != b.value) return a.value > b.value ? 1 : -1;
for (uint8_t i = 0; i < 5U; ++i) if (a.tie[i] != b.tie[i]) return a.tie[i] > b.tie[i] ? 1 : -1;
return 0;
}straightHigh() · source line 49
static uint8_t straightHigh(const uint8_t count[15])
- FOR loop
int high = 14; high >= 6; --highRepeat body while the loop condition permits; then continue below.
- Decision
count[high] && count[high-1] && count[high-2] && count[high-3] && count[high-4]True- Exit this function
return (uint8_t)high;
FalseContinue after this decision.
- Exit this function
return count[14] && count[2] && count[3] && count[4] && count[5] ? 5U : 0U;
Read original function source
static uint8_t straightHigh(const uint8_t count[15]) {
for (int high = 14; high >= 6; --high) if (count[high] && count[high-1] && count[high-2] && count[high-3] && count[high-4]) return (uint8_t)high;
return count[14] && count[2] && count[3] && count[4] && count[5] ? 5U : 0U;
}evaluateFive() · source line 53
static hand_rank_t evaluateFive(const card_t cards[5])
Calls into this documentation:
- Execute
hand_rank_t result = { .value = HAND_HIGH, .tie = {0} }; - Execute
uint8_t count[15] = {0}; - Execute
bool flush = true; - FOR loop
uint8_t i = 0; i < 5U; ++iRepeat body while the loop condition permits; then continue below.
- Execute
++count[cards[i].rank]; - Decision
i && cards[i].suit != cards[0].suitTrue- Execute
flush = false;
FalseContinue after this decision.
- Execute
const uint8_t straight = straightHigh(count); - Decision
flush && straightTrue- Execute
result.value = HAND_STRAIGHT_FLUSH; - Execute
result.tie[0] = straight; - Exit this function
return result;
FalseContinue after this decision.
- FOR loop
int rank = 14; rank >= 2; --rankRepeat body while the loop condition permits; then continue below.
- Decision
count[rank] == 4UTrue- Execute
result.value = HAND_QUADS; - Execute
result.tie[0] = (uint8_t)rank; - FOR loop
int k=14;k>=2;--kRepeat body while the loop condition permits; then continue below.
- Decision
count[k]==1UTrue- Execute
result.tie[1]=(uint8_t)k; - Exit enclosing loop or switch
break;
FalseContinue after this decision.
- Exit this function
return result;
FalseContinue after this decision.
- Execute
uint8_t three = 0, pair = 0; - FOR loop
int rank=14; rank>=2; --rankRepeat body while the loop condition permits; then continue below.
- Decision
!three && count[rank] == 3UTrue- Execute
three=(uint8_t)rank;
False- Decision
!pair && count[rank] == 2UTrue- Execute
pair=(uint8_t)rank;
FalseContinue after this decision.
- Decision
three && pairTrue- Execute
result.value=HAND_FULL_HOUSE; - Execute
result.tie[0]=three; - Execute
result.tie[1]=pair; - Exit this function
return result;
FalseContinue after this decision.
- Decision
flushTrue- Execute
result.value=HAND_FLUSH; - Execute
uint8_t n=0; - FOR loop
int rank=14;rank>=2;--rankRepeat body while the loop condition permits; then continue below.
- FOR loop
uint8_t j=0;j<count[rank];++jRepeat body while the loop condition permits; then continue below.
- Execute
result.tie[n++]=(uint8_t)rank;
- Exit this function
return result;
FalseContinue after this decision.
- Decision
straightTrue- Execute
result.value=HAND_STRAIGHT; - Execute
result.tie[0]=straight; - Exit this function
return result;
FalseContinue after this decision.
- Decision
threeTrue- Execute
result.value=HAND_TRIPS; - Execute
result.tie[0]=three; - Execute
uint8_t n=1; - FOR loop
int rank=14;rank>=2;--rankRepeat body while the loop condition permits; then continue below.
- Decision
count[rank]==1UTrue- Execute
result.tie[n++]=(uint8_t)rank;
FalseContinue after this decision.
- Exit this function
return result;
FalseContinue after this decision.
- Execute
uint8_t high_pair=0, low_pair=0; - FOR loop
int rank=14;rank>=2;--rankRepeat body while the loop condition permits; then continue below.
- Decision
count[rank]==2UTrue- Decision
!high_pairTrue- Execute
high_pair=(uint8_t)rank;
False- Execute
low_pair=(uint8_t)rank;
FalseContinue after this decision.
- Decision
high_pair && low_pairTrue- Execute
result.value=HAND_TWO_PAIR; - Execute
result.tie[0]=high_pair; - Execute
result.tie[1]=low_pair; - FOR loop
int rank=14;rank>=2;--rankRepeat body while the loop condition permits; then continue below.
- Decision
count[rank]==1UTrue- Execute
result.tie[2]=(uint8_t)rank; - Exit enclosing loop or switch
break;
FalseContinue after this decision.
- Exit this function
return result;
FalseContinue after this decision.
- Decision
high_pairTrue- Execute
result.value=HAND_PAIR; - Execute
result.tie[0]=high_pair; - Execute
uint8_t n=1; - FOR loop
int rank=14;rank>=2;--rankRepeat body while the loop condition permits; then continue below.
- Decision
count[rank]==1UTrue- Execute
result.tie[n++]=(uint8_t)rank;
FalseContinue after this decision.
- Exit this function
return result;
FalseContinue after this decision.
- Execute
uint8_t n=0; - FOR loop
int rank=14;rank>=2;--rankRepeat body while the loop condition permits; then continue below.
- Decision
count[rank]True- Execute
result.tie[n++]=(uint8_t)rank;
FalseContinue after this decision.
- Exit this function
return result;
Read original function source
static hand_rank_t evaluateFive(const card_t cards[5]) {
hand_rank_t result = { .value = HAND_HIGH, .tie = {0} }; uint8_t count[15] = {0}; bool flush = true;
for (uint8_t i = 0; i < 5U; ++i) { ++count[cards[i].rank]; if (i && cards[i].suit != cards[0].suit) flush = false; }
const uint8_t straight = straightHigh(count);
if (flush && straight) { result.value = HAND_STRAIGHT_FLUSH; result.tie[0] = straight; return result; }
for (int rank = 14; rank >= 2; --rank) if (count[rank] == 4U) { result.value = HAND_QUADS; result.tie[0] = (uint8_t)rank; for (int k=14;k>=2;--k) if (count[k]==1U) { result.tie[1]=(uint8_t)k; break; } return result; }
uint8_t three = 0, pair = 0;
for (int rank=14; rank>=2; --rank) { if (!three && count[rank] == 3U) three=(uint8_t)rank; else if (!pair && count[rank] == 2U) pair=(uint8_t)rank; }
if (three && pair) { result.value=HAND_FULL_HOUSE; result.tie[0]=three; result.tie[1]=pair; return result; }
if (flush) { result.value=HAND_FLUSH; uint8_t n=0; for(int rank=14;rank>=2;--rank) for(uint8_t j=0;j<count[rank];++j) result.tie[n++]=(uint8_t)rank; return result; }
if (straight) { result.value=HAND_STRAIGHT; result.tie[0]=straight; return result; }
if (three) { result.value=HAND_TRIPS; result.tie[0]=three; uint8_t n=1; for(int rank=14;rank>=2;--rank) if(count[rank]==1U) result.tie[n++]=(uint8_t)rank; return result; }
uint8_t high_pair=0, low_pair=0;
for(int rank=14;rank>=2;--rank) if(count[rank]==2U) { if(!high_pair) high_pair=(uint8_t)rank; else low_pair=(uint8_t)rank; }
if(high_pair && low_pair) { result.value=HAND_TWO_PAIR; result.tie[0]=high_pair; result.tie[1]=low_pair; for(int rank=14;rank>=2;--rank) if(count[rank]==1U) { result.tie[2]=(uint8_t)rank; break; } return result; }
if(high_pair) { result.value=HAND_PAIR; result.tie[0]=high_pair; uint8_t n=1; for(int rank=14;rank>=2;--rank) if(count[rank]==1U) result.tie[n++]=(uint8_t)rank; return result; }
uint8_t n=0; for(int rank=14;rank>=2;--rank) if(count[rank]) result.tie[n++]=(uint8_t)rank; return result;
}evaluateBest() · source line 71
static hand_rank_t evaluateBest(const card_t *cards, uint8_t count)
Calls into this documentation:
- Execute
hand_rank_t best = {0}; - Execute
bool first = true; - FOR loop
uint8_t a=0;a<count-4U;++aRepeat body while the loop condition permits; then continue below.
- FOR loop
uint8_t b=a+1;b<count-3U;++bRepeat body while the loop condition permits; then continue below.
- FOR loop
uint8_t c=b+1;c<count-2U;++cRepeat body while the loop condition permits; then continue below.
- FOR loop
uint8_t d=c+1;d<count-1U;++dRepeat body while the loop condition permits; then continue below.
- FOR loop
uint8_t e=d+1;e<count;++eRepeat body while the loop condition permits; then continue below.
- Execute
const card_t five[5]={cards[a],cards[b],cards[c],cards[d],cards[e]}; - Execute
hand_rank_t candidate=evaluateFive(five); - Decision
first || compareRanks(candidate,best)>0True- Execute
best=candidate; - Execute
first=false;
FalseContinue after this decision.
- Exit this function
return best;
Read original function source
static hand_rank_t evaluateBest(const card_t *cards, uint8_t count) {
hand_rank_t best = {0}; bool first = true;
for(uint8_t a=0;a<count-4U;++a) for(uint8_t b=a+1;b<count-3U;++b) for(uint8_t c=b+1;c<count-2U;++c) for(uint8_t d=c+1;d<count-1U;++d) for(uint8_t e=d+1;e<count;++e) {
const card_t five[5]={cards[a],cards[b],cards[c],cards[d],cards[e]}; hand_rank_t candidate=evaluateFive(five);
if(first || compareRanks(candidate,best)>0) { best=candidate; first=false; }
}
return best;
}handName() · source line 79
static const char *handName(hand_value_t value)
- Execute
static const char *names[] = { "HIGH CARD", "ONE PAIR", "TWO PAIR", "THREE KIND", "STRAIGHT", "FLUSH", "FULL HOUSE", "FOUR KIND", "STRAIGHT FLUSH" }; - Exit this function
return names[value];
Read original function source
static const char *handName(hand_value_t value) {
static const char *names[] = { "HIGH CARD", "ONE PAIR", "TWO PAIR", "THREE KIND", "STRAIGHT", "FLUSH", "FULL HOUSE", "FOUR KIND", "STRAIGHT FLUSH" };
return names[value];
}shuffleDeck() · source line 83
static void shuffleDeck(void)
- Execute
static const char suits[] = { 'C', 'D', 'H', 'S' }; - Execute
uint8_t n=0; - FOR loop
uint8_t s=0;s<4U;++sRepeat body while the loop condition permits; then continue below.
- FOR loop
uint8_t rank=2U;rank<=14U;++rankRepeat body while the loop condition permits; then continue below.
- Execute
deck[n++]=(card_t){rank,suits[s]};
- FOR loop
int i=DECK_SIZE-1;i>0;--iRepeat body while the loop condition permits; then continue below.
- Execute
const uint8_t j=esp_random()%(uint32_t)(i+1); - Execute
const card_t card=deck[i]; - Execute
deck[i]=deck[j]; - Execute
deck[j]=card;
- Execute
deck_position=0;
Read original function source
static void shuffleDeck(void) {
static const char suits[] = { 'C', 'D', 'H', 'S' }; uint8_t n=0;
for(uint8_t s=0;s<4U;++s) for(uint8_t rank=2U;rank<=14U;++rank) deck[n++]=(card_t){rank,suits[s]};
for(int i=DECK_SIZE-1;i>0;--i) { const uint8_t j=esp_random()%(uint32_t)(i+1); const card_t card=deck[i]; deck[i]=deck[j]; deck[j]=card; }
deck_position=0;
}deal() · source line 89
static bool deal(card_t *card)
- Decision
deck_position>=DECK_SIZETrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
*card=deck[deck_position++]; - Exit this function
return true;
Read original function source
static bool deal(card_t *card) { if(deck_position>=DECK_SIZE) return false; *card=deck[deck_position++]; return true; }dealHoleCards() · source line 90
static void dealHoleCards(void)
Calls into this documentation:
- Decision
player_dealerTrue- Execute
deal(&player_cards[0]); - Execute
deal(&cpu_cards[0]); - Execute
deal(&player_cards[1]); - Execute
deal(&cpu_cards[1]);
False- Execute
deal(&cpu_cards[0]); - Execute
deal(&player_cards[0]); - Execute
deal(&cpu_cards[1]); - Execute
deal(&player_cards[1]);
- Execute
audioPlay(AUDIO_SFX_CARD_DEAL);
Read original function source
static void dealHoleCards(void) { if(player_dealer) { deal(&player_cards[0]); deal(&cpu_cards[0]); deal(&player_cards[1]); deal(&cpu_cards[1]); } else { deal(&cpu_cards[0]); deal(&player_cards[0]); deal(&cpu_cards[1]); deal(&player_cards[1]); } audioPlay(AUDIO_SFX_CARD_DEAL); }remainingRaisePotRoom() · source line 91
static uint32_t remainingRaisePotRoom(void)
- Exit this function
return pot < POKER_RAISE_POT_LIMIT ? POKER_RAISE_POT_LIMIT-pot : 0U;
Read original function source
static uint32_t remainingRaisePotRoom(void) { return pot < POKER_RAISE_POT_LIMIT ? POKER_RAISE_POT_LIMIT-pot : 0U; }commitPlayer() · source line 92
static bool commitPlayer(uint32_t amount)
Calls into this documentation:
- Decision
amount > getGold() || !spendGold(amount)True- Exit this function
return false;
FalseContinue after this decision.
- Execute
player_bet+=amount; - Execute
player_committed+=amount; - Execute
pot+=amount; - Exit this function
return true;
Read original function source
static bool commitPlayer(uint32_t amount) { if(amount > getGold() || !spendGold(amount)) return false; player_bet+=amount; player_committed+=amount; pot+=amount; return true; }commitCpu() · source line 93
static void commitCpu(uint32_t amount)
- Decision
amount>cpu_stackTrue- Execute
amount=cpu_stack;
FalseContinue after this decision.
- Execute
cpu_stack-=amount; - Execute
cpu_bet+=amount; - Execute
pot+=amount;
Read original function source
static void commitCpu(uint32_t amount) { if(amount>cpu_stack) amount=cpu_stack; cpu_stack-=amount; cpu_bet+=amount; pot+=amount; }minimumRaise() · source line 94
static uint32_t minimumRaise(void)
Calls into this documentation:
- Execute
const uint32_t maximum=player_bet+getGold(), full=currentBet()+last_raise; - Decision
maximum<=currentBet()True- Exit this function
return 0U;
FalseContinue after this decision.
- Execute
const uint32_t target=maximum<full?maximum:full; - Exit this function
return target-player_bet>remainingRaisePotRoom()?0U:target;
Read original function source
static uint32_t minimumRaise(void) { const uint32_t maximum=player_bet+getGold(), full=currentBet()+last_raise; if(maximum<=currentBet()) return 0U; const uint32_t target=maximum<full?maximum:full; return target-player_bet>remainingRaisePotRoom()?0U:target; }holeStrength() · source line 95
static uint8_t holeStrength(const card_t cards[2])
- Execute
const uint8_t high=cards[0].rank>cards[1].rank?cards[0].rank:cards[1].rank, low=cards[0].rank<cards[1].rank?cards[0].rank:cards[1].rank; - Decision
high==lowTrue- Exit this function
return (uint8_t)(55U+high*3U);
FalseContinue after this decision.
- Execute
uint8_t strength=(uint8_t)(high*3U+low); - Decision
cards[0].suit==cards[1].suitTrue- Execute
strength+=8U;
FalseContinue after this decision.
- Execute
const uint8_t gap=high-low; - Decision
gap==1UTrue- Execute
strength+=6U;
False- Decision
gap==2UTrue- Execute
strength+=3U;
FalseContinue after this decision.
- Decision
high==14UTrue- Execute
strength+=8U;
FalseContinue after this decision.
- Exit this function
return strength>100U?100U:strength;
Read original function source
static uint8_t holeStrength(const card_t cards[2]) { const uint8_t high=cards[0].rank>cards[1].rank?cards[0].rank:cards[1].rank, low=cards[0].rank<cards[1].rank?cards[0].rank:cards[1].rank; if(high==low) return (uint8_t)(55U+high*3U); uint8_t strength=(uint8_t)(high*3U+low); if(cards[0].suit==cards[1].suit) strength+=8U; const uint8_t gap=high-low; if(gap==1U) strength+=6U; else if(gap==2U) strength+=3U; if(high==14U) strength+=8U; return strength>100U?100U:strength; }postFlopStrength() · source line 96
static uint8_t postFlopStrength(const card_t cards[2])
Calls into this documentation:
- Execute
card_t seven[7]={cards[0],cards[1]}; - FOR loop
uint8_t i=0;i<community_count;++iRepeat body while the loop condition permits; then continue below.
- Execute
seven[i+2U]=community_cards[i];
- Execute
const hand_rank_t rank=evaluateBest(seven,(uint8_t)(community_count+2U)); - Execute
static const uint8_t values[]={15,40,62,72,80,84,90,96,100}; - Exit this function
return (uint8_t)(values[rank.value]+(rank.value==HAND_PAIR||rank.value==HAND_HIGH?rank.tie[0]:0U));
Read original function source
static uint8_t postFlopStrength(const card_t cards[2]) { card_t seven[7]={cards[0],cards[1]}; for(uint8_t i=0;i<community_count;++i) seven[i+2U]=community_cards[i]; const hand_rank_t rank=evaluateBest(seven,(uint8_t)(community_count+2U)); static const uint8_t values[]={15,40,62,72,80,84,90,96,100}; return (uint8_t)(values[rank.value]+(rank.value==HAND_PAIR||rank.value==HAND_HIGH?rank.tie[0]:0U)); }strength() · source line 97
static uint8_t strength(const card_t cards[2])
Calls into this documentation:
- Exit this function
return street==STREET_PREFLOP?holeStrength(cards):postFlopStrength(cards);
Read original function source
static uint8_t strength(const card_t cards[2]) { return street==STREET_PREFLOP?holeStrength(cards):postFlopStrength(cards); }setStatus() · source line 98
static void setStatus(const char *text)
- Execute
snprintf(status_text,sizeof(status_text),"%s",text); - Execute
redraw_needed=true;
Read original function source
static void setStatus(const char *text) { snprintf(status_text,sizeof(status_text),"%s",text); redraw_needed=true; }dealFlop() · source line 99
static void dealFlop(void)
Calls into this documentation:
- Execute
card_t burn; - Execute
deal(&burn); - FOR loop
uint8_t i=0;i<3U;++iRepeat body while the loop condition permits; then continue below.
- Execute
deal(&community_cards[i]);
- Execute
community_count=3U; - Execute
street=STREET_FLOP; - Execute
audioPlay(AUDIO_SFX_CARD_DEAL);
Read original function source
static void dealFlop(void) { card_t burn; deal(&burn); for(uint8_t i=0;i<3U;++i) deal(&community_cards[i]); community_count=3U; street=STREET_FLOP; audioPlay(AUDIO_SFX_CARD_DEAL); }dealTurn() · source line 100
static void dealTurn(void)
Calls into this documentation:
- Execute
card_t burn; - Execute
deal(&burn); - Execute
deal(&community_cards[3]); - Execute
community_count=4U; - Execute
street=STREET_TURN; - Execute
audioPlay(AUDIO_SFX_CARD_DEAL);
Read original function source
static void dealTurn(void) { card_t burn; deal(&burn); deal(&community_cards[3]); community_count=4U; street=STREET_TURN; audioPlay(AUDIO_SFX_CARD_DEAL); }dealRiver() · source line 101
static void dealRiver(void)
Calls into this documentation:
- Execute
card_t burn; - Execute
deal(&burn); - Execute
deal(&community_cards[4]); - Execute
community_count=5U; - Execute
street=STREET_RIVER; - Execute
audioPlay(AUDIO_SFX_CARD_DEAL);
Read original function source
static void dealRiver(void) { card_t burn; deal(&burn); deal(&community_cards[4]); community_count=5U; street=STREET_RIVER; audioPlay(AUDIO_SFX_CARD_DEAL); }startAutoRestart() · source line 102
static void startAutoRestart(uint32_t now, uint32_t delay)
- Decision
auto_modeTrue- Execute
auto_restart_started=now; - Execute
auto_restart_delay=delay; - Execute
auto_seconds=(uint8_t)((delay+999U)/1000U);
FalseContinue after this decision.
Read original function source
static void startAutoRestart(uint32_t now, uint32_t delay) { if(auto_mode) { auto_restart_started=now; auto_restart_delay=delay; auto_seconds=(uint8_t)((delay+999U)/1000U); } }awardPot() · source line 103
static bool awardPot(void)
Calls into this documentation:
- Decision
player_committed && !addGold(player_committed)True- Exit this function
return false;
FalseContinue after this decision.
- Execute
const uint32_t profit=pot-player_committed; - Exit this function
return !profit || (auto_mode?addAIGold(profit):addUserGoldWon(profit));
Read original function source
static bool awardPot(void) { if(player_committed && !addGold(player_committed)) return false; const uint32_t profit=pot-player_committed; return !profit || (auto_mode?addAIGold(profit):addUserGoldWon(profit)); }recordLoss() · source line 104
static bool recordLoss(void)
Calls into this documentation:
- Exit this function
return auto_mode?recordAIGoldLost(player_committed):recordUserGoldLost(player_committed);
Read original function source
static bool recordLoss(void) { return auto_mode?recordAIGoldLost(player_committed):recordUserGoldLost(player_committed); }finishFold() · source line 105
static void finishFold(bool player_won, uint32_t now)
Calls into this documentation:
- Execute
audioPlay(player_won ? AUDIO_SFX_WAVE_CLEAR : AUDIO_SFX_GAME_OVER); - Execute
hand_active=false; - Execute
state=POKER_FINISHED; - Execute
reveal_cpu=false; - Execute
setStatus(player_won?(awardPot()?"CPU FOLDS":"GOLD ERROR"):(recordLoss()?"YOU FOLD":"GOLD ERROR")); - Execute
startAutoRestart(now,auto_mode&&!player_won&&street==STREET_PREFLOP?AUTO_PREFLOP_FOLD_DELAY_MS:aiRestartDelay());
Read original function source
static void finishFold(bool player_won, uint32_t now) { audioPlay(player_won ? AUDIO_SFX_WAVE_CLEAR : AUDIO_SFX_GAME_OVER); hand_active=false; state=POKER_FINISHED; reveal_cpu=false; setStatus(player_won?(awardPot()?"CPU FOLDS":"GOLD ERROR"):(recordLoss()?"YOU FOLD":"GOLD ERROR")); startAutoRestart(now,auto_mode&&!player_won&&street==STREET_PREFLOP?AUTO_PREFLOP_FOLD_DELAY_MS:aiRestartDelay()); }finishShowdown() · source line 106
static void finishShowdown(uint32_t now)
Calls into this documentation:
- Execute
card_t player[7]={player_cards[0],player_cards[1],community_cards[0],community_cards[1],community_cards[2],community_cards[3],community_cards[4]}; - Execute
card_t cpu[7]={cpu_cards[0],cpu_cards[1],community_cards[0],community_cards[1],community_cards[2],community_cards[3],community_cards[4]}; - Execute
const hand_rank_t a=evaluateBest(player,7), b=evaluateBest(cpu,7); - Execute
snprintf(player_hand_text,sizeof(player_hand_text),"%s",handName(a.value)); - Execute
snprintf(cpu_hand_text,sizeof(cpu_hand_text),"%s",handName(b.value)); - Execute
reveal_cpu=true; - Execute
hand_active=false; - Execute
state=POKER_FINISHED; - Execute
const int8_t result=compareRanks(a,b); - Execute
audioPlay(result>0 ? AUDIO_SFX_WAVE_CLEAR : result<0 ? AUDIO_SFX_GAME_OVER : AUDIO_SFX_MENU_SELECT); - Decision
result>0True- Execute
setStatus(awardPot()?"YOU WIN":"GOLD ERROR");
False- Decision
result<0True- Execute
setStatus(recordLoss()?"CPU WINS":"GOLD ERROR");
False- Execute
addGold(player_committed); - Execute
setStatus("DRAW");
- Execute
startAutoRestart(now,aiRestartDelay());
Read original function source
static void finishShowdown(uint32_t now) { card_t player[7]={player_cards[0],player_cards[1],community_cards[0],community_cards[1],community_cards[2],community_cards[3],community_cards[4]}; card_t cpu[7]={cpu_cards[0],cpu_cards[1],community_cards[0],community_cards[1],community_cards[2],community_cards[3],community_cards[4]}; const hand_rank_t a=evaluateBest(player,7), b=evaluateBest(cpu,7); snprintf(player_hand_text,sizeof(player_hand_text),"%s",handName(a.value)); snprintf(cpu_hand_text,sizeof(cpu_hand_text),"%s",handName(b.value)); reveal_cpu=true; hand_active=false; state=POKER_FINISHED; const int8_t result=compareRanks(a,b); audioPlay(result>0 ? AUDIO_SFX_WAVE_CLEAR : result<0 ? AUDIO_SFX_GAME_OVER : AUDIO_SFX_MENU_SELECT); if(result>0) setStatus(awardPot()?"YOU WIN":"GOLD ERROR"); else if(result<0) setStatus(recordLoss()?"CPU WINS":"GOLD ERROR"); else { addGold(player_committed); setStatus("DRAW"); } startAutoRestart(now,aiRestartDelay()); }moveToPlayer() · source line 107
static void moveToPlayer(const char *message, uint32_t now)
Calls into this documentation:
- Execute
state=POKER_PLAYER; - Execute
selected_action=ACTION_CALL_CHECK; - Execute
setStatus(message); - Decision
auto_modeTrue- Execute
state_started=now;
FalseContinue after this decision.
Read original function source
static void moveToPlayer(const char *message, uint32_t now) { state=POKER_PLAYER; selected_action=ACTION_CALL_CHECK; setStatus(message); if(auto_mode) state_started=now; }moveToCpu() · source line 108
static void moveToCpu(uint32_t now)
Calls into this documentation:
- Execute
state=POKER_CPU; - Execute
setStatus("CPU THINK"); - Execute
state_started=now;
Read original function source
static void moveToCpu(uint32_t now) { state=POKER_CPU; setStatus("CPU THINK"); state_started=now; }startPostFlop() · source line 109
static void startPostFlop(const char *message, uint32_t now)
Calls into this documentation:
- Execute
player_bet=cpu_bet=0; - Execute
last_raise=BIG_BLIND; - Execute
player_acted=cpu_acted=false; - Decision
player_dealerTrue- Execute
moveToCpu(now);
False- Execute
moveToPlayer(message,now);
Read original function source
static void startPostFlop(const char *message, uint32_t now) { player_bet=cpu_bet=0; last_raise=BIG_BLIND; player_acted=cpu_acted=false; if(player_dealer) moveToCpu(now); else moveToPlayer(message,now); }startAllIn() · source line 110
static void startAllIn(uint32_t now)
Calls into this documentation:
- Execute
state=POKER_ALL_IN; - Execute
setStatus("ALL IN"); - Execute
state_started=now;
Read original function source
static void startAllIn(uint32_t now) { state=POKER_ALL_IN; setStatus("ALL IN"); state_started=now; }completeRound() · source line 111
static void completeRound(uint32_t now)
Calls into this documentation:
- Decision
!getGold()||!cpu_stackTrue- Decision
community_count<5UTrue- Execute
startAllIn(now);
False- Execute
finishShowdown(now);
- Exit this function
return;
FalseContinue after this decision.
- Decision
street==STREET_PREFLOPTrue- Execute
dealFlop(); - Execute
startPostFlop("FLOP",now);
False- Decision
street==STREET_FLOPTrue- Execute
dealTurn(); - Execute
startPostFlop("TURN",now);
False- Decision
street==STREET_TURNTrue- Execute
dealRiver(); - Execute
startPostFlop("RIVER",now);
False- Execute
finishShowdown(now);
Read original function source
static void completeRound(uint32_t now) { if(!getGold()||!cpu_stack) { if(community_count<5U) startAllIn(now); else finishShowdown(now); return; } if(street==STREET_PREFLOP) { dealFlop(); startPostFlop("FLOP",now); } else if(street==STREET_FLOP) { dealTurn(); startPostFlop("TURN",now); } else if(street==STREET_TURN) { dealRiver(); startPostFlop("RIVER",now); } else finishShowdown(now); }processAllIn() · source line 112
static void processAllIn(uint32_t now)
Calls into this documentation:
- Decision
community_count==0UTrue- Execute
dealFlop(); - Execute
setStatus("ALL IN FLOP");
False- Decision
community_count==3UTrue- Execute
dealTurn(); - Execute
setStatus("ALL IN TURN");
False- Decision
community_count==4UTrue- Execute
dealRiver(); - Execute
setStatus("ALL IN RIVER");
False- Execute
finishShowdown(now); - Exit this function
return;
- Execute
state_started=now;
Read original function source
static void processAllIn(uint32_t now) { if(community_count==0U) { dealFlop(); setStatus("ALL IN FLOP"); } else if(community_count==3U) { dealTurn(); setStatus("ALL IN TURN"); } else if(community_count==4U) { dealRiver(); setStatus("ALL IN RIVER"); } else { finishShowdown(now); return; } state_started=now; }shouldFold() · source line 113
static bool shouldFold(uint32_t call, uint8_t hand_strength)
- Exit this function
return call && hand_strength<35U && esp_random()%100U>=15U;
Read original function source
static bool shouldFold(uint32_t call, uint8_t hand_strength) { return call && hand_strength<35U && esp_random()%100U>=15U; }processCpu() · source line 114
static void processCpu(uint32_t now)
Calls into this documentation:
- Execute
const uint32_t call=player_bet>cpu_bet?player_bet-cpu_bet:0U; - Execute
const uint8_t value=strength(cpu_cards); - Decision
shouldFold(call,value)True- Execute
finishFold(true,now); - Exit this function
return;
FalseContinue after this decision.
- Execute
const uint32_t target=currentBet()+last_raise, maximum=cpu_bet+cpu_stack; - Execute
const bool can_raise=value>=GOLD_HAND_STRENGTH && target>currentBet() && maximum>=target && target-cpu_bet<=remainingRaisePotRoom(); - Decision
can_raiseTrue- Execute
const uint32_t previous=currentBet(); - Execute
commitCpu(target-cpu_bet); - Execute
last_raise=target-previous; - Execute
cpu_acted=true; - Execute
player_acted=false; - Execute
moveToPlayer("CPU RAISE",now); - Exit this function
return;
FalseContinue after this decision.
- Execute
commitCpu(call); - Execute
cpu_acted=true; - Decision
player_acted && player_bet==cpu_betTrue- Execute
completeRound(now);
False- Execute
moveToPlayer(call?"CPU CALL":"CPU CHECK",now);
Read original function source
static void processCpu(uint32_t now) { const uint32_t call=player_bet>cpu_bet?player_bet-cpu_bet:0U; const uint8_t value=strength(cpu_cards); if(shouldFold(call,value)) { finishFold(true,now); return; } const uint32_t target=currentBet()+last_raise, maximum=cpu_bet+cpu_stack; const bool can_raise=value>=GOLD_HAND_STRENGTH && target>currentBet() && maximum>=target && target-cpu_bet<=remainingRaisePotRoom(); if(can_raise) { const uint32_t previous=currentBet(); commitCpu(target-cpu_bet); last_raise=target-previous; cpu_acted=true; player_acted=false; moveToPlayer("CPU RAISE",now); return; } commitCpu(call); cpu_acted=true; if(player_acted && player_bet==cpu_bet) completeRound(now); else moveToPlayer(call?"CPU CALL":"CPU CHECK",now); }processAuto() · source line 115
static void processAuto(uint32_t now)
Calls into this documentation:
- Execute
const uint32_t call=cpu_bet>player_bet?cpu_bet-player_bet:0U; - Execute
const uint8_t value=strength(player_cards); - Decision
call>getGold()||shouldFold(call,value)True- Execute
finishFold(false,now); - Exit this function
return;
FalseContinue after this decision.
- Execute
const uint32_t target=minimumRaise(); - Decision
value>=GOLD_HAND_STRENGTH && target>currentBet()True- Execute
const uint32_t previous=currentBet(); - Decision
!commitPlayer(target-player_bet)True- Execute
finishFold(false,now); - Exit this function
return;
FalseContinue after this decision.
- Execute
last_raise=target-previous; - Execute
player_acted=true; - Execute
cpu_acted=false; - Execute
moveToCpu(now); - Exit this function
return;
FalseContinue after this decision.
- Decision
!commitPlayer(call)True- Execute
finishFold(false,now); - Exit this function
return;
FalseContinue after this decision.
- Execute
player_acted=true; - Decision
cpu_acted&&player_bet==cpu_betTrue- Execute
completeRound(now);
False- Execute
moveToCpu(now);
Read original function source
static void processAuto(uint32_t now) { const uint32_t call=cpu_bet>player_bet?cpu_bet-player_bet:0U; const uint8_t value=strength(player_cards); if(call>getGold()||shouldFold(call,value)) { finishFold(false,now); return; } const uint32_t target=minimumRaise(); if(value>=GOLD_HAND_STRENGTH && target>currentBet()) { const uint32_t previous=currentBet(); if(!commitPlayer(target-player_bet)) { finishFold(false,now); return; } last_raise=target-previous; player_acted=true; cpu_acted=false; moveToCpu(now); return; } if(!commitPlayer(call)) { finishFold(false,now); return; } player_acted=true; if(cpu_acted&&player_bet==cpu_bet) completeRound(now); else moveToCpu(now); }beginHand() · source line 116
static void beginHand(uint32_t now)
Calls into this documentation:
- Execute
pot=player_bet=cpu_bet=player_committed=community_count=0; - Execute
street=STREET_PREFLOP; - Execute
last_raise=BIG_BLIND; - Execute
selected_action=ACTION_CALL_CHECK; - Execute
player_acted=cpu_acted=reveal_cpu=false; - Execute
hand_active=false; - Execute
const uint32_t starting=getGold(); - Decision
!startingTrue- Execute
state=POKER_NO_GOLD; - Execute
setStatus("NEED GOLD"); - Exit this function
return;
FalseContinue after this decision.
- Execute
cpu_stack=starting; - Execute
shuffleDeck(); - Execute
dealHoleCards(); - Decision
player_dealerTrue- Execute
commitPlayer(starting<SMALL_BLIND?starting:SMALL_BLIND); - Execute
commitCpu(cpu_stack<BIG_BLIND?cpu_stack:BIG_BLIND); - Execute
state=POKER_PLAYER; - Execute
setStatus("PREFLOP"); - Decision
auto_modeTrue- Execute
state_started=now;
FalseContinue after this decision.
False- Execute
commitCpu(cpu_stack<SMALL_BLIND?cpu_stack:SMALL_BLIND); - Execute
commitPlayer(starting<BIG_BLIND?starting:BIG_BLIND); - Execute
moveToCpu(now);
- Execute
hand_active=true; - Execute
redraw_needed=true;
Read original function source
static void beginHand(uint32_t now) { pot=player_bet=cpu_bet=player_committed=community_count=0; street=STREET_PREFLOP; last_raise=BIG_BLIND; selected_action=ACTION_CALL_CHECK; player_acted=cpu_acted=reveal_cpu=false; hand_active=false; const uint32_t starting=getGold(); if(!starting) { state=POKER_NO_GOLD; setStatus("NEED GOLD"); return; } cpu_stack=starting; shuffleDeck(); dealHoleCards(); if(player_dealer) { commitPlayer(starting<SMALL_BLIND?starting:SMALL_BLIND); commitCpu(cpu_stack<BIG_BLIND?cpu_stack:BIG_BLIND); state=POKER_PLAYER; setStatus("PREFLOP"); if(auto_mode) state_started=now; } else { commitCpu(cpu_stack<SMALL_BLIND?cpu_stack:SMALL_BLIND); commitPlayer(starting<BIG_BLIND?starting:BIG_BLIND); moveToCpu(now); } hand_active=true; redraw_needed=true; }startPoker() · source line 117
void startPoker(uint32_t now_ms)
Calls into this documentation:
- Execute
running=true; - Execute
auto_mode=false; - Execute
ai_speed=AI_SPEED_DEFAULT_INDEX; - Execute
modeSelectionReset(&mode_input); - Execute
player_dealer=true; - Execute
state=POKER_MODE; - Execute
setStatus("SELECT MODE"); - Execute
state_started=now_ms; - Execute
redraw_needed=true;
Read original function source
void startPoker(uint32_t now_ms) { running=true; auto_mode=false; ai_speed=AI_SPEED_DEFAULT_INDEX; modeSelectionReset(&mode_input); player_dealer=true; state=POKER_MODE; setStatus("SELECT MODE"); state_started=now_ms; redraw_needed=true; }stopPoker() · source line 118
void stopPoker(void)
Calls into this documentation:
- Decision
hand_activeTrue- Execute
recordLoss(); - Execute
hand_active=false; - Execute
pot=0; - Execute
player_dealer=!player_dealer;
False- Decision
state==POKER_FINISHEDTrue- Execute
player_dealer=!player_dealer;
FalseContinue after this decision.
- Execute
running=false;
Read original function source
void stopPoker(void) { if(hand_active) { recordLoss(); hand_active=false; pot=0; player_dealer=!player_dealer; } else if(state==POKER_FINISHED) player_dealer=!player_dealer; running=false; }pokerAction() · source line 119
void pokerAction(bool action, bool cycle, bool speed, uint32_t now)
Calls into this documentation:
- Decision
!runningTrue- Exit this function
return;
FalseContinue after this decision.
- Decision
state==POKER_MODETrue- Decision
actionTrue- Execute
beginHand(now);
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
auto_modeTrue- Decision
speedTrue- Execute
cycleAISpeed(&ai_speed); - Execute
state_started=now; - Execute
redraw_needed=true;
FalseContinue after this decision.
- Decision
actionTrue- Decision
hand_activeTrue- Execute
recordLoss(); - Execute
hand_active=false; - Execute
pot=0;
FalseContinue after this decision.
- Execute
auto_mode=false; - Execute
modeSelectionReset(&mode_input); - Execute
state=POKER_MODE; - Execute
redraw_needed=true;
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
state==POKER_FINISHED && actionTrue- Execute
player_dealer=!player_dealer; - Execute
beginHand(now); - Exit this function
return;
FalseContinue after this decision.
- Decision
state==POKER_RAISETrue- Decision
cycleTrue- Execute
const uint32_t maximum=player_bet+getGold(), minimum=minimumRaise(); - Execute
selected_raise=selected_raise<maximum?selected_raise+1U:minimum; - Execute
redraw_needed=true;
FalseContinue after this decision.
- Decision
actionTrue- Execute
const uint32_t previous=currentBet(), amount=selected_raise-player_bet; - Decision
amount<=remainingRaisePotRoom()&&commitPlayer(amount)True- Execute
last_raise=selected_raise-previous; - Execute
player_acted=true; - Execute
cpu_acted=false; - Execute
moveToCpu(now);
FalseContinue after this decision.
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
state!=POKER_PLAYERTrue- Exit this function
return;
FalseContinue after this decision.
- Decision
cycleTrue- Execute
selected_action=(poker_action_t)((selected_action+1U)%ACTION_COUNT); - Execute
redraw_needed=true;
FalseContinue after this decision.
- Decision
!actionTrue- Exit this function
return;
FalseContinue after this decision.
- Decision
selected_action==ACTION_FOLDTrue- Execute
finishFold(false,now); - Exit this function
return;
FalseContinue after this decision.
- Decision
selected_action==ACTION_RAISETrue- Execute
selected_raise=minimumRaise(); - Decision
selected_raiseTrue- Execute
state=POKER_RAISE; - Execute
setStatus("RAISE TO");
False- Execute
setStatus("NO RAISE");
- Exit this function
return;
FalseContinue after this decision.
- Execute
const uint32_t call=cpu_bet>player_bet?cpu_bet-player_bet:0U; - Decision
!commitPlayer(call)True- Exit this function
return;
FalseContinue after this decision.
- Execute
player_acted=true; - Decision
cpu_acted&&player_bet==cpu_betTrue- Execute
completeRound(now);
False- Execute
moveToCpu(now);
Read original function source
void pokerAction(bool action, bool cycle, bool speed, uint32_t now) {
if(!running) return;
if(state==POKER_MODE) { if(action) beginHand(now); return; }
if(auto_mode) { if(speed) { cycleAISpeed(&ai_speed); state_started=now; redraw_needed=true; } if(action) { if(hand_active) { recordLoss(); hand_active=false; pot=0; } auto_mode=false; modeSelectionReset(&mode_input); state=POKER_MODE; redraw_needed=true; } return; }
if(state==POKER_FINISHED && action) { player_dealer=!player_dealer; beginHand(now); return; }
if(state==POKER_RAISE) { if(cycle) { const uint32_t maximum=player_bet+getGold(), minimum=minimumRaise(); selected_raise=selected_raise<maximum?selected_raise+1U:minimum; redraw_needed=true; } if(action) { const uint32_t previous=currentBet(), amount=selected_raise-player_bet; if(amount<=remainingRaisePotRoom()&&commitPlayer(amount)) { last_raise=selected_raise-previous; player_acted=true; cpu_acted=false; moveToCpu(now); } } return; }
if(state!=POKER_PLAYER) return;
if(cycle) { selected_action=(poker_action_t)((selected_action+1U)%ACTION_COUNT); redraw_needed=true; }
if(!action) return;
if(selected_action==ACTION_FOLD) { finishFold(false,now); return; }
if(selected_action==ACTION_RAISE) { selected_raise=minimumRaise(); if(selected_raise) { state=POKER_RAISE; setStatus("RAISE TO"); } else setStatus("NO RAISE"); return; }
const uint32_t call=cpu_bet>player_bet?cpu_bet-player_bet:0U; if(!commitPlayer(call)) return; player_acted=true; if(cpu_acted&&player_bet==cpu_bet) completeRound(now); else moveToCpu(now);
}updatePoker() · source line 132
void updatePoker(uint16_t *frame, int x_offset, int y_offset, bool joystick_valid, bool left, bool right, uint32_t now)
Calls into this documentation:
- Execute
(void)frame; - Decision
!runningTrue- Exit this function
return;
FalseContinue after this decision.
- Decision
state==POKER_MODETrue- Decision
modeSelectionNext(&mode_input,x_offset,y_offset,joystick_valid,left,right,now)True- Execute
auto_mode=!auto_mode; - Execute
redraw_needed=true;
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
state==POKER_FINISHED&&auto_modeTrue- Execute
const uint32_t elapsed=now-auto_restart_started; - Decision
elapsed>=auto_restart_delayTrue- Execute
player_dealer=!player_dealer; - Execute
beginHand(now); - Exit this function
return;
FalseContinue after this decision.
- Execute
const uint8_t seconds=(uint8_t)((auto_restart_delay-elapsed+999U)/1000U); - Decision
seconds!=auto_secondsTrue- Execute
auto_seconds=seconds; - Execute
redraw_needed=true;
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
state==POKER_PLAYER&&auto_mode&&now-state_started>=aiSpeedDelay(ai_speed)True- Execute
processAuto(now); - Exit this function
return;
FalseContinue after this decision.
- Decision
state==POKER_CPU&&now-state_started>=(auto_mode?aiSpeedDelay(ai_speed):CPU_ACTION_DELAY_MS)True- Execute
processCpu(now); - Exit this function
return;
FalseContinue after this decision.
- Decision
state==POKER_ALL_IN&&now-state_started>=(auto_mode?aiSpeedDelay(ai_speed):ALL_IN_REVEAL_MS)True- Execute
processAllIn(now);
FalseContinue after this decision.
Read original function source
void updatePoker(uint16_t *frame, int x_offset, int y_offset, bool joystick_valid, bool left, bool right, uint32_t now) { (void)frame; if(!running) return; if(state==POKER_MODE) { if(modeSelectionNext(&mode_input,x_offset,y_offset,joystick_valid,left,right,now)) { auto_mode=!auto_mode; redraw_needed=true; } return; } if(state==POKER_FINISHED&&auto_mode) { const uint32_t elapsed=now-auto_restart_started; if(elapsed>=auto_restart_delay) { player_dealer=!player_dealer; beginHand(now); return; } const uint8_t seconds=(uint8_t)((auto_restart_delay-elapsed+999U)/1000U); if(seconds!=auto_seconds) { auto_seconds=seconds; redraw_needed=true; } return; } if(state==POKER_PLAYER&&auto_mode&&now-state_started>=aiSpeedDelay(ai_speed)) { processAuto(now); return; } if(state==POKER_CPU&&now-state_started>=(auto_mode?aiSpeedDelay(ai_speed):CPU_ACTION_DELAY_MS)) { processCpu(now); return; } if(state==POKER_ALL_IN&&now-state_started>=(auto_mode?aiSpeedDelay(ai_speed):ALL_IN_REVEAL_MS)) processAllIn(now); }cardPath() · source line 133
static void cardPath(const card_t *card, char *path, size_t size)
- Execute
const char *rank=card->rank==11U?"J":card->rank==12U?"Q":card->rank==13U?"K":card->rank==14U?"A":NULL; - Decision
rankTrue- Execute
snprintf(path,size,"/spiffs/cards/%s%c.jpg",rank,card->suit);
False- Execute
snprintf(path,size,"/spiffs/cards/%u%c.jpg",(unsigned)card->rank,card->suit);
Read original function source
static void cardPath(const card_t *card, char *path, size_t size) { const char *rank=card->rank==11U?"J":card->rank==12U?"Q":card->rank==13U?"K":card->rank==14U?"A":NULL; if(rank) snprintf(path,size,"/spiffs/cards/%s%c.jpg",rank,card->suit); else snprintf(path,size,"/spiffs/cards/%u%c.jpg",(unsigned)card->rank,card->suit); }drawCard() · source line 134
static void drawCard(uint16_t *frame,const card_t *card,int x,int y,unsigned scale)
Calls into this documentation:
- Execute
char path[32]; - Execute
cardPath(card,path,sizeof(path)); - Execute
const bool decoded=scale?imageDecodeJpegScaledAt(path,frame,(unsigned)x,(unsigned)y,scale):imageDecodeJpegAt(path,frame,(unsigned)x,(unsigned)y); - Decision
!decodedTrue- Execute
const int width=48>>scale,height=64>>scale; - Execute
fill_rect(frame,x,y,width,height,COLOR_WHITE); - Execute
draw_rect(frame,x,y,width,height,COLOR_RED); - Execute
draw_text_centred(frame,x+width/2,y+height/2-4,path+14,1,COLOR_BLACK);
FalseContinue after this decision.
Read original function source
static void drawCard(uint16_t *frame,const card_t *card,int x,int y,unsigned scale) { char path[32]; cardPath(card,path,sizeof(path)); const bool decoded=scale?imageDecodeJpegScaledAt(path,frame,(unsigned)x,(unsigned)y,scale):imageDecodeJpegAt(path,frame,(unsigned)x,(unsigned)y); if(!decoded) { const int width=48>>scale,height=64>>scale; fill_rect(frame,x,y,width,height,COLOR_WHITE); draw_rect(frame,x,y,width,height,COLOR_RED); draw_text_centred(frame,x+width/2,y+height/2-4,path+14,1,COLOR_BLACK); } }drawBack() · source line 135
static void drawBack(uint16_t *frame,int x,int y)
Calls into this documentation:
- Decision
!imageDecodeJpegAt("/spiffs/cards/Back.jpg",frame,(unsigned)x,(unsigned)y)True- Execute
fill_rect(frame,x,y,48,64,COLOR_BLUE); - Execute
draw_rect(frame,x,y,48,64,COLOR_WHITE);
FalseContinue after this decision.
Read original function source
static void drawBack(uint16_t *frame,int x,int y) { if(!imageDecodeJpegAt("/spiffs/cards/Back.jpg",frame,(unsigned)x,(unsigned)y)) { fill_rect(frame,x,y,48,64,COLOR_BLUE); draw_rect(frame,x,y,48,64,COLOR_WHITE); } }drawPoker() · source line 136
void drawPoker(uint16_t *frame)
Calls into this documentation:
- Decision
!running || !redraw_neededTrue- Exit this function
return;
FalseContinue after this decision.
- Execute
redraw_needed = false; - Execute
clear(frame, COLOR_BLACK); - Execute
char text[42]; - Decision
state == POKER_MODETrue- Execute
draw_text_centred(frame, 160, 12, "POKER", 4, COLOR_CYAN); - Execute
draw_text_centred(frame, 160, 42, "SELECT MODE", 1, COLOR_LIGHTGRAY); - Execute
draw_text_centred(frame, 100, 60, "PLAY", 2, auto_mode ? COLOR_LIGHTGRAY : COLOR_YELLOW); - Execute
draw_text_centred(frame, 220, 60, "AUTO", 2, auto_mode ? COLOR_YELLOW : COLOR_LIGHTGRAY); - Execute
draw_text_centred(frame, 160, 105, "D/B/STICK CHANGE A/K START", 1, COLOR_LIGHTGRAY); - Execute
draw_text_centred(frame, 160, 130, "BOOT EXIT", 1, COLOR_LIGHTGRAY); - Exit this function
return;
FalseContinue after this decision.
- Decision
state == POKER_NO_GOLDTrue- Execute
draw_text_centred(frame, 160, 18, "POKER", 4, COLOR_CYAN); - Execute
draw_text_centred(frame, 160, 72, "NO GOLD", 3, COLOR_RED); - Exit this function
return;
FalseContinue after this decision.
- Decision
reveal_cpuTrue- Execute
drawCard(frame, &cpu_cards[0], 112, 2, 0); - Execute
drawCard(frame, &cpu_cards[1], 164, 2, 0);
False- Execute
drawBack(frame, 112, 2); - Execute
drawBack(frame, 164, 2);
- FOR loop
uint8_t i = 0; i < 5U; ++iRepeat body while the loop condition permits; then continue below.
- Execute
const int x = 94 + (int)i * 27; - Decision
i < community_countTrue- Execute
drawCard(frame, &community_cards[i], x, 69, 1);
False- Execute
fill_rect(frame, x, 69, 24, 32, COLOR_BLACK); - Execute
draw_rect(frame, x, 69, 24, 32, COLOR_DARKGREY);
- Execute
drawCard(frame, &player_cards[0], 112, 104, 0); - Execute
drawCard(frame, &player_cards[1], 164, 104, 0); - Execute
draw_text(frame, 3, 4, "CPU", 1, COLOR_CYAN); - Decision
reveal_cpuTrue- Execute
draw_text(frame, 3, 18, cpu_hand_text, 1, COLOR_WHITE);
False- Execute
snprintf(text, sizeof(text), "B %u", (unsigned)cpu_bet); - Execute
draw_text(frame, 3, 18, text, 1, COLOR_WHITE);
- Execute
draw_text(frame, 3, 106, "YOU", 1, COLOR_GREEN); - Decision
reveal_cpuTrue- Execute
draw_text(frame, 3, 120, player_hand_text, 1, COLOR_WHITE);
False- Execute
snprintf(text, sizeof(text), "B %u", (unsigned)player_bet); - Execute
draw_text(frame, 3, 120, text, 1, COLOR_WHITE);
- Execute
draw_text(frame, 3, 48, status_text, 1, COLOR_CYAN); - Execute
const char *choice = state == POKER_RAISE ? "TO" : state == POKER_CPU ? "WAIT" : state == POKER_ALL_IN ? "ALL IN" : state == POKER_FINISHED ? (auto_mode ? "NEXT" : "DEAL") : (selected_action == ACTION_RAISE ? "RAISE" : selected_action == ACTION_FOLD ? "FOLD" : player_bet < currentBet() ? "CALL" : "CHECK"); - Decision
state == POKER_RAISETrue- Execute
snprintf(text, sizeof(text), "TO %u", (unsigned)selected_raise);
False- Decision
state == POKER_FINISHED && auto_modeTrue- Execute
snprintf(text, sizeof(text), "NEXT %u", (unsigned)auto_seconds);
False- Execute
snprintf(text, sizeof(text), "%s", choice);
- Execute
draw_text(frame, 3, 65, text, 1, COLOR_YELLOW); - Execute
drawGameGold(frame, 260, 4, 56, true); - Execute
snprintf(text, sizeof(text), "POT %u", (unsigned)pot); - Execute
draw_text(frame, 260, 46, text, 1, COLOR_ORANGE); - Execute
draw_text(frame, 260, 106, player_dealer ? "D YOU" : "D CPU", 1, COLOR_CYAN); - Execute
draw_text(frame, 260, 120, "BL 1/2", 1, COLOR_DARKGREY); - Decision
state == POKER_PLAYERTrue- Decision
auto_modeTrue- Execute
snprintf(text, sizeof(text), "AUTO E SPEED %s A STOP", aiSpeedShortText(ai_speed)); - Execute
draw_text_centred(frame, 160, 158, text, 1, COLOR_LIGHTGRAY);
False- Execute
draw_text_centred(frame, 160, 158, "C CHOOSE A/K SELECT", 1, COLOR_LIGHTGRAY);
False- Decision
state == POKER_FINISHEDTrue- Execute
draw_text_centred(frame, 160, 158, auto_mode ? "E SPEED A STOP" : "A/K DEAL", 1, COLOR_LIGHTGRAY);
FalseContinue after this decision.
Read original function source
void drawPoker(uint16_t *frame) {
if (!running || !redraw_needed)
return;
redraw_needed = false;
clear(frame, COLOR_BLACK);
char text[42];
if (state == POKER_MODE) {
draw_text_centred(frame, 160, 12, "POKER", 4, COLOR_CYAN);
draw_text_centred(frame, 160, 42, "SELECT MODE", 1, COLOR_LIGHTGRAY);
draw_text_centred(frame, 100, 60, "PLAY", 2, auto_mode ? COLOR_LIGHTGRAY : COLOR_YELLOW);
draw_text_centred(frame, 220, 60, "AUTO", 2, auto_mode ? COLOR_YELLOW : COLOR_LIGHTGRAY);
draw_text_centred(frame, 160, 105, "D/B/STICK CHANGE A/K START", 1,
COLOR_LIGHTGRAY);
draw_text_centred(frame, 160, 130, "BOOT EXIT", 1, COLOR_LIGHTGRAY);
return;
}
if (state == POKER_NO_GOLD) {
draw_text_centred(frame, 160, 18, "POKER", 4, COLOR_CYAN);
draw_text_centred(frame, 160, 72, "NO GOLD", 3, COLOR_RED);
return;
}
if (reveal_cpu) {
drawCard(frame, &cpu_cards[0], 112, 2, 0);
drawCard(frame, &cpu_cards[1], 164, 2, 0);
} else {
drawBack(frame, 112, 2);
drawBack(frame, 164, 2);
}
for (uint8_t i = 0; i < 5U; ++i) {
const int x = 94 + (int)i * 27;
if (i < community_count)
drawCard(frame, &community_cards[i], x, 69, 1);
else {
fill_rect(frame, x, 69, 24, 32, COLOR_BLACK);
draw_rect(frame, x, 69, 24, 32, COLOR_DARKGREY);
}
}
drawCard(frame, &player_cards[0], 112, 104, 0);
drawCard(frame, &player_cards[1], 164, 104, 0);
draw_text(frame, 3, 4, "CPU", 1, COLOR_CYAN);
if (reveal_cpu)
draw_text(frame, 3, 18, cpu_hand_text, 1, COLOR_WHITE);
else {
snprintf(text, sizeof(text), "B %u", (unsigned)cpu_bet);
draw_text(frame, 3, 18, text, 1, COLOR_WHITE);
}
draw_text(frame, 3, 106, "YOU", 1, COLOR_GREEN);
if (reveal_cpu)
draw_text(frame, 3, 120, player_hand_text, 1, COLOR_WHITE);
else {
snprintf(text, sizeof(text), "B %u", (unsigned)player_bet);
draw_text(frame, 3, 120, text, 1, COLOR_WHITE);
}
draw_text(frame, 3, 48, status_text, 1, COLOR_CYAN);
const char *choice = state == POKER_RAISE ? "TO"
: state == POKER_CPU ? "WAIT"
: state == POKER_ALL_IN ? "ALL IN"
: state == POKER_FINISHED
? (auto_mode ? "NEXT" : "DEAL")
: (selected_action == ACTION_RAISE ? "RAISE"
: selected_action == ACTION_FOLD ? "FOLD"
: player_bet < currentBet() ? "CALL"
: "CHECK");
if (state == POKER_RAISE)
snprintf(text, sizeof(text), "TO %u", (unsigned)selected_raise);
else if (state == POKER_FINISHED && auto_mode)
snprintf(text, sizeof(text), "NEXT %u", (unsigned)auto_seconds);
else
snprintf(text, sizeof(text), "%s", choice);
draw_text(frame, 3, 65, text, 1, COLOR_YELLOW);
drawGameGold(frame, 260, 4, 56, true);
snprintf(text, sizeof(text), "POT %u", (unsigned)pot);
draw_text(frame, 260, 46, text, 1, COLOR_ORANGE);
draw_text(frame, 260, 106, player_dealer ? "D YOU" : "D CPU", 1, COLOR_CYAN);
draw_text(frame, 260, 120, "BL 1/2", 1, COLOR_DARKGREY);
if (state == POKER_PLAYER) {
if (auto_mode) {
snprintf(text, sizeof(text), "AUTO E SPEED %s A STOP",
aiSpeedShortText(ai_speed));
draw_text_centred(frame, 160, 158, text, 1, COLOR_LIGHTGRAY);
} else {
draw_text_centred(frame, 160, 158, "C CHOOSE A/K SELECT", 1,
COLOR_LIGHTGRAY);
}
} else if (state == POKER_FINISHED)
draw_text_centred(frame, 160, 158,
auto_mode ? "E SPEED A STOP" : "A/K DEAL", 1,
COLOR_LIGHTGRAY);
}Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
// Heads-up Texas Hold'em. This module is intentionally unregistered until
// its menu and main-loop lifecycle routing are added in the next step.
#include "poker.h"
#include "ai_speed.h"
#include "audio.h"
#include "esp_random.h"
#include "game_graphics.h"
#include "PET2001_font.h"
#include "gold.h"
#include "image_decoder.h"
#include "mode_selection.h"
#include <stdio.h>
#include <string.h>
#define DECK_SIZE 52U
#define SMALL_BLIND 1U
#define BIG_BLIND 2U
#define CPU_ACTION_DELAY_MS 700U
#define ALL_IN_REVEAL_MS 700U
#define AUTO_PREFLOP_FOLD_DELAY_MS 1000U
#define GOLD_HAND_STRENGTH 75U
#define BLUFF_GOLD_PERCENT 25U
#define POKER_RAISE_POT_LIMIT 1000U
typedef enum { POKER_MODE, POKER_NO_GOLD, POKER_PLAYER, POKER_RAISE, POKER_CPU, POKER_ALL_IN, POKER_FINISHED } poker_state_t;
typedef enum { STREET_PREFLOP, STREET_FLOP, STREET_TURN, STREET_RIVER } poker_street_t;
typedef enum { ACTION_CALL_CHECK, ACTION_RAISE, ACTION_FOLD, ACTION_COUNT } poker_action_t;
typedef enum { HAND_HIGH, HAND_PAIR, HAND_TWO_PAIR, HAND_TRIPS, HAND_STRAIGHT, HAND_FLUSH, HAND_FULL_HOUSE, HAND_QUADS, HAND_STRAIGHT_FLUSH } hand_value_t;
typedef struct { uint8_t rank; char suit; } card_t;
typedef struct { hand_value_t value; uint8_t tie[5]; } hand_rank_t;
static card_t deck[DECK_SIZE], player_cards[2], cpu_cards[2], community_cards[5];
static uint8_t deck_position, community_count, ai_speed, auto_seconds;
static uint32_t pot, player_bet, cpu_bet, player_committed, cpu_stack, last_raise, selected_raise;
static uint32_t state_started, auto_restart_started, auto_restart_delay;
static poker_state_t state;
static poker_street_t street;
static poker_action_t selected_action;
static bool player_acted, cpu_acted, reveal_cpu, hand_active, player_dealer, auto_mode, running, redraw_needed;
static mode_selection_input_t mode_input;
static char status_text[20], player_hand_text[20], cpu_hand_text[20];
static uint32_t currentBet(void) { return player_bet > cpu_bet ? player_bet : cpu_bet; }
static int8_t compareRanks(hand_rank_t a, hand_rank_t b) {
if (a.value != b.value) return a.value > b.value ? 1 : -1;
for (uint8_t i = 0; i < 5U; ++i) if (a.tie[i] != b.tie[i]) return a.tie[i] > b.tie[i] ? 1 : -1;
return 0;
}
static uint8_t straightHigh(const uint8_t count[15]) {
for (int high = 14; high >= 6; --high) if (count[high] && count[high-1] && count[high-2] && count[high-3] && count[high-4]) return (uint8_t)high;
return count[14] && count[2] && count[3] && count[4] && count[5] ? 5U : 0U;
}
static hand_rank_t evaluateFive(const card_t cards[5]) {
hand_rank_t result = { .value = HAND_HIGH, .tie = {0} }; uint8_t count[15] = {0}; bool flush = true;
for (uint8_t i = 0; i < 5U; ++i) { ++count[cards[i].rank]; if (i && cards[i].suit != cards[0].suit) flush = false; }
const uint8_t straight = straightHigh(count);
if (flush && straight) { result.value = HAND_STRAIGHT_FLUSH; result.tie[0] = straight; return result; }
for (int rank = 14; rank >= 2; --rank) if (count[rank] == 4U) { result.value = HAND_QUADS; result.tie[0] = (uint8_t)rank; for (int k=14;k>=2;--k) if (count[k]==1U) { result.tie[1]=(uint8_t)k; break; } return result; }
uint8_t three = 0, pair = 0;
for (int rank=14; rank>=2; --rank) { if (!three && count[rank] == 3U) three=(uint8_t)rank; else if (!pair && count[rank] == 2U) pair=(uint8_t)rank; }
if (three && pair) { result.value=HAND_FULL_HOUSE; result.tie[0]=three; result.tie[1]=pair; return result; }
if (flush) { result.value=HAND_FLUSH; uint8_t n=0; for(int rank=14;rank>=2;--rank) for(uint8_t j=0;j<count[rank];++j) result.tie[n++]=(uint8_t)rank; return result; }
if (straight) { result.value=HAND_STRAIGHT; result.tie[0]=straight; return result; }
if (three) { result.value=HAND_TRIPS; result.tie[0]=three; uint8_t n=1; for(int rank=14;rank>=2;--rank) if(count[rank]==1U) result.tie[n++]=(uint8_t)rank; return result; }
uint8_t high_pair=0, low_pair=0;
for(int rank=14;rank>=2;--rank) if(count[rank]==2U) { if(!high_pair) high_pair=(uint8_t)rank; else low_pair=(uint8_t)rank; }
if(high_pair && low_pair) { result.value=HAND_TWO_PAIR; result.tie[0]=high_pair; result.tie[1]=low_pair; for(int rank=14;rank>=2;--rank) if(count[rank]==1U) { result.tie[2]=(uint8_t)rank; break; } return result; }
if(high_pair) { result.value=HAND_PAIR; result.tie[0]=high_pair; uint8_t n=1; for(int rank=14;rank>=2;--rank) if(count[rank]==1U) result.tie[n++]=(uint8_t)rank; return result; }
uint8_t n=0; for(int rank=14;rank>=2;--rank) if(count[rank]) result.tie[n++]=(uint8_t)rank; return result;
}
static hand_rank_t evaluateBest(const card_t *cards, uint8_t count) {
hand_rank_t best = {0}; bool first = true;
for(uint8_t a=0;a<count-4U;++a) for(uint8_t b=a+1;b<count-3U;++b) for(uint8_t c=b+1;c<count-2U;++c) for(uint8_t d=c+1;d<count-1U;++d) for(uint8_t e=d+1;e<count;++e) {
const card_t five[5]={cards[a],cards[b],cards[c],cards[d],cards[e]}; hand_rank_t candidate=evaluateFive(five);
if(first || compareRanks(candidate,best)>0) { best=candidate; first=false; }
}
return best;
}
static const char *handName(hand_value_t value) {
static const char *names[] = { "HIGH CARD", "ONE PAIR", "TWO PAIR", "THREE KIND", "STRAIGHT", "FLUSH", "FULL HOUSE", "FOUR KIND", "STRAIGHT FLUSH" };
return names[value];
}
static void shuffleDeck(void) {
static const char suits[] = { 'C', 'D', 'H', 'S' }; uint8_t n=0;
for(uint8_t s=0;s<4U;++s) for(uint8_t rank=2U;rank<=14U;++rank) deck[n++]=(card_t){rank,suits[s]};
for(int i=DECK_SIZE-1;i>0;--i) { const uint8_t j=esp_random()%(uint32_t)(i+1); const card_t card=deck[i]; deck[i]=deck[j]; deck[j]=card; }
deck_position=0;
}
static bool deal(card_t *card) { if(deck_position>=DECK_SIZE) return false; *card=deck[deck_position++]; return true; }
static void dealHoleCards(void) { if(player_dealer) { deal(&player_cards[0]); deal(&cpu_cards[0]); deal(&player_cards[1]); deal(&cpu_cards[1]); } else { deal(&cpu_cards[0]); deal(&player_cards[0]); deal(&cpu_cards[1]); deal(&player_cards[1]); } audioPlay(AUDIO_SFX_CARD_DEAL); }
static uint32_t remainingRaisePotRoom(void) { return pot < POKER_RAISE_POT_LIMIT ? POKER_RAISE_POT_LIMIT-pot : 0U; }
static bool commitPlayer(uint32_t amount) { if(amount > getGold() || !spendGold(amount)) return false; player_bet+=amount; player_committed+=amount; pot+=amount; return true; }
static void commitCpu(uint32_t amount) { if(amount>cpu_stack) amount=cpu_stack; cpu_stack-=amount; cpu_bet+=amount; pot+=amount; }
static uint32_t minimumRaise(void) { const uint32_t maximum=player_bet+getGold(), full=currentBet()+last_raise; if(maximum<=currentBet()) return 0U; const uint32_t target=maximum<full?maximum:full; return target-player_bet>remainingRaisePotRoom()?0U:target; }
static uint8_t holeStrength(const card_t cards[2]) { const uint8_t high=cards[0].rank>cards[1].rank?cards[0].rank:cards[1].rank, low=cards[0].rank<cards[1].rank?cards[0].rank:cards[1].rank; if(high==low) return (uint8_t)(55U+high*3U); uint8_t strength=(uint8_t)(high*3U+low); if(cards[0].suit==cards[1].suit) strength+=8U; const uint8_t gap=high-low; if(gap==1U) strength+=6U; else if(gap==2U) strength+=3U; if(high==14U) strength+=8U; return strength>100U?100U:strength; }
static uint8_t postFlopStrength(const card_t cards[2]) { card_t seven[7]={cards[0],cards[1]}; for(uint8_t i=0;i<community_count;++i) seven[i+2U]=community_cards[i]; const hand_rank_t rank=evaluateBest(seven,(uint8_t)(community_count+2U)); static const uint8_t values[]={15,40,62,72,80,84,90,96,100}; return (uint8_t)(values[rank.value]+(rank.value==HAND_PAIR||rank.value==HAND_HIGH?rank.tie[0]:0U)); }
static uint8_t strength(const card_t cards[2]) { return street==STREET_PREFLOP?holeStrength(cards):postFlopStrength(cards); }
static void setStatus(const char *text) { snprintf(status_text,sizeof(status_text),"%s",text); redraw_needed=true; }
static void dealFlop(void) { card_t burn; deal(&burn); for(uint8_t i=0;i<3U;++i) deal(&community_cards[i]); community_count=3U; street=STREET_FLOP; audioPlay(AUDIO_SFX_CARD_DEAL); }
static void dealTurn(void) { card_t burn; deal(&burn); deal(&community_cards[3]); community_count=4U; street=STREET_TURN; audioPlay(AUDIO_SFX_CARD_DEAL); }
static void dealRiver(void) { card_t burn; deal(&burn); deal(&community_cards[4]); community_count=5U; street=STREET_RIVER; audioPlay(AUDIO_SFX_CARD_DEAL); }
static void startAutoRestart(uint32_t now, uint32_t delay) { if(auto_mode) { auto_restart_started=now; auto_restart_delay=delay; auto_seconds=(uint8_t)((delay+999U)/1000U); } }
static bool awardPot(void) { if(player_committed && !addGold(player_committed)) return false; const uint32_t profit=pot-player_committed; return !profit || (auto_mode?addAIGold(profit):addUserGoldWon(profit)); }
static bool recordLoss(void) { return auto_mode?recordAIGoldLost(player_committed):recordUserGoldLost(player_committed); }
static void finishFold(bool player_won, uint32_t now) { audioPlay(player_won ? AUDIO_SFX_WAVE_CLEAR : AUDIO_SFX_GAME_OVER); hand_active=false; state=POKER_FINISHED; reveal_cpu=false; setStatus(player_won?(awardPot()?"CPU FOLDS":"GOLD ERROR"):(recordLoss()?"YOU FOLD":"GOLD ERROR")); startAutoRestart(now,auto_mode&&!player_won&&street==STREET_PREFLOP?AUTO_PREFLOP_FOLD_DELAY_MS:aiRestartDelay()); }
static void finishShowdown(uint32_t now) { card_t player[7]={player_cards[0],player_cards[1],community_cards[0],community_cards[1],community_cards[2],community_cards[3],community_cards[4]}; card_t cpu[7]={cpu_cards[0],cpu_cards[1],community_cards[0],community_cards[1],community_cards[2],community_cards[3],community_cards[4]}; const hand_rank_t a=evaluateBest(player,7), b=evaluateBest(cpu,7); snprintf(player_hand_text,sizeof(player_hand_text),"%s",handName(a.value)); snprintf(cpu_hand_text,sizeof(cpu_hand_text),"%s",handName(b.value)); reveal_cpu=true; hand_active=false; state=POKER_FINISHED; const int8_t result=compareRanks(a,b); audioPlay(result>0 ? AUDIO_SFX_WAVE_CLEAR : result<0 ? AUDIO_SFX_GAME_OVER : AUDIO_SFX_MENU_SELECT); if(result>0) setStatus(awardPot()?"YOU WIN":"GOLD ERROR"); else if(result<0) setStatus(recordLoss()?"CPU WINS":"GOLD ERROR"); else { addGold(player_committed); setStatus("DRAW"); } startAutoRestart(now,aiRestartDelay()); }
static void moveToPlayer(const char *message, uint32_t now) { state=POKER_PLAYER; selected_action=ACTION_CALL_CHECK; setStatus(message); if(auto_mode) state_started=now; }
static void moveToCpu(uint32_t now) { state=POKER_CPU; setStatus("CPU THINK"); state_started=now; }
static void startPostFlop(const char *message, uint32_t now) { player_bet=cpu_bet=0; last_raise=BIG_BLIND; player_acted=cpu_acted=false; if(player_dealer) moveToCpu(now); else moveToPlayer(message,now); }
static void startAllIn(uint32_t now) { state=POKER_ALL_IN; setStatus("ALL IN"); state_started=now; }
static void completeRound(uint32_t now) { if(!getGold()||!cpu_stack) { if(community_count<5U) startAllIn(now); else finishShowdown(now); return; } if(street==STREET_PREFLOP) { dealFlop(); startPostFlop("FLOP",now); } else if(street==STREET_FLOP) { dealTurn(); startPostFlop("TURN",now); } else if(street==STREET_TURN) { dealRiver(); startPostFlop("RIVER",now); } else finishShowdown(now); }
static void processAllIn(uint32_t now) { if(community_count==0U) { dealFlop(); setStatus("ALL IN FLOP"); } else if(community_count==3U) { dealTurn(); setStatus("ALL IN TURN"); } else if(community_count==4U) { dealRiver(); setStatus("ALL IN RIVER"); } else { finishShowdown(now); return; } state_started=now; }
static bool shouldFold(uint32_t call, uint8_t hand_strength) { return call && hand_strength<35U && esp_random()%100U>=15U; }
static void processCpu(uint32_t now) { const uint32_t call=player_bet>cpu_bet?player_bet-cpu_bet:0U; const uint8_t value=strength(cpu_cards); if(shouldFold(call,value)) { finishFold(true,now); return; } const uint32_t target=currentBet()+last_raise, maximum=cpu_bet+cpu_stack; const bool can_raise=value>=GOLD_HAND_STRENGTH && target>currentBet() && maximum>=target && target-cpu_bet<=remainingRaisePotRoom(); if(can_raise) { const uint32_t previous=currentBet(); commitCpu(target-cpu_bet); last_raise=target-previous; cpu_acted=true; player_acted=false; moveToPlayer("CPU RAISE",now); return; } commitCpu(call); cpu_acted=true; if(player_acted && player_bet==cpu_bet) completeRound(now); else moveToPlayer(call?"CPU CALL":"CPU CHECK",now); }
static void processAuto(uint32_t now) { const uint32_t call=cpu_bet>player_bet?cpu_bet-player_bet:0U; const uint8_t value=strength(player_cards); if(call>getGold()||shouldFold(call,value)) { finishFold(false,now); return; } const uint32_t target=minimumRaise(); if(value>=GOLD_HAND_STRENGTH && target>currentBet()) { const uint32_t previous=currentBet(); if(!commitPlayer(target-player_bet)) { finishFold(false,now); return; } last_raise=target-previous; player_acted=true; cpu_acted=false; moveToCpu(now); return; } if(!commitPlayer(call)) { finishFold(false,now); return; } player_acted=true; if(cpu_acted&&player_bet==cpu_bet) completeRound(now); else moveToCpu(now); }
static void beginHand(uint32_t now) { pot=player_bet=cpu_bet=player_committed=community_count=0; street=STREET_PREFLOP; last_raise=BIG_BLIND; selected_action=ACTION_CALL_CHECK; player_acted=cpu_acted=reveal_cpu=false; hand_active=false; const uint32_t starting=getGold(); if(!starting) { state=POKER_NO_GOLD; setStatus("NEED GOLD"); return; } cpu_stack=starting; shuffleDeck(); dealHoleCards(); if(player_dealer) { commitPlayer(starting<SMALL_BLIND?starting:SMALL_BLIND); commitCpu(cpu_stack<BIG_BLIND?cpu_stack:BIG_BLIND); state=POKER_PLAYER; setStatus("PREFLOP"); if(auto_mode) state_started=now; } else { commitCpu(cpu_stack<SMALL_BLIND?cpu_stack:SMALL_BLIND); commitPlayer(starting<BIG_BLIND?starting:BIG_BLIND); moveToCpu(now); } hand_active=true; redraw_needed=true; }
void startPoker(uint32_t now_ms) { running=true; auto_mode=false; ai_speed=AI_SPEED_DEFAULT_INDEX; modeSelectionReset(&mode_input); player_dealer=true; state=POKER_MODE; setStatus("SELECT MODE"); state_started=now_ms; redraw_needed=true; }
void stopPoker(void) { if(hand_active) { recordLoss(); hand_active=false; pot=0; player_dealer=!player_dealer; } else if(state==POKER_FINISHED) player_dealer=!player_dealer; running=false; }
void pokerAction(bool action, bool cycle, bool speed, uint32_t now) {
if(!running) return;
if(state==POKER_MODE) { if(action) beginHand(now); return; }
if(auto_mode) { if(speed) { cycleAISpeed(&ai_speed); state_started=now; redraw_needed=true; } if(action) { if(hand_active) { recordLoss(); hand_active=false; pot=0; } auto_mode=false; modeSelectionReset(&mode_input); state=POKER_MODE; redraw_needed=true; } return; }
if(state==POKER_FINISHED && action) { player_dealer=!player_dealer; beginHand(now); return; }
if(state==POKER_RAISE) { if(cycle) { const uint32_t maximum=player_bet+getGold(), minimum=minimumRaise(); selected_raise=selected_raise<maximum?selected_raise+1U:minimum; redraw_needed=true; } if(action) { const uint32_t previous=currentBet(), amount=selected_raise-player_bet; if(amount<=remainingRaisePotRoom()&&commitPlayer(amount)) { last_raise=selected_raise-previous; player_acted=true; cpu_acted=false; moveToCpu(now); } } return; }
if(state!=POKER_PLAYER) return;
if(cycle) { selected_action=(poker_action_t)((selected_action+1U)%ACTION_COUNT); redraw_needed=true; }
if(!action) return;
if(selected_action==ACTION_FOLD) { finishFold(false,now); return; }
if(selected_action==ACTION_RAISE) { selected_raise=minimumRaise(); if(selected_raise) { state=POKER_RAISE; setStatus("RAISE TO"); } else setStatus("NO RAISE"); return; }
const uint32_t call=cpu_bet>player_bet?cpu_bet-player_bet:0U; if(!commitPlayer(call)) return; player_acted=true; if(cpu_acted&&player_bet==cpu_bet) completeRound(now); else moveToCpu(now);
}
void updatePoker(uint16_t *frame, int x_offset, int y_offset, bool joystick_valid, bool left, bool right, uint32_t now) { (void)frame; if(!running) return; if(state==POKER_MODE) { if(modeSelectionNext(&mode_input,x_offset,y_offset,joystick_valid,left,right,now)) { auto_mode=!auto_mode; redraw_needed=true; } return; } if(state==POKER_FINISHED&&auto_mode) { const uint32_t elapsed=now-auto_restart_started; if(elapsed>=auto_restart_delay) { player_dealer=!player_dealer; beginHand(now); return; } const uint8_t seconds=(uint8_t)((auto_restart_delay-elapsed+999U)/1000U); if(seconds!=auto_seconds) { auto_seconds=seconds; redraw_needed=true; } return; } if(state==POKER_PLAYER&&auto_mode&&now-state_started>=aiSpeedDelay(ai_speed)) { processAuto(now); return; } if(state==POKER_CPU&&now-state_started>=(auto_mode?aiSpeedDelay(ai_speed):CPU_ACTION_DELAY_MS)) { processCpu(now); return; } if(state==POKER_ALL_IN&&now-state_started>=(auto_mode?aiSpeedDelay(ai_speed):ALL_IN_REVEAL_MS)) processAllIn(now); }
static void cardPath(const card_t *card, char *path, size_t size) { const char *rank=card->rank==11U?"J":card->rank==12U?"Q":card->rank==13U?"K":card->rank==14U?"A":NULL; if(rank) snprintf(path,size,"/spiffs/cards/%s%c.jpg",rank,card->suit); else snprintf(path,size,"/spiffs/cards/%u%c.jpg",(unsigned)card->rank,card->suit); }
static void drawCard(uint16_t *frame,const card_t *card,int x,int y,unsigned scale) { char path[32]; cardPath(card,path,sizeof(path)); const bool decoded=scale?imageDecodeJpegScaledAt(path,frame,(unsigned)x,(unsigned)y,scale):imageDecodeJpegAt(path,frame,(unsigned)x,(unsigned)y); if(!decoded) { const int width=48>>scale,height=64>>scale; fill_rect(frame,x,y,width,height,COLOR_WHITE); draw_rect(frame,x,y,width,height,COLOR_RED); drawPet2001TextCentredTransparent(frame,x+width/2,y+height/2-4,path+14,COLOR_BLACK,1); } }
static void drawBack(uint16_t *frame,int x,int y) { if(!imageDecodeJpegAt("/spiffs/cards/Back.jpg",frame,(unsigned)x,(unsigned)y)) { fill_rect(frame,x,y,48,64,COLOR_BLUE); draw_rect(frame,x,y,48,64,COLOR_WHITE); } }
void drawPoker(uint16_t *frame) {
if (!running || !redraw_needed)
return;
redraw_needed = false;
clear(frame, COLOR_BLACK);
char text[42];
if (state == POKER_MODE) {
drawPet2001TextCentredTransparent(frame, 160, 12, "POKER", COLOR_CYAN, 4);
drawPet2001TextCentredTransparent(frame, 160, 42, "SELECT MODE", COLOR_LIGHTGRAY, 1);
drawPet2001TextCentredTransparent(frame, 100, 60, "PLAY", auto_mode ? COLOR_LIGHTGRAY : COLOR_YELLOW, 2);
drawPet2001TextCentredTransparent(frame, 220, 60, "AUTO", auto_mode ? COLOR_YELLOW : COLOR_LIGHTGRAY, 2);
drawPet2001TextCentredTransparent(frame, 160, 105, "D/B/STICK CHANGE A/K START", COLOR_LIGHTGRAY, 1);
drawPet2001TextCentredTransparent(frame, 160, 130, "BOOT EXIT", COLOR_LIGHTGRAY, 1);
return;
}
if (state == POKER_NO_GOLD) {
drawPet2001TextCentredTransparent(frame, 160, 18, "POKER", COLOR_CYAN, 4);
drawPet2001TextCentredTransparent(frame, 160, 72, "NO GOLD", COLOR_RED, 3);
return;
}
if (reveal_cpu) {
drawCard(frame, &cpu_cards[0], 112, 2, 0);
drawCard(frame, &cpu_cards[1], 164, 2, 0);
} else {
drawBack(frame, 112, 2);
drawBack(frame, 164, 2);
}
for (uint8_t i = 0; i < 5U; ++i) {
const int x = 94 + (int)i * 27;
if (i < community_count)
drawCard(frame, &community_cards[i], x, 69, 1);
else {
fill_rect(frame, x, 69, 24, 32, COLOR_BLACK);
draw_rect(frame, x, 69, 24, 32, COLOR_DARKGREY);
}
}
drawCard(frame, &player_cards[0], 112, 104, 0);
drawCard(frame, &player_cards[1], 164, 104, 0);
drawPet2001TextTransparent(frame, 3, 4, "CPU", COLOR_CYAN, 1);
if (reveal_cpu)
drawPet2001TextTransparent(frame, 0, 18, cpu_hand_text, COLOR_WHITE, 1);
else {
snprintf(text, sizeof(text), "B %u", (unsigned)cpu_bet);
drawPet2001TextTransparent(frame, 3, 18, text, COLOR_WHITE, 1);
}
drawPet2001TextTransparent(frame, 3, 106, "YOU", COLOR_GREEN, 1);
if (reveal_cpu)
drawPet2001TextTransparent(frame, 0, 120, player_hand_text, COLOR_WHITE, 1);
else {
snprintf(text, sizeof(text), "B %u", (unsigned)player_bet);
drawPet2001TextTransparent(frame, 3, 120, text, COLOR_WHITE, 1);
}
drawPet2001TextTransparent(frame, 3, 48, status_text, COLOR_CYAN, 1);
const char *choice = state == POKER_RAISE ? "TO"
: state == POKER_CPU ? "WAIT"
: state == POKER_ALL_IN ? "ALL IN"
: state == POKER_FINISHED
? (auto_mode ? "NEXT" : "DEAL")
: (selected_action == ACTION_RAISE ? "RAISE"
: selected_action == ACTION_FOLD ? "FOLD"
: player_bet < currentBet() ? "CALL"
: "CHECK");
if (state == POKER_RAISE)
snprintf(text, sizeof(text), "TO %u", (unsigned)selected_raise);
else if (state == POKER_FINISHED && auto_mode)
snprintf(text, sizeof(text), "NEXT %u", (unsigned)auto_seconds);
else
snprintf(text, sizeof(text), "%s", choice);
drawPet2001TextTransparent(frame, 3, 65, text, COLOR_YELLOW, 1);
drawGameGold(frame, 260, 4, 56, true);
snprintf(text, sizeof(text), "POT %u", (unsigned)pot);
drawPet2001TextTransparent(frame, 256, 46, text, COLOR_ORANGE, 1);
drawPet2001TextTransparent(frame, 260, 106, player_dealer ? "D YOU" : "D CPU", COLOR_CYAN, 1);
drawPet2001TextTransparent(frame, 260, 120, "BL 1/2", COLOR_DARKGREY, 1);
if (state == POKER_PLAYER) {
if (auto_mode) {
snprintf(text, sizeof(text), "AUTO E SPEED %s A STOP",
aiSpeedShortText(ai_speed));
drawPet2001TextCentredTransparent(frame, 160, 158, text, COLOR_LIGHTGRAY, 1);
} else {
drawPet2001TextCentredTransparent(frame, 160, 158, "C CHOOSE A/K SELECT", COLOR_LIGHTGRAY, 1);
}
} else if (state == POKER_FINISHED)
drawPet2001TextCentredTransparent(frame, 160, 158,
auto_mode ? "E SPEED A STOP" : "A/K DEAL", COLOR_LIGHTGRAY, 1);
}