diff options
Diffstat (limited to 'economy')
| -rw-r--r-- | economy/coins.go | 138 | ||||
| -rw-r--r-- | economy/coins_test.go | 90 | ||||
| -rw-r--r-- | economy/heads.go | 37 |
3 files changed, 265 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 +} diff --git a/economy/coins_test.go b/economy/coins_test.go new file mode 100644 index 0000000..d318fbe --- /dev/null +++ b/economy/coins_test.go @@ -0,0 +1,90 @@ +package economy_test + +import ( + "nonsense-time/economy" + "testing" +) + +func assert[T comparable](t *testing.T, expected T, actual T) bool { + if expected != actual { + t.Logf("expected %v != actual %v\n", expected, actual) + t.Fail() + return false + } + + return true +} + +func TestMoneyAdd(t *testing.T) { + a := economy.Money{0, -1, -2, -3, -4} + b := economy.Money{1, 2, 3, 4, 5} + a.Add(b) + + pass := true + pass = pass && assert(t, 1, a.Copper) + pass = pass && assert(t, 1, a.Silver) + pass = pass && assert(t, 1, a.Electrum) + pass = pass && assert(t, 1, a.Gold) + pass = pass && assert(t, 1, a.Platinum) + if !pass { + t.Logf("%+v\n", a) + } + +} + +func TestMoneySubtract(t *testing.T) { + a := economy.Money{1, 2, 3, 4, 5} + b := economy.Money{0, 1, 2, 3, 4} + + a.Subtract(b) + + pass := true + pass = pass && assert(t, 1, a.Copper) + pass = pass && assert(t, 1, a.Silver) + pass = pass && assert(t, 1, a.Electrum) + pass = pass && assert(t, 1, a.Gold) + pass = pass && assert(t, 1, a.Platinum) + if !pass { + t.Logf("%+v\n", a) + } +} + +func TestMoneyMult(t *testing.T) { + a := economy.Money{1, 2, 3, 5, 7} + b := economy.Money{11, 13, 17, 19, 23} + + t.Log("Testing positive multiplication") + a.Multiply(b) + + pass := true + pass = pass && assert(t, 11, a.Copper) + pass = pass && assert(t, 26, a.Silver) + pass = pass && assert(t, 51, a.Electrum) + pass = pass && assert(t, 95, a.Gold) + pass = pass && assert(t, 161, a.Platinum) + if !pass { + t.Logf("%+v\n", a) + } +} + +func TestMoneyValue(t *testing.T) { + a := economy.Money{1, 1, 1, 1, 1} + + t.Log("Testing all positive coins") + if !assert(t, 1161, a.Value()) { + t.Log(a) + } + + t.Log("Testing all negative coins") + a = economy.Money{-1, -1, -1, -1, -1} + if !assert(t, -1161, a.Value()) { + t.Log(a) + } + + t.Log("Testing mixed coins") + a.Copper = 10 + a.Electrum = 2 + if !assert(t, -1000, a.Value()) { + t.Log(a) + } +} diff --git a/economy/heads.go b/economy/heads.go new file mode 100644 index 0000000..15c9456 --- /dev/null +++ b/economy/heads.go @@ -0,0 +1,37 @@ +package economy + +import ( + "maps" +) + +type Location uint +type CostFunc func(cr float32, mutiplier float32, modifier float32) Money + +const ( + Field Location = iota + Display + Storage +) + +type Head struct { + Location Location + Conditions struct { + Multipliers map[string]float32 + Modifiers map[string]float32 + } + CR float32 +} + +func (h Head) Value(cost CostFunc) Money { + var multiplier float32 = 1 + for val := range maps.Values(h.Conditions.Multipliers) { + multiplier *= val + } + + var modifier float32 = 0 + for val := range maps.Values(h.Conditions.Modifiers) { + modifier += val + } + + return cost(h.CR, multiplier, modifier) +} |
