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
|
package economy
import (
"fmt"
"strings"
)
type Coin float64
const (
CopperPiece Coin = 1
SilverPiece Coin = 10
ElectrumPiece Coin = 50
GoldPiece Coin = 100
PlatinumPiece Coin = 1000
)
type Money struct {
Copper Coin
Silver Coin
Electrum Coin
Gold Coin
Platinum Coin
}
func abs[T int | int32 | int64](x T) T {
if x < 0 {
return -x
}
return x
}
// Computes sign(a) * (abs(a) % b)
func safeMod(dividend int, divisor uint) int {
absMod := abs(dividend) % int(divisor)
if dividend < 0 {
return -absMod
}
return absMod
}
func (a *Money) Add(b Money) {
a.Copper += b.Copper
a.Silver += b.Silver
a.Electrum += b.Electrum
a.Gold += b.Gold
a.Platinum += b.Platinum
}
func (a *Money) Subtract(b Money) {
a.Copper -= b.Copper
a.Silver -= b.Silver
a.Electrum -= b.Electrum
a.Gold -= b.Gold
a.Platinum -= b.Platinum
}
func (a *Money) Multiply(b Money) {
a.Copper *= b.Copper
a.Silver *= b.Silver
a.Electrum *= b.Electrum
a.Gold *= b.Gold
a.Platinum *= b.Platinum
}
// Converts coins Money to the smallest amount of largest denomination possible
func (m *Money) Simplify() {
totalValue := m.Value()
totalCopper := int(totalValue)
if abs(totalCopper) > int(PlatinumPiece) {
m.Platinum = Coin(totalCopper / int(PlatinumPiece))
totalCopper = safeMod(totalCopper, uint(PlatinumPiece))
}
if abs(totalCopper) > int(GoldPiece) {
m.Gold = Coin(totalCopper / int(GoldPiece))
totalCopper = safeMod(totalCopper, uint(GoldPiece))
}
if abs(totalCopper) > int(ElectrumPiece) {
m.Electrum = Coin(totalCopper / int(ElectrumPiece))
totalCopper = safeMod(totalCopper, uint(ElectrumPiece))
}
if abs(totalCopper) > int(SilverPiece) {
m.Silver = Coin(totalCopper / int(SilverPiece))
totalCopper = safeMod(totalCopper, uint(SilverPiece))
}
m.Copper = Coin(totalCopper)
}
func (m Money) Value() Coin {
var value Coin = 0.0
value += m.Copper
value += m.Silver * SilverPiece
value += m.Electrum * ElectrumPiece
value += m.Gold * GoldPiece
value += m.Platinum * PlatinumPiece
return value
}
func (m Money) String() string {
var b strings.Builder
if m.Copper != 0 {
fmt.Fprintf(&b, "%.2fcp", m.Copper)
}
if m.Silver != 0 {
fmt.Fprintf(&b, "%.2fsp", m.Silver)
}
if m.Electrum != 0 {
fmt.Fprintf(&b, "%.2fep", m.Electrum)
}
if m.Gold != 0 {
fmt.Fprintf(&b, "%.2fgp", m.Gold)
}
if m.Platinum != 0 {
fmt.Fprintf(&b, "%.2fpp", m.Platinum)
}
return b.String()
}
func Sum(amounts []Money) Money {
total := Money{}
for _, amount := range amounts {
total.Add(amount)
}
return total
}
|