aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/economy/coins.go
blob: e2d3531cacaa9316b4f6bf924931008d3d9f7da8 (plain) (blame)
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
}