commit 5a07623a53ccb4f557c613420dc927cda1eab616
parent e3342c8e7bc0b9e74ead87970cf2641169428cce
Author: n0tr1v <n0tr1v@protonmail.com>
Date: Wed, 6 Dec 2023 16:56:20 -0500
implement dealer index
Diffstat:
2 files changed, 83 insertions(+), 7 deletions(-)
diff --git a/pkg/web/handlers/poker/poker.go b/pkg/web/handlers/poker/poker.go
@@ -47,6 +47,7 @@ func (p *Poker) GetOrCreateGame(roomID string) *PokerGame {
g = &PokerGame{
PlayersEventCh: make(chan PlayerEvent),
Players: make([]*PokerStandingPlayer, NbPlayers),
+ DealerIdx: -1,
}
p.games[roomID] = g
}
@@ -96,6 +97,7 @@ type PokerPlayer struct {
Username string
Bet int
Cash int
+ SeatIdx int
Cards []PlayerCard
CardsMtx sync.RWMutex
Folded bool
@@ -112,6 +114,7 @@ type PokerGame struct {
Players []*PokerStandingPlayer
Ongoing *Ongoing
DealerIdx int
+ DealerIdxMtx sync.RWMutex
IsGameDone atomic.Bool
IsGameOver atomic.Bool
}
@@ -167,6 +170,32 @@ func isRoundSettled(players []*PokerPlayer) bool {
return allSettled
}
+func (g *PokerGame) incrDealerIdx() {
+ g.DealerIdxMtx.RLock()
+ dealerIdx := g.DealerIdx
+ g.DealerIdxMtx.RUnlock()
+ var found bool
+ for i := dealerIdx + 1; i < len(g.Players); i++ {
+ if g.Players[i] != nil {
+ dealerIdx = i
+ found = true
+ break
+ }
+ }
+ if !found {
+ for i := 0; i < dealerIdx; i++ {
+ if g.Players[i] != nil {
+ dealerIdx = i
+ found = true
+ break
+ }
+ }
+ }
+ g.DealerIdxMtx.Lock()
+ g.DealerIdx = dealerIdx
+ g.DealerIdxMtx.Unlock()
+}
+
func (g *PokerGame) SitPlayer(authUser *database.User, pos int) error {
if g.Players[pos] != nil {
return errors.New("seat already taken")
@@ -188,7 +217,7 @@ func NewOngoing(g *PokerGame) *Ongoing {
for idx, p := range g.Players {
var player *PokerPlayer
if p != nil && p.Cash > 0 {
- player = &PokerPlayer{Username: p.Username, Cash: p.Cash}
+ player = &PokerPlayer{Username: p.Username, Cash: p.Cash, SeatIdx: idx}
}
players[idx] = player
}
@@ -206,12 +235,26 @@ func newLogEvent(g *PokerGame, roomLogsTopic, msg string) {
}
}
+func reorderPlayers[T any](players []T, dealerIdx int) (out []T) {
+ for i := dealerIdx; i < len(players); i++ {
+ out = append(out, players[i])
+ }
+ for i := 0; i < dealerIdx; i++ {
+ out = append(out, players[i])
+ }
+ return
+}
+
// Return either or not the game ended because only 1 player left playing
func waitPlayersActionFn(g *PokerGame, roomID string) bool {
roomTopic := "room_" + roomID
lastRisePlayerIdx := -1
minBet := 0
+ g.DealerIdxMtx.RLock()
+ dealerIdx := g.DealerIdx
+ g.DealerIdxMtx.RUnlock()
+
playerAlive := 0
for _, p := range g.Ongoing.Players {
if p != nil && !p.Folded {
@@ -222,11 +265,12 @@ func waitPlayersActionFn(g *PokerGame, roomID string) bool {
// TODO: implement maximum re-rise
OUTER:
for { // Loop until the round is settled
- for i, p := range g.Ongoing.Players {
+ players := reorderPlayers(g.Ongoing.Players, dealerIdx)
+ for _, p := range players {
if p == nil {
continue
}
- if i == lastRisePlayerIdx {
+ if p.SeatIdx == lastRisePlayerIdx {
break OUTER
}
player := g.Ongoing.GetPlayer(p.Username)
@@ -236,7 +280,7 @@ OUTER:
if player.Cash == 0 {
continue
}
- evt := PokerWaitTurnEvent{Idx: i}
+ evt := PokerWaitTurnEvent{Idx: p.SeatIdx}
PokerPubSub.Pub(roomTopic, evt)
g.Ongoing.WaitTurnEventMtx.Lock()
@@ -322,7 +366,7 @@ OUTER:
p.Bet += bet
p.Cash -= bet
}
- PokerPubSub.Pub(roomTopic, PlayerBetEvent{PlayerIdx: i, Player: p.Username, Bet: bet, TotalBet: p.Bet, Cash: p.Cash})
+ PokerPubSub.Pub(roomTopic, PlayerBetEvent{PlayerIdx: p.SeatIdx, Player: p.Username, Bet: bet, TotalBet: p.Bet, Cash: p.Cash})
newLogEvent(g, roomLogsTopic, fmt.Sprintf("%s call", p.Username))
} else if evt.Bet > 0 {
@@ -332,12 +376,12 @@ OUTER:
continue
}
if (p.Bet + evt.Bet) > minBet {
- lastRisePlayerIdx = i
+ lastRisePlayerIdx = p.SeatIdx
}
minBet = p.Bet + evt.Bet
p.Bet += evt.Bet
p.Cash -= evt.Bet
- PokerPubSub.Pub(roomTopic, PlayerBetEvent{PlayerIdx: i, Player: p.Username, Bet: evt.Bet, TotalBet: p.Bet, Cash: p.Cash})
+ PokerPubSub.Pub(roomTopic, PlayerBetEvent{PlayerIdx: p.SeatIdx, Player: p.Username, Bet: evt.Bet, TotalBet: p.Bet, Cash: p.Cash})
newLogEvent(g, roomLogsTopic, fmt.Sprintf("%s bet %d", p.Username, evt.Bet))
} else {
@@ -387,6 +431,8 @@ func dealerThread(db *database.DkfDB, g *PokerGame, roomID string) {
var winnerHand string
var minScore int32 = math.MaxInt32
+ g.incrDealerIdx()
+
type Seat struct {
Top int
Left int
diff --git a/pkg/web/handlers/poker/poker_test.go b/pkg/web/handlers/poker/poker_test.go
@@ -0,0 +1,30 @@
+package poker
+
+import (
+ "reflect"
+ "testing"
+)
+
+func Test_reorderPlayers(t *testing.T) {
+ type args[T any] struct {
+ players []T
+ dealerIdx int
+ }
+ type testCase[T any] struct {
+ name string
+ args args[T]
+ wantOut []T
+ }
+ tests := []testCase[int]{
+ {"1", args[int]{[]int{1, 2, 3, 4, 5, 6}, 0}, []int{1, 2, 3, 4, 5, 6}},
+ {"2", args[int]{[]int{1, 2, 3, 4, 5, 6}, 1}, []int{2, 3, 4, 5, 6, 1}},
+ {"2", args[int]{[]int{1, 2, 3, 4, 5, 6}, 5}, []int{6, 1, 2, 3, 4, 5}},
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if gotOut := reorderPlayers(tt.args.players, tt.args.dealerIdx); !reflect.DeepEqual(gotOut, tt.wantOut) {
+ t.Errorf("reorderPlayers() = %v, want %v", gotOut, tt.wantOut)
+ }
+ })
+ }
+}