diff options
| author | historia <[not public]> | 2026-08-07 05:02:39 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-08-07 05:02:39 -0400 |
| commit | 9a716a7d2ce514f452b425caedc1a9a15cde09f0 (patch) | |
| tree | de980f16c4af93512a1616e6521275fd62aca542 /internal/casino/manager.go | |
| parent | 0f008790f192a491ac3901d54b506b756f57fef8 (diff) | |
| download | thehouseoficarus-9a716a7d2ce514f452b425caedc1a9a15cde09f0.tar.gz | |
feat: disconnect forfeits bet and frees up seat
Diffstat (limited to 'internal/casino/manager.go')
| -rw-r--r-- | internal/casino/manager.go | 137 |
1 files changed, 66 insertions, 71 deletions
diff --git a/internal/casino/manager.go b/internal/casino/manager.go index 60bf14d..a9bab92 100644 --- a/internal/casino/manager.go +++ b/internal/casino/manager.go @@ -22,6 +22,10 @@ func NewManager(seed int64) *Manager { } } +func tableKey(roomID int, tableID string) string { + return fmt.Sprintf("%d:%s", roomID, tableID) +} + func (m *Manager) EnsureMachine(roomID int, cfg MachineConfig) *Machine { cfg = cfg.Normalize() key := tableKey(roomID, cfg.ID) @@ -35,10 +39,8 @@ func (m *Manager) EnsureMachine(roomID int, cfg MachineConfig) *Machine { return machine } -func tableKey(roomID int, tableID string) string { - return fmt.Sprintf("%d:%s", roomID, tableID) -} - +// EnsureTable returns the table for cfg, or nil when cfg.Game has no +// multiplayer table implementation. func (m *Manager) EnsureTable(roomID int, cfg TableConfig) *Table { cfg = cfg.Normalize() key := tableKey(roomID, cfg.ID) @@ -48,6 +50,9 @@ func (m *Manager) EnsureTable(roomID int, cfg TableConfig) *Table { return table } table := newTable(roomID, cfg, m.rng) + if table == nil { + return nil + } m.tables[key] = table return table } @@ -58,13 +63,30 @@ func (m *Manager) Table(roomID int, tableID string) *Table { return m.tables[tableKey(roomID, tableID)] } -func (m *Manager) Tick() []Event { +// snapshotTables copies the live table list under the lock so callers can +// iterate without holding it (table methods take their own locks). +func (m *Manager) snapshotTables() []*Table { m.mu.Lock() tables := make([]*Table, 0, len(m.tables)) for _, table := range m.tables { tables = append(tables, table) } m.mu.Unlock() + return tables +} + +func (m *Manager) snapshotMachines() []*Machine { + m.mu.Lock() + machines := make([]*Machine, 0, len(m.machines)) + for _, machine := range m.machines { + machines = append(machines, machine) + } + m.mu.Unlock() + return machines +} + +func (m *Manager) Tick() []Event { + tables := m.snapshotTables() sort.Slice(tables, func(i, j int) bool { if tables[i].RoomID != tables[j].RoomID { return tables[i].RoomID < tables[j].RoomID @@ -75,12 +97,7 @@ func (m *Manager) Tick() []Event { for _, table := range tables { events = append(events, table.tick()...) } - m.mu.Lock() - machines := make([]*Machine, 0, len(m.machines)) - for _, machine := range m.machines { - machines = append(machines, machine) - } - m.mu.Unlock() + machines := m.snapshotMachines() sort.Slice(machines, func(i, j int) bool { if machines[i].RoomID != machines[j].RoomID { return machines[i].RoomID < machines[j].RoomID @@ -93,62 +110,61 @@ func (m *Manager) Tick() []Event { return events } -func (m *Manager) JoinMachine(roomID int, cfg MachineConfig, name string) []Event { - return m.EnsureMachine(roomID, cfg).join(name) -} - -func (m *Manager) SetMachineBet(roomID int, machineID, name string, amount int, wallet Wallet) []Event { +// withMachine runs fn against the named machine when it exists. +func (m *Manager) withMachine(roomID int, machineID string, fn func(*Machine) []Event) []Event { m.mu.Lock() machine := m.machines[tableKey(roomID, machineID)] m.mu.Unlock() if machine == nil { return nil } - return machine.setBet(name, amount, wallet) + return fn(machine) +} + +func (m *Manager) JoinMachine(roomID int, cfg MachineConfig, name string) []Event { + return m.EnsureMachine(roomID, cfg).join(name) +} + +func (m *Manager) SetMachineBet(roomID int, machineID, name string, amount int, wallet Wallet) []Event { + return m.withMachine(roomID, machineID, func(machine *Machine) []Event { + return machine.setBet(name, amount, wallet) + }) } func (m *Manager) StartMachine(roomID int, machineID, name string, wallet Wallet) []Event { - m.mu.Lock() - machine := m.machines[tableKey(roomID, machineID)] - m.mu.Unlock() - if machine == nil { - return nil - } - return machine.start(name, wallet) + return m.withMachine(roomID, machineID, func(machine *Machine) []Event { + return machine.start(name, wallet) + }) } func (m *Manager) EnableMachineAutoBet(roomID int, machineID, name string, wallet Wallet) []Event { - m.mu.Lock() - machine := m.machines[tableKey(roomID, machineID)] - m.mu.Unlock() - if machine == nil { - return nil - } - return machine.enableAutoBet(name, wallet) + return m.withMachine(roomID, machineID, func(machine *Machine) []Event { + return machine.enableAutoBet(name, wallet) + }) } func (m *Manager) StopMachineAutoBet(roomID int, machineID, name string) ([]Event, bool) { - m.mu.Lock() - machine := m.machines[tableKey(roomID, machineID)] - m.mu.Unlock() - if machine == nil { - return nil, false - } - return machine.stopAutoBet(name) + stopped := false + events := m.withMachine(roomID, machineID, func(machine *Machine) []Event { + events, ok := machine.stopAutoBet(name) + stopped = ok + return events + }) + return events, stopped } func (m *Manager) LeaveMachine(roomID int, machineID, name string) []Event { - m.mu.Lock() - machine := m.machines[tableKey(roomID, machineID)] - m.mu.Unlock() - if machine == nil { - return nil - } - return machine.leave(name) + return m.withMachine(roomID, machineID, func(machine *Machine) []Event { + return machine.leave(name) + }) } func (m *Manager) Join(roomID int, cfg TableConfig, name string) []Event { - return m.EnsureTable(roomID, cfg).join(name) + table := m.EnsureTable(roomID, cfg) + if table == nil { + return []Event{{RoomID: roomID, TableID: cfg.ID, Type: EventResult, PrivateTo: name, Message: "That game is not available here."}} + } + return table.join(name) } func (m *Manager) Leave(roomID int, tableID, name string) []Event { @@ -179,40 +195,19 @@ func (m *Manager) Rebet(roomID int, tableID, name string) (string, int) { return "", 0 } +// MarkDisconnected removes the player from every table and machine, +// forfeiting any wager they had committed, so seats free up immediately. func (m *Manager) MarkDisconnected(name string) []Event { - m.mu.Lock() - tables := make([]*Table, 0, len(m.tables)) - for _, table := range m.tables { - tables = append(tables, table) - } - m.mu.Unlock() var events []Event - for _, table := range tables { + for _, table := range m.snapshotTables() { events = append(events, table.markDisconnected(name)...) } - m.mu.Lock() - machines := make([]*Machine, 0, len(m.machines)) - for _, machine := range m.machines { - machines = append(machines, machine) - } - m.mu.Unlock() - for _, machine := range machines { + for _, machine := range m.snapshotMachines() { events = append(events, machine.markDisconnected(name)...) } return events } -func (m *Manager) MarkConnected(name string) { - m.mu.Lock() - defer m.mu.Unlock() - for _, table := range m.tables { - table.markConnected(name) - } - for _, machine := range m.machines { - machine.markConnected(name) - } -} - func (m *Manager) Participation(name string) (*Table, bool) { m.mu.Lock() defer m.mu.Unlock() |
