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 }