aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/manager.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/casino/manager.go')
-rw-r--r--internal/casino/manager.go238
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
+}