Skip to content

Instantly share code, notes, and snippets.

@caelifer
Last active December 10, 2019 04:55
Show Gist options
  • Save caelifer/31e8780bae7d05270b4fa02aae0fd886 to your computer and use it in GitHub Desktop.
Save caelifer/31e8780bae7d05270b4fa02aae0fd886 to your computer and use it in GitHub Desktop.
Calculate change from available pool of coins simulating automatic cash register.
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, ", "))
}
@caelifer
Copy link
Author

caelifer commented Dec 10, 2019

Live code - https://play.golang.org/p/SrQkFRmRzgC

Output:

Started with money in the bank: 3.50 dollars [2 quaters, 10 dimes, 20 nickles, 100 pennies]
Start dispensing change

Requesting change of 3 cents
Dispensed coins: 3 pennies
Money in the bank: 3.47 dollars [2 quaters, 10 dimes, 20 nickles, 97 pennies]

Requesting change of 5 cents
Dispensed coins: 1 nickle
Money in the bank: 3.42 dollars [2 quaters, 10 dimes, 19 nickles, 97 pennies]

Requesting change of 10 cents
Dispensed coins: 1 dime
Money in the bank: 3.32 dollars [2 quaters, 9 dimes, 19 nickles, 97 pennies]

Requesting change of 17 cents
Dispensed coins: 1 dime, 1 nickle, 2 pennies
Money in the bank: 3.15 dollars [2 quaters, 8 dimes, 18 nickles, 95 pennies]

Requesting change of 23 cents
Dispensed coins: 2 dimes, 3 pennies
Money in the bank: 2.92 dollars [2 quaters, 6 dimes, 18 nickles, 92 pennies]

Requesting change of 25 cents
Dispensed coins: 1 quater
Money in the bank: 2.67 dollars [1 quater, 6 dimes, 18 nickles, 92 pennies]

Requesting change of 41 cents
2009/11/10 23:00:00 out of quaters
Dispensed coins: 1 quater, 1 dime, 1 nickle, 1 penny
Money in the bank: 2.26 dollars [0 quaters, 5 dimes, 17 nickles, 91 pennies]

Requesting change of 91 cents
2009/11/10 23:00:00 out of dimes
Dispensed coins: 5 dimes, 8 nickles, 1 penny
Money in the bank: 1.35 dollars [0 quaters, 0 dimes, 9 nickles, 90 pennies]

Requesting change of 99 cents
2009/11/10 23:00:00 out of nickles
Dispensed coins: 9 nickles, 54 pennies
Money in the bank: 0.36 dollars [0 quaters, 0 dimes, 0 nickles, 36 pennies]

Requesting change of 50 cents
2009/11/10 23:00:00 out of pennies
2009/11/10 23:00:00 Not enough coins to make change on 14 cents balance

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment