diff options
Diffstat (limited to 'economy/coins.go')
| -rw-r--r-- | economy/coins.go | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/economy/coins.go b/economy/coins.go new file mode 100644 index 0000000..e2d3531 --- /dev/null +++ b/economy/coins.go @@ -0,0 +1,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 +} |
