attempt at fixing deadlock

This commit is contained in:
nak 2026-03-18 05:02:22 +00:00
parent 2836676ff5
commit 68f1db5427

View file

@ -101,21 +101,23 @@ func NewTable(cfg Config) *Table {
// The caller is responsible for deducting from the player's wallet first.
func (t *Table) Sit(username string, seatIndex int, buyin int64) error {
t.mu.Lock()
defer t.mu.Unlock()
if seatIndex < 0 || seatIndex >= len(t.Seats) {
t.mu.Unlock()
return errors.New("invalid seat index")
}
if t.Seats[seatIndex].Username != "" {
t.mu.Unlock()
return errors.New("seat taken")
}
// Check player not already seated
for _, s := range t.Seats {
if s.Username == username {
t.mu.Unlock()
return errors.New("already seated")
}
}
if buyin < t.Config.MinBuyin || buyin > t.Config.MaxBuyin {
t.mu.Unlock()
return fmt.Errorf("buy-in must be between %d and %d", t.Config.MinBuyin, t.Config.MaxBuyin)
}
@ -123,6 +125,7 @@ func (t *Table) Sit(username string, seatIndex int, buyin int64) error {
t.Seats[seatIndex].Stack = buyin
t.Seats[seatIndex].Folded = false
t.Seats[seatIndex].SitOut = false
t.mu.Unlock()
t.broadcastState()
t.maybeStartHand()
@ -133,20 +136,21 @@ func (t *Table) Sit(username string, seatIndex int, buyin int64) error {
// Cannot stand mid-hand unless folded.
func (t *Table) Stand(username string) (int64, error) {
t.mu.Lock()
defer t.mu.Unlock()
seat := t.findSeat(username)
if seat == nil {
t.mu.Unlock()
return 0, errors.New("not seated")
}
// Allow standing mid-hand only if folded or hand is waiting
if t.Hand.Phase != PhaseWaiting && !seat.Folded {
t.mu.Unlock()
return 0, errors.New("cannot stand mid-hand while active")
}
stack := seat.Stack
*seat = Seat{} // clear seat
*seat = Seat{}
t.mu.Unlock()
t.broadcastState()
return stack, nil
}
@ -154,19 +158,23 @@ func (t *Table) Stand(username string) (int64, error) {
// TopUp adds chips to a seated player's stack (between hands only).
func (t *Table) TopUp(username string, amount int64) error {
t.mu.Lock()
defer t.mu.Unlock()
if t.Hand.Phase != PhaseWaiting {
t.mu.Unlock()
return errors.New("can only top up between hands")
}
seat := t.findSeat(username)
if seat == nil {
t.mu.Unlock()
return errors.New("not seated")
}
if seat.Stack+amount > t.Config.MaxBuyin {
t.mu.Unlock()
return fmt.Errorf("would exceed max buy-in of %d", t.Config.MaxBuyin)
}
seat.Stack += amount
t.mu.Unlock()
t.broadcastState()
return nil
}
@ -274,17 +282,19 @@ const (
// Action processes a player's action. Returns an error if invalid.
func (t *Table) Action(username string, action ActionType, amount int64) error {
t.mu.Lock()
defer t.mu.Unlock()
if t.Hand.Phase == PhaseWaiting || t.Hand.Phase == PhaseDealing || t.Hand.Phase == PhaseShowdown {
t.mu.Unlock()
return errors.New("no action in current phase")
}
seatIdx := t.findSeatIndex(username)
if seatIdx < 0 {
t.mu.Unlock()
return errors.New("not seated")
}
if seatIdx != t.Hand.ActionOn {
t.mu.Unlock()
return errors.New("not your turn")
}
@ -298,12 +308,14 @@ func (t *Table) Action(username string, action ActionType, amount int64) error {
case ActionCheck:
if seat.Bet < currentBet {
t.mu.Unlock()
return errors.New("cannot check — must call or raise")
}
case ActionCall:
toCall := currentBet - seat.Bet
if toCall <= 0 {
t.mu.Unlock()
return errors.New("nothing to call — check instead")
}
if toCall > seat.Stack {
@ -315,6 +327,7 @@ func (t *Table) Action(username string, action ActionType, amount int64) error {
case ActionRaise:
if amount < t.Hand.MinRaise {
t.mu.Unlock()
return fmt.Errorf("minimum raise is %d", t.Hand.MinRaise)
}
toCall := currentBet - seat.Bet
@ -330,6 +343,7 @@ func (t *Table) Action(username string, action ActionType, amount int64) error {
t.acted = make(map[string]bool) // raise reopens action
default:
t.mu.Unlock()
return fmt.Errorf("unknown action: %s", action)
}
@ -344,7 +358,6 @@ func (t *Table) Action(username string, action ActionType, amount int64) error {
t.mu.Unlock()
t.broadcastAction(username, action, amount)
t.advance()
t.mu.Lock()
return nil
}