dkforest

A forum and chat platform (onion)
git clone https://git.dasho.dev/n0tr1v/dkforest.git
Log | Files | Refs | LICENSE

commit 3bf371e63b8da5b4e6daca8dabfd6de8dabcb78c
parent 24652cddc1ec40643704d4dcb3d2626b305c6295
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Sat, 16 Dec 2023 04:03:46 -0500

schedule action to do before it's your turn to play

Diffstat:
Mpkg/web/handlers/poker/poker.go | 263++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
1 file changed, 179 insertions(+), 84 deletions(-)

diff --git a/pkg/web/handlers/poker/poker.go b/pkg/web/handlers/poker/poker.go @@ -485,6 +485,20 @@ func setWaitTurn(g *PokerGame, roomTopic string, seatIdx int) { g.Ongoing.WaitTurnEventMtx.Unlock() } +const ( + NoAction = iota + FoldAction + CallAction + CheckAction +) + +const ( + doNothing = iota + breakRoundIsSettledLoop + continueGetPlayerEventLoop + breakGetPlayerEventLoop +) + // Return either or not the game ended because only 1 player left playing (or none) func waitPlayersActionFn(db *database.DkfDB, g *PokerGame, roomID RoomID, skip int, minBet database.PokerChip) bool { roomTopic := roomID.Topic() @@ -493,6 +507,7 @@ func waitPlayersActionFn(db *database.DkfDB, g *PokerGame, roomID RoomID, skip i playerToPlayIdx := (dealerIdx + skip) % len(g.Ongoing.Players) lastRaisePlayerIdx := -1 newlyAllInPlayers := make([]*PokerPlayer, 0) + autoCache := make(map[database.Username]int) foldPlayer := func(p *PokerPlayer) { p.Folded.Store(true) @@ -538,28 +553,138 @@ RoundIsSettledLoop: setWaitTurn(g, roomTopic, p.SeatIdx) PokerPubSub.Pub(roomUserTopic, PokerYourTurnEvent{}) + doTimeout := func() int { + if p.Bet < minBet { + foldPlayer(p) + newLogEvent(g, roomLogsTopic, fmt.Sprintf("%s auto fold", pUsername)) + + playerAlive-- + if playerAlive == 1 { + return breakRoundIsSettledLoop + } + return breakGetPlayerEventLoop + } + newLogEvent(g, roomLogsTopic, fmt.Sprintf("%s auto check", pUsername)) + return breakGetPlayerEventLoop + } + + doFold := func() int { + foldPlayer(p) + newLogEvent(g, roomLogsTopic, fmt.Sprintf("%s fold", pUsername)) + + playerAlive-- + if playerAlive == 1 { + PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: ""}) + return breakRoundIsSettledLoop + } + return doNothing + } + + doCheck := func() int { + if p.Bet < minBet { + msg := fmt.Sprintf("Need to bet %d", minBet-p.Bet) + PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg}) + return continueGetPlayerEventLoop + } + newLogEvent(g, roomLogsTopic, fmt.Sprintf("%s check", pUsername)) + return doNothing + } + + doCall := func() int { + bet := utils.MinInt(minBet-p.Bet, p.Cash) + if bet == 0 { + newLogEvent(g, roomLogsTopic, fmt.Sprintf("%s check", pUsername)) + } else { + p.doBet(db, bet, g.PokerTableID, roomTopic) + logMsg := fmt.Sprintf("%s call (%d)", pUsername, bet) + if p.isAllIn() { + logMsg += " (all-in)" + newlyAllInPlayers = append(newlyAllInPlayers, p) + } + newLogEvent(g, roomLogsTopic, logMsg) + } + return doNothing + } + + doAllIn := func() int { + bet := p.Cash + if (p.Bet + bet) > minBet { + lastRaisePlayerIdx = playerToPlayIdx + } + minBet = utils.MaxInt(p.Bet+bet, minBet) + p.doBet(db, bet, g.PokerTableID, roomTopic) + logMsg := fmt.Sprintf("%s all-in (%d)", pUsername, bet) + if p.isAllIn() { + newlyAllInPlayers = append(newlyAllInPlayers, p) + } + newLogEvent(g, roomLogsTopic, 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 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.Bet + bet) < minBet { + msg := fmt.Sprintf("Bet (%d) is too low. Must bet at least %d", bet, minBet-p.Bet) + PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg}) + return continueGetPlayerEventLoop + } + if bet > p.Cash { + msg := fmt.Sprintf("Bet (%d) is too high. Must bet at most %d", bet, p.Cash) + PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg}) + return continueGetPlayerEventLoop + } + if (p.Bet + bet) > minBet { + lastRaisePlayerIdx = playerToPlayIdx + } + minBet = utils.MaxInt(p.Bet+bet, minBet) + p.doBet(db, bet, g.PokerTableID, roomTopic) + logMsg := fmt.Sprintf("%s bet %d", pUsername, bet) + if p.isAllIn() { + logMsg += " (all-in)" + newlyAllInPlayers = append(newlyAllInPlayers, p) + } + newLogEvent(g, roomLogsTopic, logMsg) + return doNothing + } + // Maximum time allowed for the player to send his action waitCh := time.After(MaxUserCountdown * time.Second) GetPlayerEventLoop: for { // Repeat until we get an event from the player we're interested in var evt PlayerEvent + actionResult := doNothing + + // Check for pre-selected action + if autoAction, ok := autoCache[pUsername]; ok { + if autoAction > NoAction { + time.Sleep(500 * time.Millisecond) + p.LastActionTS = time.Now() + switch autoAction { + case NoAction: + case FoldAction: + actionResult = doFold() + case CheckAction: + actionResult = doCheck() + case CallAction: + actionResult = doCall() + } + } + delete(autoCache, pUsername) + goto checkActionResult + } select { case evt = <-g.PlayersEventCh: - case <-waitCh: - // Waited too long, either auto-check or auto-fold - if p.Bet < minBet { - foldPlayer(p) - newLogEvent(g, roomLogsTopic, fmt.Sprintf("%s auto fold", pUsername)) - - playerAlive-- - if playerAlive == 1 { - break RoundIsSettledLoop - } - break GetPlayerEventLoop - } - newLogEvent(g, roomLogsTopic, fmt.Sprintf("%s auto check", pUsername)) - break GetPlayerEventLoop + case <-waitCh: // Waited too long, either auto-check or auto-fold + actionResult = doTimeout() + goto checkActionResult } if evt.Unsit { @@ -572,89 +697,37 @@ RoundIsSettledLoop: } if evt.Player != pUsername { + handleAutoAction(evt, roomID, autoCache) continue GetPlayerEventLoop } p.LastActionTS = time.Now() if evt.Fold { - foldPlayer(p) - newLogEvent(g, roomLogsTopic, fmt.Sprintf("%s fold", pUsername)) - - playerAlive-- - if playerAlive == 1 { - PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: ""}) - break RoundIsSettledLoop - } + actionResult = doFold() } else if evt.Check { - if p.Bet < minBet { - msg := fmt.Sprintf("Need to bet %d", minBet-p.Bet) - PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg}) - continue GetPlayerEventLoop - } - newLogEvent(g, roomLogsTopic, fmt.Sprintf("%s check", pUsername)) - + actionResult = doCheck() } else if evt.Call { - bet := utils.MinInt(minBet-p.Bet, p.Cash) - if bet == 0 { - newLogEvent(g, roomLogsTopic, fmt.Sprintf("%s check", pUsername)) - } else { - p.doBet(db, bet, g.PokerTableID, roomTopic) - logMsg := fmt.Sprintf("%s call (%d)", pUsername, bet) - if p.isAllIn() { - logMsg += " (all-in)" - newlyAllInPlayers = append(newlyAllInPlayers, p) - } - newLogEvent(g, roomLogsTopic, logMsg) - } - + actionResult = doCall() } else if evt.AllIn { - bet := p.Cash - if (p.Bet + bet) > minBet { - lastRaisePlayerIdx = playerToPlayIdx - } - minBet = utils.MaxInt(p.Bet+bet, minBet) - p.doBet(db, bet, g.PokerTableID, roomTopic) - logMsg := fmt.Sprintf("%s all-in (%d)", pUsername, bet) - if p.isAllIn() { - newlyAllInPlayers = append(newlyAllInPlayers, p) - } - newLogEvent(g, roomLogsTopic, logMsg) - + actionResult = doAllIn() } else if evt.Bet > 0 { - pokerTableMinBet := g.PokerTableMinBet - bet := evt.Bet - // Ensure the player cannot bet below the table minimum bet (amount of the big blind) - if bet < pokerTableMinBet { - msg := fmt.Sprintf("Bet (%d) is too low. Must bet at least %d", bet, pokerTableMinBet) - PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg}) - continue GetPlayerEventLoop - } - if (p.Bet + bet) < minBet { - msg := fmt.Sprintf("Bet (%d) is too low. Must bet at least %d", bet, minBet-p.Bet) - PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg}) - continue GetPlayerEventLoop - } - if bet > p.Cash { - msg := fmt.Sprintf("Bet (%d) is too high. Must bet at most %d", bet, p.Cash) - PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: msg}) - continue GetPlayerEventLoop - } - if (p.Bet + bet) > minBet { - lastRaisePlayerIdx = playerToPlayIdx - } - minBet = utils.MaxInt(p.Bet+bet, minBet) - p.doBet(db, bet, g.PokerTableID, roomTopic) - logMsg := fmt.Sprintf("%s bet %d", pUsername, bet) - if p.isAllIn() { - logMsg += " (all-in)" - newlyAllInPlayers = append(newlyAllInPlayers, p) - } - newLogEvent(g, roomLogsTopic, logMsg) - + actionResult = doBet(evt) } else { + actionResult = continueGetPlayerEventLoop + } + + checkActionResult: + switch actionResult { + case doNothing: + case continueGetPlayerEventLoop: continue GetPlayerEventLoop + case breakGetPlayerEventLoop: + break GetPlayerEventLoop + case breakRoundIsSettledLoop: + break RoundIsSettledLoop } + PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: ""}) break GetPlayerEventLoop } // End of repeat until we get an event from the player we're interested in @@ -707,6 +780,28 @@ RoundIsSettled: return playerAlive <= 1 } +func handleAutoAction(evt PlayerEvent, roomID RoomID, autoCache map[database.Username]int) { + roomUserTopic := roomID.UserTopic(evt.Player) + autoAction := autoCache[evt.Player] + if evt.Fold && autoAction == FoldAction || + evt.Call && autoAction == CallAction || + evt.Check && autoAction == CheckAction { + delete(autoCache, evt.Player) + PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: ""}) + return + } + if evt.Fold { + autoCache[evt.Player] = FoldAction + PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: "Will auto fold"}) + } else if evt.Call { + autoCache[evt.Player] = CallAction + PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: "Will auto call"}) + } else if evt.Check { + autoCache[evt.Player] = CheckAction + PokerPubSub.Pub(roomUserTopic, ErrorMsgEvent{Message: "Will auto check"}) + } +} + type Seat struct { Top int Left int