commit 57bc06413e84c5621edd286b7f6904ed3c93f8c5
parent 0f4949bd06f819e056c95043e2eca6a257b2639a
Author: n0tr1v <n0tr1v@protonmail.com>
Date: Mon, 18 Dec 2023 22:21:32 -0500
cleanup
Diffstat:
1 file changed, 203 insertions(+), 190 deletions(-)
diff --git a/pkg/web/handlers/poker/poker.go b/pkg/web/handlers/poker/poker.go
@@ -579,6 +579,204 @@ type AutoAction struct {
evt PlayerEvent
}
+func foldPlayer(g *PokerGame, p *PokerPlayer) {
+ roomTopic := g.RoomID.Topic()
+ p.Folded.Store(true)
+ var firstCardIdx, secondCardIdx int
+ p.Cards.RWith(func(pCards *[]PlayerCard) {
+ firstCardIdx = (*pCards)[0].Idx
+ secondCardIdx = (*pCards)[1].Idx
+ })
+ evt1 := PokerEvent{ID: "card" + itoa(firstCardIdx), Name: "", Idx: firstCardIdx, Top: BurnStackY, Left: BurnStackX, Angle: "0deg", Reveal: false}
+ evt2 := PokerEvent{ID: "card" + itoa(secondCardIdx), Name: "", Idx: secondCardIdx, Top: BurnStackY, Left: BurnStackX, Angle: "0deg", Reveal: false}
+ PokerPubSub.Pub(roomTopic, evt1)
+ PokerPubSub.Pub(roomTopic, evt2)
+ g.Ongoing.AddEvent(evt1, evt2)
+}
+
+func doTimeout(g *PokerGame, p *PokerPlayer, minBet database.PokerChip, playerAlive *int) int {
+ pUsername := p.Username
+ if p.GetBet() < minBet {
+ foldPlayer(g, p)
+ g.newLogEvent(fmt.Sprintf("%s auto fold", pUsername))
+
+ *playerAlive--
+ if *playerAlive == 1 {
+ return breakRoundIsSettledLoop
+ }
+ return breakGetPlayerEventLoop
+ }
+ g.newLogEvent(fmt.Sprintf("%s auto check", pUsername))
+ return breakGetPlayerEventLoop
+}
+
+func doUnsit(g *PokerGame, p *PokerPlayer, playerAlive *int) int {
+ *playerAlive = g.Ongoing.CountAlivePlayers()
+ if *playerAlive == 1 {
+ p.countChancesToAction--
+ return breakRoundIsSettledLoop
+ }
+ return continueGetPlayerEventLoop
+}
+
+func doFold(g *PokerGame, p *PokerPlayer, playerAlive *int, roomUserTopic string) int {
+ foldPlayer(g, p)
+ g.newLogEvent(fmt.Sprintf("%s fold", p.Username))
+
+ *playerAlive--
+ if *playerAlive == 1 {
+ PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: ""})
+ return breakRoundIsSettledLoop
+ }
+ return doNothing
+}
+
+func doCheck(g *PokerGame, p *PokerPlayer, minBet database.PokerChip, roomUserTopic string) int {
+ if p.GetBet() < minBet {
+ msg := fmt.Sprintf("Need to bet %d", minBet-p.GetBet())
+ PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg})
+ return continueGetPlayerEventLoop
+ }
+ g.newLogEvent(fmt.Sprintf("%s check", p.Username))
+ return doNothing
+}
+
+func doCall(g *PokerGame, p *PokerPlayer, db *database.DkfDB, minBet database.PokerChip, newlyAllInPlayers *[]*PokerPlayer, pokerTableID int64) int {
+ pUsername := p.Username
+ bet := utils.MinInt(minBet-p.GetBet(), p.GetCash())
+ if bet == 0 {
+ g.newLogEvent(fmt.Sprintf("%s check", pUsername))
+ } else {
+ p.doBetAndNotif(db, pokerTableID, bet, g.RoomID.Topic())
+ logMsg := fmt.Sprintf("%s call (%d)", pUsername, bet)
+ if p.isAllIn() {
+ logMsg += " (all-in)"
+ *newlyAllInPlayers = append(*newlyAllInPlayers, p)
+ }
+ g.newLogEvent(logMsg)
+ }
+ return doNothing
+}
+
+func doAllIn(g *PokerGame, p *PokerPlayer, db *database.DkfDB, minBet database.PokerChip, newlyAllInPlayers *[]*PokerPlayer, pokerTableID int64, lastRaisePlayerIdx *int, playerToPlayIdx int) int {
+ bet := p.GetCash()
+ if (p.GetBet() + bet) > minBet {
+ *lastRaisePlayerIdx = playerToPlayIdx
+ }
+ minBet = utils.MaxInt(p.GetBet()+bet, minBet)
+ p.doBetAndNotif(db, pokerTableID, bet, g.RoomID.Topic())
+ logMsg := fmt.Sprintf("%s all-in (%d)", p.Username, bet)
+ if p.isAllIn() {
+ *newlyAllInPlayers = append(*newlyAllInPlayers, p)
+ }
+ g.newLogEvent(logMsg)
+ return doNothing
+}
+
+func doBet(g *PokerGame, p *PokerPlayer, db *database.DkfDB, minBet database.PokerChip, newlyAllInPlayers *[]*PokerPlayer, pokerTableID int64, lastRaisePlayerIdx *int, playerToPlayIdx int, evt PlayerEvent) int {
+ roomTopic := g.RoomID.Topic()
+ roomUserTopic := g.RoomID.UserTopic(p.Username)
+ pokerTableMinBet := g.PokerTableMinBet
+ bet := evt.Bet
+ // Ensure the player cannot bet below the table minimum bet (amount of the big blind)
+ if p.GetBet()+bet != minBet && bet < pokerTableMinBet {
+ msg := fmt.Sprintf("Bet (%d) is too low. Must bet at least %d", bet, pokerTableMinBet)
+ PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg})
+ return continueGetPlayerEventLoop
+ }
+ if (p.GetBet() + bet) < minBet {
+ msg := fmt.Sprintf("Bet (%d) is too low. Must bet at least %d", bet, minBet-p.GetBet())
+ PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg})
+ return continueGetPlayerEventLoop
+ }
+ if bet > p.GetCash() {
+ msg := fmt.Sprintf("Bet (%d) is too high. Must bet at most %d", bet, p.GetCash())
+ PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg})
+ return continueGetPlayerEventLoop
+ }
+ if (p.GetBet() + bet) > minBet {
+ *lastRaisePlayerIdx = playerToPlayIdx
+ }
+ minBet = utils.MaxInt(p.GetBet()+bet, minBet)
+ p.doBetAndNotif(db, pokerTableID, bet, roomTopic)
+ logMsg := fmt.Sprintf("%s bet %d", p.Username, bet)
+ if p.isAllIn() {
+ logMsg += " (all-in)"
+ *newlyAllInPlayers = append(*newlyAllInPlayers, p)
+ }
+ g.newLogEvent(logMsg)
+ return doNothing
+}
+
+func handleAutoActionReceived(g *PokerGame, autoCache map[database.Username]AutoAction, roomID RoomID, evt PlayerEvent) int {
+ roomUserTopic := roomID.UserTopic(evt.Player)
+ autoAction := autoCache[evt.Player]
+ if evt.Fold && autoAction.action == FoldAction ||
+ evt.Call && autoAction.action == CallAction ||
+ evt.Check && autoAction.action == CheckAction {
+ delete(autoCache, evt.Player)
+ setAutoAction(g, roomUserTopic, "")
+ return continueGetPlayerEventLoop
+ }
+
+ action := evt.getAction()
+ if action != NoAction {
+ autoCache[evt.Player] = AutoAction{action: action, evt: evt}
+ setAutoAction(g, roomUserTopic, "Will auto "+action.String())
+ }
+ return continueGetPlayerEventLoop
+}
+
+func applyAutoAction(g *PokerGame, p *PokerPlayer, db *database.DkfDB, minBet database.PokerChip,
+ newlyAllInPlayers *[]*PokerPlayer, pokerTableID int64,
+ lastRaisePlayerIdx, playerAlive *int, playerToPlayIdx int, autoAction AutoAction,
+ autoCache map[database.Username]AutoAction) (actionResult int) {
+
+ roomUserTopic := g.RoomID.UserTopic(p.Username)
+ if autoAction.action > NoAction {
+ time.Sleep(500 * time.Millisecond)
+ p.LastActionTS = time.Now()
+ switch autoAction.action {
+ case NoAction:
+ case FoldAction:
+ actionResult = doFold(g, p, playerAlive, roomUserTopic)
+ case CheckAction:
+ actionResult = doCheck(g, p, minBet, roomUserTopic)
+ case CallAction:
+ actionResult = doCall(g, p, db, minBet, newlyAllInPlayers, pokerTableID)
+ case BetAction:
+ actionResult = doBet(g, p, db, minBet, newlyAllInPlayers, pokerTableID, lastRaisePlayerIdx, playerToPlayIdx, autoAction.evt)
+ case AllInAction:
+ actionResult = doAllIn(g, p, db, minBet, newlyAllInPlayers, pokerTableID, lastRaisePlayerIdx, playerToPlayIdx)
+ }
+ }
+ delete(autoCache, p.Username)
+ setAutoAction(g, roomUserTopic, "")
+ return
+}
+
+func handlePlayerActionEvent(g *PokerGame, p *PokerPlayer, db *database.DkfDB, minBet database.PokerChip,
+ newlyAllInPlayers *[]*PokerPlayer, pokerTableID int64,
+ lastRaisePlayerIdx, playerAlive *int, playerToPlayIdx int, evt PlayerEvent) (actionResult int) {
+
+ roomUserTopic := g.RoomID.UserTopic(p.Username)
+ p.LastActionTS = time.Now()
+ if evt.Fold {
+ actionResult = doFold(g, p, playerAlive, roomUserTopic)
+ } else if evt.Check {
+ actionResult = doCheck(g, p, minBet, roomUserTopic)
+ } else if evt.Call {
+ actionResult = doCall(g, p, db, minBet, newlyAllInPlayers, pokerTableID)
+ } else if evt.AllIn {
+ actionResult = doAllIn(g, p, db, minBet, newlyAllInPlayers, pokerTableID, lastRaisePlayerIdx, playerToPlayIdx)
+ } else if evt.Bet > 0 {
+ actionResult = doBet(g, p, db, minBet, newlyAllInPlayers, pokerTableID, lastRaisePlayerIdx, playerToPlayIdx, evt)
+ } else {
+ actionResult = continueGetPlayerEventLoop
+ }
+ return actionResult
+}
+
// Return either or not the game ended because only 1 player left playing (or none)
func execBettingRound(g *PokerGame, skip int, minBet database.PokerChip) bool {
db := g.DB
@@ -592,21 +790,6 @@ func execBettingRound(g *PokerGame, skip int, minBet database.PokerChip) bool {
newlyAllInPlayers := make([]*PokerPlayer, 0)
autoCache := make(map[database.Username]AutoAction)
- foldPlayer := func(p *PokerPlayer) {
- p.Folded.Store(true)
-
- var firstCardIdx, secondCardIdx int
- p.Cards.RWith(func(pCards *[]PlayerCard) {
- firstCardIdx = (*pCards)[0].Idx
- secondCardIdx = (*pCards)[1].Idx
- })
- evt1 := PokerEvent{ID: "card" + itoa(firstCardIdx), Name: "", Idx: firstCardIdx, Top: BurnStackY, Left: BurnStackX, Angle: "0deg", Reveal: false}
- evt2 := PokerEvent{ID: "card" + itoa(secondCardIdx), Name: "", Idx: secondCardIdx, Top: BurnStackY, Left: BurnStackX, Angle: "0deg", Reveal: false}
- PokerPubSub.Pub(roomTopic, evt1)
- PokerPubSub.Pub(roomTopic, evt2)
- ongoing.AddEvent(evt1, evt2)
- }
-
playerAlive := ongoing.CountAlivePlayers()
// Avoid asking for actions if only 1 player can do so (because others are all-in)
@@ -640,176 +823,6 @@ RoundIsSettledLoop:
setWaitTurn(g, p.SeatIdx)
PokerPubSub.Pub(roomUserTopic, PokerYourTurnEvent{})
- doTimeout := func() int {
- if p.GetBet() < minBet {
- foldPlayer(p)
- g.newLogEvent(fmt.Sprintf("%s auto fold", pUsername))
-
- playerAlive--
- if playerAlive == 1 {
- return breakRoundIsSettledLoop
- }
- return breakGetPlayerEventLoop
- }
- g.newLogEvent(fmt.Sprintf("%s auto check", pUsername))
- return breakGetPlayerEventLoop
- }
-
- doUnsit := func() int {
- playerAlive = ongoing.CountAlivePlayers()
- if playerAlive == 1 {
- p.countChancesToAction--
- return breakRoundIsSettledLoop
- }
- return continueGetPlayerEventLoop
- }
-
- doFold := func() int {
- foldPlayer(p)
- g.newLogEvent(fmt.Sprintf("%s fold", pUsername))
-
- playerAlive--
- if playerAlive == 1 {
- PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: ""})
- return breakRoundIsSettledLoop
- }
- return doNothing
- }
-
- doCheck := func() int {
- if p.GetBet() < minBet {
- msg := fmt.Sprintf("Need to bet %d", minBet-p.GetBet())
- PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg})
- return continueGetPlayerEventLoop
- }
- g.newLogEvent(fmt.Sprintf("%s check", pUsername))
- return doNothing
- }
-
- doCall := func() int {
- bet := utils.MinInt(minBet-p.GetBet(), p.GetCash())
- if bet == 0 {
- g.newLogEvent(fmt.Sprintf("%s check", pUsername))
- } else {
- p.doBetAndNotif(db, pokerTableID, bet, roomTopic)
- logMsg := fmt.Sprintf("%s call (%d)", pUsername, bet)
- if p.isAllIn() {
- logMsg += " (all-in)"
- newlyAllInPlayers = append(newlyAllInPlayers, p)
- }
- g.newLogEvent(logMsg)
- }
- return doNothing
- }
-
- doAllIn := func() int {
- bet := p.GetCash()
- if (p.GetBet() + bet) > minBet {
- lastRaisePlayerIdx = playerToPlayIdx
- }
- minBet = utils.MaxInt(p.GetBet()+bet, minBet)
- p.doBetAndNotif(db, pokerTableID, bet, roomTopic)
- logMsg := fmt.Sprintf("%s all-in (%d)", pUsername, bet)
- if p.isAllIn() {
- newlyAllInPlayers = append(newlyAllInPlayers, p)
- }
- g.newLogEvent(logMsg)
- return doNothing
- }
-
- doBet := func(evt PlayerEvent) int {
- pokerTableMinBet := g.PokerTableMinBet
- bet := evt.Bet
- // Ensure the player cannot bet below the table minimum bet (amount of the big blind)
- if p.GetBet()+bet != minBet && bet < pokerTableMinBet {
- msg := fmt.Sprintf("Bet (%d) is too low. Must bet at least %d", bet, pokerTableMinBet)
- PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg})
- return continueGetPlayerEventLoop
- }
- if (p.GetBet() + bet) < minBet {
- msg := fmt.Sprintf("Bet (%d) is too low. Must bet at least %d", bet, minBet-p.GetBet())
- PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg})
- return continueGetPlayerEventLoop
- }
- if bet > p.GetCash() {
- msg := fmt.Sprintf("Bet (%d) is too high. Must bet at most %d", bet, p.GetCash())
- PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg})
- return continueGetPlayerEventLoop
- }
- if (p.GetBet() + bet) > minBet {
- lastRaisePlayerIdx = playerToPlayIdx
- }
- minBet = utils.MaxInt(p.GetBet()+bet, minBet)
- p.doBetAndNotif(db, pokerTableID, bet, roomTopic)
- logMsg := fmt.Sprintf("%s bet %d", pUsername, bet)
- if p.isAllIn() {
- logMsg += " (all-in)"
- newlyAllInPlayers = append(newlyAllInPlayers, p)
- }
- g.newLogEvent(logMsg)
- return doNothing
- }
-
- handleAutoActionReceived := func(evt PlayerEvent) int {
- roomUserTopic := roomID.UserTopic(evt.Player)
- autoAction := autoCache[evt.Player]
- if evt.Fold && autoAction.action == FoldAction ||
- evt.Call && autoAction.action == CallAction ||
- evt.Check && autoAction.action == CheckAction {
- delete(autoCache, evt.Player)
- setAutoAction(g, roomUserTopic, "")
- return continueGetPlayerEventLoop
- }
-
- action := evt.getAction()
- if action != NoAction {
- autoCache[evt.Player] = AutoAction{action: action, evt: evt}
- setAutoAction(g, roomUserTopic, "Will auto "+action.String())
- }
- return continueGetPlayerEventLoop
- }
-
- handlePlayerActionEvent := func(evt PlayerEvent) (actionResult int) {
- p.LastActionTS = time.Now()
- if evt.Fold {
- actionResult = doFold()
- } else if evt.Check {
- actionResult = doCheck()
- } else if evt.Call {
- actionResult = doCall()
- } else if evt.AllIn {
- actionResult = doAllIn()
- } else if evt.Bet > 0 {
- actionResult = doBet(evt)
- } else {
- actionResult = continueGetPlayerEventLoop
- }
- return actionResult
- }
-
- applyAutoAction := func(autoAction AutoAction) (actionResult int) {
- if autoAction.action > NoAction {
- time.Sleep(500 * time.Millisecond)
- p.LastActionTS = time.Now()
- switch autoAction.action {
- case NoAction:
- case FoldAction:
- actionResult = doFold()
- case CheckAction:
- actionResult = doCheck()
- case CallAction:
- actionResult = doCall()
- case BetAction:
- actionResult = doBet(autoAction.evt)
- case AllInAction:
- actionResult = doAllIn()
- }
- }
- delete(autoCache, pUsername)
- setAutoAction(g, roomUserTopic, "")
- return
- }
-
// Maximum time allowed for the player to send his action
waitCh := time.After(MaxUserCountdown * time.Second)
GetPlayerEventLoop:
@@ -819,28 +832,28 @@ RoundIsSettledLoop:
// Check for pre-selected action
if autoAction, ok := autoCache[pUsername]; ok {
- actionResult = applyAutoAction(autoAction)
+ actionResult = applyAutoAction(g, p, db, minBet, &newlyAllInPlayers, pokerTableID, &lastRaisePlayerIdx, &playerAlive, playerToPlayIdx, autoAction, autoCache)
goto checkActionResult
}
select {
case evt = <-g.PlayersEventCh:
case <-waitCh: // Waited too long, either auto-check or auto-fold
- actionResult = doTimeout()
+ actionResult = doTimeout(g, p, minBet, &playerAlive)
goto checkActionResult
}
if evt.Unsit {
- actionResult = doUnsit()
+ actionResult = doUnsit(g, p, &playerAlive)
goto checkActionResult
}
if evt.Player != pUsername {
- actionResult = handleAutoActionReceived(evt)
+ actionResult = handleAutoActionReceived(g, autoCache, roomID, evt)
goto checkActionResult
}
- actionResult = handlePlayerActionEvent(evt)
+ actionResult = handlePlayerActionEvent(g, p, db, minBet, &newlyAllInPlayers, pokerTableID, &lastRaisePlayerIdx, &playerAlive, playerToPlayIdx, evt)
goto checkActionResult
checkActionResult: