dkforest

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

commit 5a07623a53ccb4f557c613420dc927cda1eab616
parent e3342c8e7bc0b9e74ead87970cf2641169428cce
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Wed,  6 Dec 2023 16:56:20 -0500

implement dealer index

Diffstat:
Mpkg/web/handlers/poker/poker.go | 60+++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Apkg/web/handlers/poker/poker_test.go | 30++++++++++++++++++++++++++++++
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) + } + }) + } +}