-
Notifications
You must be signed in to change notification settings - Fork 0
/
machine.go
158 lines (137 loc) · 3.46 KB
/
machine.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package slotmachine
import (
"crypto/rand"
"math"
"math/big"
)
const SlotSetSize = 3
type SlotValue int
type SlotSet [SlotSetSize]SlotValue
type Payout struct {
Sum int64
Text string
}
type BetResult struct {
SlotSet *SlotSet
Payout *Payout
}
type Stats struct {
Payouts int64
Revenue int64
}
type PayoutRate struct {
TotalCombinations int64
WinningCombinations int64 // the more winning combinations, the more interesting a game is
SumOfWinningAmounts int64 // should be less than total amount of combinations * amount of a bet
BiggestWin int64
}
const Slot0 = SlotValue(0)
const Slot1 = SlotValue(1)
const Slot2 = SlotValue(2)
const Slot3 = SlotValue(3)
const Slot4 = SlotValue(4)
const Slot5 = SlotValue(5)
const Slot6 = SlotValue(6)
const Slot7 = SlotValue(7)
const Slot8 = SlotValue(8)
const Slot9 = SlotValue(9)
var SlotValues = []SlotValue{
Slot0,
Slot1,
Slot2,
Slot3,
Slot4,
Slot5,
Slot6,
Slot7,
Slot8,
Slot9,
}
var DefaultSlotSetPayout = map[SlotSet]Payout{
SlotSet{Slot0, Slot0, Slot0}: {Sum: 1, Text: "Beautiful, but all zeros. Keep it up!"},
SlotSet{Slot1, Slot1, Slot1}: {Sum: 11, Text: "Win! But try bigger"},
SlotSet{Slot2, Slot2, Slot2}: {Sum: 12, Text: "Not bad! Winner!"},
SlotSet{Slot3, Slot3, Slot3}: {Sum: 200, Text: "Nice bet!"},
SlotSet{Slot4, Slot4, Slot4}: {Sum: 14, Text: "Good result!"},
SlotSet{Slot5, Slot5, Slot5}: {Sum: 15, Text: "Beautiful!"},
SlotSet{Slot6, Slot6, Slot6}: {Sum: 16, Text: "Great result!"},
SlotSet{Slot7, Slot7, Slot7}: {Sum: 600, Text: "Jackpot!!!"},
SlotSet{Slot8, Slot8, Slot8}: {Sum: 18, Text: "Look at you, winner!"},
SlotSet{Slot9, Slot9, Slot9}: {Sum: 19, Text: "Biggest win aside of Jackpot!"},
}
type SlotMachine struct {
betSize int64
stats *Stats
max *big.Int
slotValues []SlotValue
payoutTable map[SlotSet]Payout
}
func NewSlotMachine(betSize int64, slotValues []SlotValue, payoutTable map[SlotSet]Payout) SlotMachine {
m := SlotMachine{
betSize: betSize,
stats: &Stats{},
slotValues: slotValues,
max: big.NewInt(int64(len(slotValues))),
payoutTable: payoutTable,
}
return m
}
func (m *SlotMachine) GetStats() Stats {
return *m.stats
}
func (m *SlotMachine) GetPayoutRate() PayoutRate {
wc := int64(0)
s := int64(0)
maxSum := int64(0)
for _, v := range m.payoutTable {
if maxSum < v.Sum {
maxSum = v.Sum
}
s += v.Sum
wc += 1
}
return PayoutRate{
TotalCombinations: int64(math.Pow(float64(len(m.slotValues)), float64(SlotSetSize))),
WinningCombinations: wc,
SumOfWinningAmounts: s,
BiggestWin: maxSum,
}
}
func (m *SlotMachine) spinSlot() (int64, error) {
s, err := rand.Int(rand.Reader, m.max)
if err != nil {
return -1, err
}
return s.Int64(), nil
}
func (m *SlotMachine) BetResult() (*BetResult, error) {
firstSlot, err := m.spinSlot()
if err != nil {
return nil, err
}
secondSlot, err := m.spinSlot()
if err != nil {
return nil, err
}
thirdSlot, err := m.spinSlot()
if err != nil {
return nil, err
}
set := SlotSet{SlotValue(firstSlot), SlotValue(secondSlot), SlotValue(thirdSlot)}
m.stats.Revenue += m.betSize
pay := m.payoutTable[set]
return &BetResult{SlotSet: &set, Payout: &pay}, nil
}
// bet result can be discarded, this hack needed to keep stats relevant
func (m *SlotMachine) ApplyBetResultToStats(br *BetResult) {
if br.Payout == nil {
return
}
m.stats.Payouts += br.Payout.Sum
if br.SlotSet == nil {
return
}
}
func (m *SlotMachine) GetBetSize() int64 {
return m.betSize
}