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:
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