diff options
Diffstat (limited to 'internal/casino/manager.go')
| -rw-r--r-- | internal/casino/manager.go | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/internal/casino/manager.go b/internal/casino/manager.go new file mode 100644 index 0000000..d6a3825 --- /dev/null +++ b/internal/casino/manager.go @@ -0,0 +1,238 @@ +package casino + +import ( + "fmt" + "math/rand" + "sort" + "sync" +) + +type Manager struct { + mu sync.Mutex + tables map[string]*Table + machines map[string]*Machine + rng *rand.Rand +} + +func NewManager(seed int64) *Manager { + return &Manager{ + tables: make(map[string]*Table), + machines: make(map[string]*Machine), + rng: rand.New(rand.NewSource(seed)), + } +} + +func (m *Manager) EnsureMachine(roomID int, cfg MachineConfig) *Machine { + cfg = cfg.Normalize() + key := tableKey(roomID, cfg.ID) + m.mu.Lock() + defer m.mu.Unlock() + if machine := m.machines[key]; machine != nil { + return machine + } + machine := newMachine(roomID, cfg, m.rng) + m.machines[key] = machine + return machine +} + +func tableKey(roomID int, tableID string) string { + return fmt.Sprintf("%d:%s", roomID, tableID) +} + +func (m *Manager) EnsureTable(roomID int, cfg TableConfig) *Table { + cfg = cfg.Normalize() + key := tableKey(roomID, cfg.ID) + m.mu.Lock() + defer m.mu.Unlock() + if table := m.tables[key]; table != nil { + return table + } + table := newTable(roomID, cfg, m.rng) + m.tables[key] = table + return table +} + +func (m *Manager) Table(roomID int, tableID string) *Table { + m.mu.Lock() + defer m.mu.Unlock() + return m.tables[tableKey(roomID, tableID)] +} + +func (m *Manager) Tick() []Event { + m.mu.Lock() + tables := make([]*Table, 0, len(m.tables)) + for _, table := range m.tables { + tables = append(tables, table) + } + m.mu.Unlock() + sort.Slice(tables, func(i, j int) bool { + if tables[i].RoomID != tables[j].RoomID { + return tables[i].RoomID < tables[j].RoomID + } + return tables[i].Config.ID < tables[j].Config.ID + }) + var events []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() + sort.Slice(machines, func(i, j int) bool { + if machines[i].RoomID != machines[j].RoomID { + return machines[i].RoomID < machines[j].RoomID + } + return machines[i].Config.ID < machines[j].Config.ID + }) + for _, machine := range machines { + events = append(events, machine.tick()...) + } + 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) []Event { + m.mu.Lock() + machine := m.machines[tableKey(roomID, machineID)] + m.mu.Unlock() + if machine == nil { + return nil + } + return machine.setBet(name, amount) +} + +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) +} + +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) +} + +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) +} + +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) +} + +func (m *Manager) Join(roomID int, cfg TableConfig, name string) []Event { + return m.EnsureTable(roomID, cfg).join(name) +} + +func (m *Manager) Leave(roomID int, tableID, name string) []Event { + if table := m.Table(roomID, tableID); table != nil { + return table.leave(name) + } + return nil +} + +func (m *Manager) Bet(roomID int, tableID, name string, amount int, wallet Wallet) []Event { + if table := m.Table(roomID, tableID); table != nil { + return table.bet(name, amount, wallet) + } + return []Event{{RoomID: roomID, TableID: tableID, Type: EventResult, Player: name, PrivateTo: name, Message: "That game is not available here."}} +} + +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 { + 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 { + 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() + for _, table := range m.tables { + if table.hasParticipant(name) { + return table, true + } + } + for _, machine := range m.machines { + if machine.hasParticipant(name) { + return nil, true + } + } + return nil, false +} + +func (m *Manager) MachineFor(name string) (*Machine, bool) { + m.mu.Lock() + defer m.mu.Unlock() + for _, machine := range m.machines { + if machine.hasParticipant(name) { + return machine, true + } + } + return nil, false +} + +func (m *Manager) MachineBusy(name string) bool { + m.mu.Lock() + defer m.mu.Unlock() + for _, machine := range m.machines { + if machine.isBusy(name) { + return true + } + } + return false +} |
