Last active
December 10, 2019 04:55
-
-
Save caelifer/31e8780bae7d05270b4fa02aae0fd886 to your computer and use it in GitHub Desktop.
Calculate change from available pool of coins simulating automatic cash register.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"log" | |
"strings" | |
) | |
func main() { | |
b := NewBank(map[Coin]int{ | |
Penny: 100, | |
Nickle: 20, | |
Dime: 10, | |
Quater: 2, | |
}) | |
fmt.Printf("Started with money in the bank: %v\n", b) | |
fmt.Println("Start dispensing change") | |
fmt.Println() | |
for _, v := range []int{3, 5, 10, 17, 23, 25, 41, 91, 99, 50} { | |
fmt.Printf("Requesting change of %d cents\n", v) | |
fmt.Printf("Dispensed coins: %s\n", b.DispenseCoins(v)) | |
fmt.Printf("Money in the bank: %s\n", b) | |
fmt.Println() | |
} | |
} | |
type Coin int | |
const ( | |
Penny Coin = 1 | |
Nickle = 5 | |
Dime = 10 | |
Quater = 25 | |
) | |
func (c Coin) singular() string { | |
switch c { | |
case Penny: | |
return "penny" | |
case Nickle: | |
return "nickle" | |
case Dime: | |
return "dime" | |
case Quater: | |
return "quater" | |
} | |
return "unknown coin" | |
} | |
func (c Coin) plural() string { | |
switch c { | |
case Penny: | |
return "pennies" | |
default: | |
return c.singular() + "s" | |
} | |
} | |
type CoinStack struct { | |
Type Coin | |
Count int | |
} | |
func (cs CoinStack) Value() int { | |
return int(cs.Type) * cs.Count | |
} | |
func (cs *CoinStack) Get(amount int) (*CoinStack, int) { | |
needCoins := amount / int(cs.Type) | |
balance := amount % int(cs.Type) | |
if needCoins > cs.Count { | |
defficit := needCoins - cs.Count | |
balance += defficit * int(cs.Type) | |
needCoins, cs.Count = cs.Count, 0 | |
} else { | |
cs.Count -= needCoins | |
} | |
if cs.Count == 0 { | |
log.Printf("out of %s", cs.Type.plural()) | |
} | |
return &CoinStack{Type: cs.Type, Count: needCoins}, balance | |
} | |
func (cs CoinStack) String() string { | |
denom := cs.Type.plural | |
if cs.Count == 1 { | |
denom = cs.Type.singular | |
} | |
return fmt.Sprintf("%d %s", cs.Count, denom()) | |
} | |
type Bank struct { | |
Store [4]*CoinStack | |
} | |
func NewBank(money map[Coin]int) *Bank { | |
bank := new(Bank) | |
// Transfer coins into bank | |
for i, c := range []Coin{Quater, Dime, Nickle, Penny} { | |
if count, ok := money[c]; ok { | |
bank.Store[i] = &CoinStack{Type: c, Count: count} | |
} | |
} | |
return bank | |
} | |
func (b *Bank) DispenseCoins(amount int) string { | |
res := make([]string, 0, 4) | |
for _, cs := range b.Store[:] { | |
if cs.Count == 0 { | |
continue | |
} | |
var coins *CoinStack | |
coins, amount = cs.Get(amount) | |
if coins.Count > 0 { | |
res = append(res, coins.String()) | |
} | |
if amount == 0 { | |
break | |
} | |
} | |
if amount > 0 { | |
log.Fatalf("Not enough coins to make change on %d cents balance", amount) | |
} | |
return strings.Join(res, ", ") | |
} | |
func (b Bank) String() string { | |
res := make([]string, 0, 4) | |
val := 0 | |
for _, cs := range b.Store[:] { | |
val += cs.Value() | |
res = append(res, cs.String()) | |
} | |
return fmt.Sprintf("%.2f dollars [%v]", float64(val)/100, strings.Join(res, ", ")) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Live code - https://play.golang.org/p/SrQkFRmRzgC
Output: