dkforest

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

commit 264dcc30a67e6a00881aba57e8c7b9a7060756a2
parent d02757a0fdb7667e5d84eb732a6426e68dcfb879
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Sat, 23 Dec 2023 00:04:41 -0500

cleanup

Diffstat:
Mpkg/web/handlers/poker.go | 109+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mpkg/web/handlers/poker/events.go | 4++++
Mpkg/web/handlers/poker/poker.go | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
3 files changed, 125 insertions(+), 72 deletions(-)

diff --git a/pkg/web/handlers/poker.go b/pkg/web/handlers/poker.go @@ -446,74 +446,89 @@ func PokerBetHandler(c echo.Context) error { return c.Redirect(http.StatusFound, "/") } + roomUserTopic := roomID.UserTopic(authUser.ID) + sub := poker.PokerPubSub.Subscribe([]string{roomUserTopic}) + defer sub.Close() + quit := hutils.CloseSignalChan(c) + hutils.SetStreamingHeaders(c) + + // Keep track of users streams, so we can limit how many are open at one time per user + if err := usersStreamsManager.Inst.Add(authUser.ID, roomUserTopic); err != nil { + return nil + } + defer usersStreamsManager.Inst.Remove(authUser.ID, roomUserTopic) + if c.Request().Method == http.MethodPost { submitBtn := c.Request().PostFormValue("submitBtn") if submitBtn == "check" { g.Check(authUser.ID) - return c.Redirect(http.StatusFound, c.Request().Referer()) } else if submitBtn == "call" { g.Call(authUser.ID) - return c.Redirect(http.StatusFound, c.Request().Referer()) } else if submitBtn == "fold" { g.Fold(authUser.ID) - return c.Redirect(http.StatusFound, c.Request().Referer()) } else if submitBtn == "allIn" { g.AllIn(authUser.ID) - return c.Redirect(http.StatusFound, c.Request().Referer()) } else { raiseBtn := c.Request().PostFormValue("raise") if raiseBtn == "raise" { g.Raise(authUser.ID) - return c.Redirect(http.StatusFound, c.Request().Referer()) } else if raiseBtn == "raiseValue" { raiseValue := database.PokerChip(utils.DoParseUint64(c.Request().PostFormValue("raiseValue"))) g.Bet(authUser.ID, raiseValue) - return c.Redirect(http.StatusFound, c.Request().Referer()) } } - } - - roomUserTopic := roomID.UserTopic(authUser.ID) - sub := poker.PokerPubSub.Subscribe([]string{roomUserTopic}) - defer sub.Close() - quit := hutils.CloseSignalChan(c) - hutils.SetStreamingHeaders(c) - - // Keep track of users streams, so we can limit how many are open at one time per user - if err := usersStreamsManager.Inst.Add(authUser.ID, roomUserTopic); err != nil { - return nil - } - defer usersStreamsManager.Inst.Remove(authUser.ID, roomUserTopic) - - send(hutils.HtmlCssReset) + send(`<style>#actionsForm { display: none; }</style>`) + c.Response().Flush() - if player := g.OngoingPlayer(authUser.ID); player != nil { - canCheck := g.CanCheck(player) - canFold := g.CanFold(player) - playerBet := player.GetBet() - betBtnLbl := utils.Ternary(g.IsBet(), "Bet", "Raise") - minBet := g.MinBet() - minRaise := g.MinRaise() - send(`<form method="post">`) - send(` <div style="display: inline-block; margin-right: 20px;">`) - send(fmt.Sprintf(`<input type="number" name="raiseValue" value="%s" min="%s" style="width: 90px;" /><button type="submit" name="raise" value="raiseValue">%s</button><br />`, minRaise, minRaise, betBtnLbl)) - send(` </div>`) - send(` <div style="display: inline-block; vertical-align: top;">`) - if canCheck { - send(` <button name="submitBtn" value="check">Check</button>`) - } - if minBet-playerBet > 0 { - send(` <button name="submitBtn" value="call">Call</button>`) - } - if canFold { - send(` <button name="submitBtn" value="fold">Fold</button>`) - } - send(` <button name="submitBtn" value="allIn">All-in</button>`) - send(` </div>`) - send(`</form>`) - send(fmt.Sprintf(`<div style="margin-top: 4px;">Min raise: %d</div>`, minRaise)) + } else { + + send(hutils.HtmlCssReset) + + if player := g.OngoingPlayer(authUser.ID); player != nil { + if !g.IsYourTurn(player) { + betBtnLbl := utils.Ternary(g.IsBet(), "Bet", "Raise") + minRaise := g.MinRaise() + send(`<form method="post" id="actionsForm">`) + send(` <div style="display: inline-block; margin-right: 20px;">`) + send(fmt.Sprintf(`<input type="number" name="raiseValue" value="%s" min="%s" style="width: 90px;" /><button type="submit" name="raise" value="raiseValue">%s</button><br />`, minRaise, minRaise, betBtnLbl)) + send(` </div>`) + send(` <div style="display: inline-block; vertical-align: top;">`) + send(` <button name="submitBtn" value="check">Check</button>`) + send(` <button name="submitBtn" value="call">Call</button>`) + send(` <button name="submitBtn" value="fold">Fold</button>`) + send(` <button name="submitBtn" value="allIn">All-in</button>`) + send(` </div>`) + send(`</form>`) + send(fmt.Sprintf(`<div style="margin-top: 4px; font-size: 20px; font-family: Arial,Helvetica,sans-serif; font-size: 18px;">Min raise: %d</div>`, minRaise)) + } else { + canCheck := g.CanCheck(player) + canFold := g.CanFold(player) + playerBet := player.GetBet() + betBtnLbl := utils.Ternary(g.IsBet(), "Bet", "Raise") + minBet := g.MinBet() + minRaise := g.MinRaise() + send(`<form method="post" id="actionsForm">`) + send(` <div style="display: inline-block; margin-right: 20px;">`) + send(fmt.Sprintf(`<input type="number" name="raiseValue" value="%s" min="%s" style="width: 90px;" /><button type="submit" name="raise" value="raiseValue">%s</button><br />`, minRaise, minRaise, betBtnLbl)) + send(` </div>`) + send(` <div style="display: inline-block; vertical-align: top;">`) + if canCheck { + send(` <button name="submitBtn" value="check">Check</button>`) + } + if minBet-playerBet > 0 { + send(` <button name="submitBtn" value="call">Call</button>`) + } + if canFold { + send(` <button name="submitBtn" value="fold">Fold</button>`) + } + send(` <button name="submitBtn" value="allIn">All-in</button>`) + send(` </div>`) + send(`</form>`) + send(fmt.Sprintf(`<div style="margin-top: 4px; font-size: 20px; font-family: Arial,Helvetica,sans-serif; font-size: 18px;">Min raise: %d</div>`, minRaise)) + } + } + c.Response().Flush() } - c.Response().Flush() Loop: for { diff --git a/pkg/web/handlers/poker/events.go b/pkg/web/handlers/poker/events.go @@ -56,6 +56,10 @@ type PlayerFoldEvent struct { Card1Idx, Card2Idx int } +type PokerMinRaiseUpdatedEvent struct { + MinRaise database.PokerChip +} + type PokerMainPotUpdatedEvent struct { MainPot database.PokerChip } diff --git a/pkg/web/handlers/poker/poker.go b/pkg/web/handlers/poker/poker.go @@ -24,7 +24,7 @@ import ( const NbPlayers = 6 const MaxUserCountdown = 60 -const MinTimeAfterGame = 1 +const MinTimeAfterGame = 10 const BackfacingDeg = "-180deg" const BurnStackX = 400 const BurnStackY = 30 @@ -34,7 +34,7 @@ const DealSpacing = 55 const DealerStackX = 250 const DealerStackY = 30 const NbCardsPerPlayer = 2 -const animationTime = 100 * time.Millisecond +const animationTime = 1000 * time.Millisecond type Poker struct { sync.Mutex @@ -137,6 +137,7 @@ type ongoingGame struct { autoActionEvent rwmtx.RWMtx[AutoActionEvent] MinBet rwmtx.RWMtx[database.PokerChip] MinRaise rwmtx.RWMtx[database.PokerChip] + playerToPlay rwmtx.RWMtx[database.UserID] hasBet rwmtx.RWMtx[bool] players pokerPlayers createdAt time.Time @@ -234,6 +235,13 @@ func (g *PokerGame) IsBet() (out bool) { return } +func (g *PokerGame) IsYourTurn(player *pokerPlayer) (out bool) { + if g.ongoing != nil { + return player.userID == g.ongoing.playerToPlay.Get() + } + return +} + func (g *PokerGame) CanCheck(player *pokerPlayer) (out bool) { if g.ongoing != nil { return player.bet.Get() == g.ongoing.MinBet.Get() @@ -386,6 +394,10 @@ func (g *ongoingGame) getMainPot() (out database.PokerChip) { return database.PokerChip(g.mainPot.Load()) } +func (g *ongoingGame) getMinRaise() (out database.PokerChip) { + return g.MinRaise.Get() +} + func (g *ongoingGame) setMainPot(v database.PokerChip) { g.mainPot.Store(uint64(v)) } @@ -811,13 +823,13 @@ func doFold(g *PokerGame, p *pokerPlayer, playerAlive *int) int { } func doCall(g *PokerGame, p *pokerPlayer, - newlyAllInPlayers *[]*pokerPlayer, lastBetPlayerIdx, lastRaisePlayerIdx *int, playerToPlayIdx int) int { + newlyAllInPlayers *[]*pokerPlayer, lastBetPlayerIdx *int, playerToPlayIdx int) int { pUsername := p.username bet := utils.MinInt(g.ongoing.MinBet.Get()-p.GetBet(), p.getCash()) if bet == 0 { return doCheck(g, p) } else if bet == p.cash.Get() { - return doAllIn(g, p, newlyAllInPlayers, lastBetPlayerIdx, lastRaisePlayerIdx, playerToPlayIdx) + return doAllIn(g, p, newlyAllInPlayers, lastBetPlayerIdx, playerToPlayIdx) } else { p.status.Set("call") p.doBetAndNotif(g.db, g.pokerTableID, bet, g.roomID.Topic()) @@ -828,13 +840,13 @@ func doCall(g *PokerGame, p *pokerPlayer, } func doAllIn(g *PokerGame, p *pokerPlayer, - newlyAllInPlayers *[]*pokerPlayer, lastBetPlayerIdx, lastRaisePlayerIdx *int, playerToPlayIdx int) int { + newlyAllInPlayers *[]*pokerPlayer, lastBetPlayerIdx *int, playerToPlayIdx int) int { bet := p.getCash() minBet := g.ongoing.MinBet.Get() if (p.GetBet() + bet) > minBet { *lastBetPlayerIdx = playerToPlayIdx - *lastRaisePlayerIdx = playerToPlayIdx g.ongoing.MinRaise.Set(bet) + PokerPubSub.Pub(g.roomID.Topic(), PokerMinRaiseUpdatedEvent{MinRaise: bet}) } g.ongoing.MinBet.Set(utils.MaxInt(p.GetBet()+bet, minBet)) p.doBetAndNotif(g.db, g.pokerTableID, bet, g.roomID.Topic()) @@ -848,13 +860,13 @@ func doAllIn(g *PokerGame, p *pokerPlayer, } func doRaise(g *PokerGame, p *pokerPlayer, - newlyAllInPlayers *[]*pokerPlayer, lastBetPlayerIdx, lastRaisePlayerIdx *int, playerToPlayIdx int, evt playerEvent) int { + newlyAllInPlayers *[]*pokerPlayer, lastBetPlayerIdx *int, playerToPlayIdx int, evt playerEvent) int { evt.Bet = g.ongoing.MinRaise.Get() - return doBet(g, p, newlyAllInPlayers, lastBetPlayerIdx, lastRaisePlayerIdx, playerToPlayIdx, evt) + return doBet(g, p, newlyAllInPlayers, lastBetPlayerIdx, playerToPlayIdx, evt) } func doBet(g *PokerGame, p *pokerPlayer, - newlyAllInPlayers *[]*pokerPlayer, lastBetPlayerIdx, lastRaisePlayerIdx *int, playerToPlayIdx int, evt playerEvent) int { + newlyAllInPlayers *[]*pokerPlayer, lastBetPlayerIdx *int, playerToPlayIdx int, evt playerEvent) int { roomTopic := g.roomID.Topic() roomUserTopic := g.roomID.UserTopic(p.userID) minBet := g.ongoing.MinBet.Get() @@ -862,7 +874,7 @@ func doBet(g *PokerGame, p *pokerPlayer, playerBet := p.bet.Get() bet := evt.Bet + (minBet - playerBet) if bet >= p.cash.Get() { - return doAllIn(g, p, newlyAllInPlayers, lastBetPlayerIdx, lastRaisePlayerIdx, playerToPlayIdx) + return doAllIn(g, p, newlyAllInPlayers, lastBetPlayerIdx, playerToPlayIdx) } playerTotalBet := playerBet + bet betLbl := utils.Ternary(g.IsBet(), "bet", "raise") @@ -878,7 +890,7 @@ func doBet(g *PokerGame, p *pokerPlayer, return continueGetPlayerEventLoop } *lastBetPlayerIdx = playerToPlayIdx - *lastRaisePlayerIdx = playerToPlayIdx + PokerPubSub.Pub(g.roomID.Topic(), PokerMinRaiseUpdatedEvent{MinRaise: evt.Bet}) g.ongoing.MinRaise.Set(evt.Bet) g.ongoing.MinBet.Set(playerTotalBet) @@ -924,14 +936,14 @@ func handleAutoActionReceived(g *PokerGame, autoCache map[database.UserID]autoAc func applyAutoAction(g *PokerGame, p *pokerPlayer, newlyAllInPlayers *[]*pokerPlayer, - lastBetPlayerIdx, lastRaisePlayerIdx, playerAlive *int, playerToPlayIdx int, autoAction autoAction, + lastBetPlayerIdx, playerAlive *int, playerToPlayIdx int, autoAction autoAction, autoCache map[database.UserID]autoAction) (actionResult int) { pUserID := p.userID roomUserTopic := g.roomID.UserTopic(pUserID) if autoAction.action > NoAction { time.Sleep(500 * time.Millisecond) - actionResult = handlePlayerActionEvent(g, p, newlyAllInPlayers, lastBetPlayerIdx, lastRaisePlayerIdx, playerAlive, playerToPlayIdx, autoAction.evt) + actionResult = handlePlayerActionEvent(g, p, newlyAllInPlayers, lastBetPlayerIdx, playerAlive, playerToPlayIdx, autoAction.evt) } delete(autoCache, pUserID) setAutoAction(g, roomUserTopic, "") @@ -940,7 +952,7 @@ func applyAutoAction(g *PokerGame, p *pokerPlayer, func handlePlayerActionEvent(g *PokerGame, p *pokerPlayer, newlyAllInPlayers *[]*pokerPlayer, - lastBetPlayerIdx, lastRaisePlayerIdx, playerAlive *int, playerToPlayIdx int, evt playerEvent) (actionResult int) { + lastBetPlayerIdx, playerAlive *int, playerToPlayIdx int, evt playerEvent) (actionResult int) { p.lastActionTS = time.Now() if evt.Fold { @@ -948,13 +960,13 @@ func handlePlayerActionEvent(g *PokerGame, p *pokerPlayer, } else if evt.Check { actionResult = doCheck(g, p) } else if evt.Call { - actionResult = doCall(g, p, newlyAllInPlayers, lastBetPlayerIdx, lastRaisePlayerIdx, playerToPlayIdx) + actionResult = doCall(g, p, newlyAllInPlayers, lastBetPlayerIdx, playerToPlayIdx) } else if evt.AllIn { - actionResult = doAllIn(g, p, newlyAllInPlayers, lastBetPlayerIdx, lastRaisePlayerIdx, playerToPlayIdx) + actionResult = doAllIn(g, p, newlyAllInPlayers, lastBetPlayerIdx, playerToPlayIdx) } else if evt.Raise { - actionResult = doRaise(g, p, newlyAllInPlayers, lastBetPlayerIdx, lastRaisePlayerIdx, playerToPlayIdx, evt) + actionResult = doRaise(g, p, newlyAllInPlayers, lastBetPlayerIdx, playerToPlayIdx, evt) } else if evt.Bet > 0 { - actionResult = doBet(g, p, newlyAllInPlayers, lastBetPlayerIdx, lastRaisePlayerIdx, playerToPlayIdx, evt) + actionResult = doBet(g, p, newlyAllInPlayers, lastBetPlayerIdx, playerToPlayIdx, evt) } else { actionResult = continueGetPlayerEventLoop } @@ -963,15 +975,15 @@ func handlePlayerActionEvent(g *PokerGame, p *pokerPlayer, // 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 { + roomID := g.roomID + roomTopic := roomID.Topic() g.ongoing.MinBet.Set(minBet) g.ongoing.MinRaise.Set(g.PokerTableMinBet) + PokerPubSub.Pub(roomTopic, PokerMinRaiseUpdatedEvent{MinRaise: g.PokerTableMinBet}) db := g.db ongoing := g.ongoing - roomID := g.roomID - roomTopic := roomID.Topic() _, dealerIdx := ongoing.getPlayerBySeatIdx(int(g.dealerSeatIdx.Load())) playerToPlayIdx := (dealerIdx + skip) % len(ongoing.players) - lastRaisePlayerIdx := -1 lastBetPlayerIdx := -1 newlyAllInPlayers := make([]*pokerPlayer, 0) autoCache := make(map[database.UserID]autoAction) @@ -1000,6 +1012,7 @@ RoundIsSettledLoop: for { // Repeat until all players have played playerToPlayIdx = (playerToPlayIdx + 1) % len(ongoing.players) p := ongoing.players[playerToPlayIdx] + g.ongoing.playerToPlay.Set(p.userID) p.countChancesToAction++ pUserID := p.userID roomUserTopic := roomID.UserTopic(pUserID) @@ -1007,7 +1020,6 @@ RoundIsSettledLoop: if playerToPlayIdx == lastBetPlayerIdx { break AllPlayersLoop } - lastRaisePlayerIdx = utils.Ternary(lastRaisePlayerIdx == -1, playerToPlayIdx, lastRaisePlayerIdx) lastBetPlayerIdx = utils.Ternary(lastBetPlayerIdx == -1, playerToPlayIdx, lastBetPlayerIdx) if !p.canBet() { continue AllPlayersLoop @@ -1029,7 +1041,7 @@ RoundIsSettledLoop: // Check for pre-selected action if autoActionVal, ok := autoCache[pUserID]; ok { actionResult = applyAutoAction(g, p, &newlyAllInPlayers, - &lastBetPlayerIdx, &lastRaisePlayerIdx, &playerAlive, playerToPlayIdx, autoActionVal, autoCache) + &lastBetPlayerIdx, &playerAlive, playerToPlayIdx, autoActionVal, autoCache) goto checkActionResult } select { @@ -1047,7 +1059,7 @@ RoundIsSettledLoop: goto checkActionResult } actionResult = handlePlayerActionEvent(g, p, &newlyAllInPlayers, - &lastBetPlayerIdx, &lastRaisePlayerIdx, &playerAlive, playerToPlayIdx, evt) + &lastBetPlayerIdx, &playerAlive, playerToPlayIdx, evt) goto checkActionResult checkActionResult: @@ -1700,6 +1712,8 @@ func BuildPayloadHtml(g *PokerGame, authUser *database.User, payload any) (html html += getPokerEventHtml(evt, animationTime.String()) case PokerMainPotUpdatedEvent: html += drawMainPotHtml(evt) + case PokerMinRaiseUpdatedEvent: + html += drawMinRaiseHtml(evt) } return } @@ -1713,6 +1727,7 @@ func buildGameDiv(g *PokerGame, authUser *database.User) (html string) { html += buildActionsDiv(roomID) html += buildDealerTokenHtml(g) html += buildMainPotHtml(g) + html += buildMinRaiseHtml(g) html += buildWinnerHtml() html += buildCountdownsHtml() html += `</div>` @@ -1791,6 +1806,17 @@ func buildMainPotHtml(g *PokerGame) string { return html } +func buildMinRaiseHtml(g *PokerGame) string { + ongoing := g.ongoing + html := `<div id="minRaise"></div>` + minRaise := uint64(0) + if ongoing != nil { + minRaise = uint64(ongoing.getMinRaise()) + } + html += `<style>#minRaise:before { content: "Min raise: ` + itoa1(minRaise) + `"; }</style>` + return html +} + func buildCountdownsHtml() (html string) { for i := 1; i <= NbPlayers; i++ { idxStr := itoa(i) @@ -2030,6 +2056,13 @@ func drawMainPotHtml(evt PokerMainPotUpdatedEvent) (html string) { return } +func drawMinRaiseHtml(evt PokerMinRaiseUpdatedEvent) (html string) { + html += `<style>` + html += `#minRaise:before { content: "Min raise: ` + itoa2(evt.MinRaise) + `"; }` + html += `</style>` + return +} + func getPokerEventHtml(payload PokerEvent, animationTime string) string { transform := `transform: translate(` + itoa(payload.Left) + `px, ` + itoa(payload.Top) + `px)` transform += utils.Ternary(payload.Angle != "", ` rotateZ(`+payload.Angle+`)`, ``) @@ -2305,7 +2338,8 @@ body { #countdown4 { top: 404px; left: 375px; position: absolute; display: none; z-index: 100; } #countdown5 { top: 404px; left: 185px; position: absolute; display: none; z-index: 100; } #countdown6 { top: 419px; left: 59px; position: absolute; display: none; z-index: 100; } -#mainPot { position: absolute; top: 220px; left: 250px; font-size: 20px; font-family: Arial,Helvetica,sans-serif; } +#mainPot { position: absolute; top: 220px; left: 215px; font-size: 20px; font-family: Arial,Helvetica,sans-serif; } +#minRaise { position: absolute; top: 220px; left: 365px; font-size: 18px; font-family: Arial,Helvetica,sans-serif; } #winner { position: absolute; top: 265px; left: 250px; } #errorMsg { margin-top: 10px;