mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Add adventure plugin, holdem CFR fixes, and wordle plugin
Adventure: Complete v1 daily idle RPG with DM-driven gameplay, equipment shop, treasure system, TwinBee NPC, streak/grudge/party mechanics, flavor text, and scheduled morning/evening/midnight tickers. Holdem CFR: Fix three critical training bugs (fold not forfeiting pot, free calls after raises, training/runtime key mismatch). Add performance optimizations (preflop lookup table, zero-alloc equity, integer keys, raise cap, regret pruning). Enrich abstraction with 12 equity buckets, board texture dimension, and 6-char action history. Replace validation with proper multi-street simulation. Also includes wordle plugin, holdem seed tooling, and schema additions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
114
internal/plugin/holdem_equity.go
Normal file
114
internal/plugin/holdem_equity.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"math/rand/v2"
|
||||
|
||||
"github.com/chehsunliu/poker"
|
||||
)
|
||||
|
||||
// EquityResult holds Monte Carlo simulation results.
|
||||
type EquityResult struct {
|
||||
Win float64
|
||||
Tie float64
|
||||
Loss float64
|
||||
}
|
||||
|
||||
// allCards returns a fresh 52-card slice.
|
||||
func allCards() []poker.Card {
|
||||
suits := []string{"s", "h", "d", "c"}
|
||||
ranks := []string{"2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"}
|
||||
cards := make([]poker.Card, 0, 52)
|
||||
for _, r := range ranks {
|
||||
for _, s := range suits {
|
||||
cards = append(cards, poker.NewCard(r+s))
|
||||
}
|
||||
}
|
||||
return cards
|
||||
}
|
||||
|
||||
// Equity computes win/tie/loss fractions via Monte Carlo simulation.
|
||||
func Equity(hole [2]poker.Card, community []poker.Card, numOpponents, iterations int) EquityResult {
|
||||
if numOpponents < 1 {
|
||||
numOpponents = 1
|
||||
}
|
||||
|
||||
// Build set of known cards to exclude.
|
||||
known := make(map[poker.Card]bool, 2+len(community))
|
||||
known[hole[0]] = true
|
||||
known[hole[1]] = true
|
||||
for _, c := range community {
|
||||
known[c] = true
|
||||
}
|
||||
|
||||
// Remaining deck.
|
||||
remaining := make([]poker.Card, 0, 52-len(known))
|
||||
for _, c := range allCards() {
|
||||
if !known[c] {
|
||||
remaining = append(remaining, c)
|
||||
}
|
||||
}
|
||||
|
||||
boardNeeded := 5 - len(community)
|
||||
cardsNeeded := numOpponents*2 + boardNeeded
|
||||
|
||||
var wins, ties, losses int
|
||||
|
||||
for i := 0; i < iterations; i++ {
|
||||
// Fisher-Yates shuffle of first cardsNeeded elements.
|
||||
for j := 0; j < cardsNeeded && j < len(remaining); j++ {
|
||||
k := j + rand.IntN(len(remaining)-j)
|
||||
remaining[j], remaining[k] = remaining[k], remaining[j]
|
||||
}
|
||||
|
||||
// Deal opponent holes.
|
||||
idx := 0
|
||||
opponentHoles := make([][2]poker.Card, numOpponents)
|
||||
for o := 0; o < numOpponents; o++ {
|
||||
opponentHoles[o] = [2]poker.Card{remaining[idx], remaining[idx+1]}
|
||||
idx += 2
|
||||
}
|
||||
|
||||
// Complete board.
|
||||
fullBoard := make([]poker.Card, 5)
|
||||
copy(fullBoard, community)
|
||||
for b := len(community); b < 5; b++ {
|
||||
fullBoard[b] = remaining[idx]
|
||||
idx++
|
||||
}
|
||||
|
||||
// Evaluate hero.
|
||||
heroCards := make([]poker.Card, 7)
|
||||
heroCards[0] = hole[0]
|
||||
heroCards[1] = hole[1]
|
||||
copy(heroCards[2:], fullBoard)
|
||||
heroRank := poker.Evaluate(heroCards)
|
||||
|
||||
// Evaluate opponents.
|
||||
bestOpp := int32(7463) // worst possible rank
|
||||
for _, oh := range opponentHoles {
|
||||
oppCards := make([]poker.Card, 7)
|
||||
oppCards[0] = oh[0]
|
||||
oppCards[1] = oh[1]
|
||||
copy(oppCards[2:], fullBoard)
|
||||
oppRank := poker.Evaluate(oppCards)
|
||||
if oppRank < bestOpp {
|
||||
bestOpp = oppRank
|
||||
}
|
||||
}
|
||||
|
||||
if heroRank < bestOpp {
|
||||
wins++
|
||||
} else if heroRank == bestOpp {
|
||||
ties++
|
||||
} else {
|
||||
losses++
|
||||
}
|
||||
}
|
||||
|
||||
total := float64(iterations)
|
||||
return EquityResult{
|
||||
Win: float64(wins) / total,
|
||||
Tie: float64(ties) / total,
|
||||
Loss: float64(losses) / total,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user