Skip to content

Commit 0024536

Browse files
authored
change (#60)
1 parent 917d02d commit 0024536

10 files changed

Lines changed: 254 additions & 0 deletions

File tree

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,14 @@
462462
"practices": [],
463463
"prerequisites": [],
464464
"difficulty": 5
465+
},
466+
{
467+
"slug": "change",
468+
"name": "Change",
469+
"uuid": "756a79f1-6149-4eef-a365-e3cfcaf9c999",
470+
"practices": [],
471+
"prerequisites": [],
472+
"difficulty": 6
465473
}
466474
]
467475
},

exercises/practice/change/.busted

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
return {
2+
default = {
3+
ROOT = { '.' }
4+
}
5+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Instructions
2+
3+
Determine the fewest number of coins to give a customer so that the sum of their values equals the correct amount of change.
4+
5+
## Examples
6+
7+
- An amount of 15 with available coin values [1, 5, 10, 25, 100] should return one coin of value 5 and one coin of value 10, or [5, 10].
8+
- An amount of 40 with available coin values [1, 5, 10, 25, 100] should return one coin of value 5, one coin of value 10, and one coin of value 25, or [5, 10, 25].
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Introduction
2+
3+
In the mystical village of Coinholt, you stand behind the counter of your bakery, arranging a fresh batch of pastries.
4+
The door creaks open, and in walks Denara, a skilled merchant with a keen eye for quality goods.
5+
After a quick meal, she slides a shimmering coin across the counter, representing a value of 100 units.
6+
7+
You smile, taking the coin, and glance at the total cost of the meal: 88 units.
8+
That means you need to return 12 units in change.
9+
10+
Denara holds out her hand expectantly.
11+
"Just give me the fewest coins," she says with a smile.
12+
"My pouch is already full, and I don't want to risk losing them on the road."
13+
14+
You know you have a few options.
15+
"We have Lumis (worth 10 units), Viras (worth 5 units), and Zenth (worth 2 units) available for change."
16+
17+
You quickly calculate the possibilities in your head:
18+
19+
- one Lumis (1 × 10 units) + one Zenth (1 × 2 units) = 2 coins total
20+
- two Viras (2 × 5 units) + one Zenth (1 × 2 units) = 3 coins total
21+
- six Zenth (6 × 2 units) = 6 coins total
22+
23+
"The best choice is two coins: one Lumis and one Zenth," you say, handing her the change.
24+
25+
Denara smiles, clearly impressed.
26+
"As always, you've got it right."
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"glennj"
4+
],
5+
"files": {
6+
"solution": [
7+
"change.moon"
8+
],
9+
"test": [
10+
"change_spec.moon"
11+
],
12+
"example": [
13+
".meta/example.moon"
14+
]
15+
},
16+
"blurb": "Correctly determine change to be given using the least number of coins.",
17+
"source": "Software Craftsmanship - Coin Change Kata",
18+
"source_url": "https://web.archive.org/web/20130115115225/http://craftsmanship.sv.cmu.edu:80/exercises/coin-change-kata"
19+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
-- Change making algorithm from
2+
-- http://www.ccs.neu.edu/home/jaa/CSG713.04F/Information/Handouts/dyn_prog.pdf
3+
4+
-- This function generates two arrays:
5+
--
6+
-- C = maps the minimum number of coins required to make
7+
-- change for each n from 1 to amount.
8+
-- It is returned but only used internally in this
9+
-- application.
10+
--
11+
-- S = the _first_ coin used to make change for amount n
12+
-- (actually stores the coin _index_ into the
13+
-- denominations array)
14+
--
15+
change = (amount, denominations) ->
16+
C = {[0]: 0}
17+
S = {}
18+
19+
for p = 1, amount
20+
min = math.maxinteger
21+
coin_idx = nil
22+
23+
for i = 1, #denominations
24+
if denominations[i] <= p
25+
if C[p - denominations[i]] < min
26+
min = 1 + C[p - denominations[i]]
27+
coin_idx = i
28+
29+
C[p] = min
30+
S[p] = coin_idx
31+
32+
C, S
33+
34+
35+
change_maker = (S, d, n) ->
36+
result = {}
37+
while n > 0
38+
coin = d[S[n]]
39+
assert coin, "can't make target with given coins"
40+
41+
table.insert result, 1, coin
42+
n -= coin
43+
result
44+
45+
46+
{
47+
make_change: (amount, coins) ->
48+
assert amount >= 0, "target can't be negative"
49+
_, first_coin = change amount, coins
50+
change_maker first_coin, coins, amount
51+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
int_list = (list) -> "{#{table.concat list, ', '}}"
2+
3+
{
4+
module_imports: {'make_change'},
5+
6+
generate_test: (case, level) ->
7+
local lines
8+
if case.expected.error
9+
lines = {
10+
"f = -> make_change #{case.input.target}, #{int_list case.input.coins}",
11+
"assert.has.error f, #{quote case.expected.error}"
12+
}
13+
else
14+
lines = {
15+
"result = make_change #{case.input.target}, #{int_list case.input.coins}",
16+
"expected = #{int_list case.expected}",
17+
"assert.are.same expected, result"
18+
}
19+
table.concat [indent line, level for line in *lines], '\n'
20+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[d0ebd0e1-9d27-4609-a654-df5c0ba1d83a]
13+
description = "change for 1 cent"
14+
15+
[36887bea-7f92-4a9c-b0cc-c0e886b3ecc8]
16+
description = "single coin change"
17+
18+
[cef21ccc-0811-4e6e-af44-f011e7eab6c6]
19+
description = "multiple coin change"
20+
21+
[d60952bc-0c1a-4571-bf0c-41be72690cb3]
22+
description = "change with Lilliputian Coins"
23+
24+
[408390b9-fafa-4bb9-b608-ffe6036edb6c]
25+
description = "change with Lower Elbonia Coins"
26+
27+
[7421a4cb-1c48-4bf9-99c7-7f049689132f]
28+
description = "large target values"
29+
30+
[f79d2e9b-0ae3-4d6a-bb58-dc978b0dba28]
31+
description = "possible change without unit coins available"
32+
33+
[9a166411-d35d-4f7f-a007-6724ac266178]
34+
description = "another possible change without unit coins available"
35+
36+
[ce0f80d5-51c3-469d-818c-3e69dbd25f75]
37+
description = "a greedy approach is not optimal"
38+
39+
[bbbcc154-e9e9-4209-a4db-dd6d81ec26bb]
40+
description = "no coins make 0 change"
41+
42+
[c8b81d5a-49bd-4b61-af73-8ee5383a2ce1]
43+
description = "error testing for change smaller than the smallest of coins"
44+
45+
[3c43e3e4-63f9-46ac-9476-a67516e98f68]
46+
description = "error if no combination can add up to target"
47+
48+
[8fe1f076-9b2d-4f44-89fe-8a6ccd63c8f3]
49+
description = "cannot find negative change values"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
make_change: (target_amount, denominations) ->
3+
error 'Implement me'
4+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import make_change from require 'change'
2+
3+
describe 'change', ->
4+
it 'change for 1 cent', ->
5+
result = make_change 1, {1, 5, 10, 25}
6+
expected = {1}
7+
assert.are.same expected, result
8+
9+
pending 'single coin change', ->
10+
result = make_change 25, {1, 5, 10, 25, 100}
11+
expected = {25}
12+
assert.are.same expected, result
13+
14+
pending 'multiple coin change', ->
15+
result = make_change 15, {1, 5, 10, 25, 100}
16+
expected = {5, 10}
17+
assert.are.same expected, result
18+
19+
pending 'change with Lilliputian Coins', ->
20+
result = make_change 23, {1, 4, 15, 20, 50}
21+
expected = {4, 4, 15}
22+
assert.are.same expected, result
23+
24+
pending 'change with Lower Elbonia Coins', ->
25+
result = make_change 63, {1, 5, 10, 21, 25}
26+
expected = {21, 21, 21}
27+
assert.are.same expected, result
28+
29+
pending 'large target values', ->
30+
result = make_change 999, {1, 2, 5, 10, 20, 50, 100}
31+
expected = {2, 2, 5, 20, 20, 50, 100, 100, 100, 100, 100, 100, 100, 100, 100}
32+
assert.are.same expected, result
33+
34+
pending 'possible change without unit coins available', ->
35+
result = make_change 21, {2, 5, 10, 20, 50}
36+
expected = {2, 2, 2, 5, 10}
37+
assert.are.same expected, result
38+
39+
pending 'another possible change without unit coins available', ->
40+
result = make_change 27, {4, 5}
41+
expected = {4, 4, 4, 5, 5, 5}
42+
assert.are.same expected, result
43+
44+
pending 'a greedy approach is not optimal', ->
45+
result = make_change 20, {1, 10, 11}
46+
expected = {10, 10}
47+
assert.are.same expected, result
48+
49+
pending 'no coins make 0 change', ->
50+
result = make_change 0, {1, 5, 10, 21, 25}
51+
expected = {}
52+
assert.are.same expected, result
53+
54+
pending 'error testing for change smaller than the smallest of coins', ->
55+
f = -> make_change 3, {5, 10}
56+
assert.has.error f, "can't make target with given coins"
57+
58+
pending 'error if no combination can add up to target', ->
59+
f = -> make_change 94, {5, 10}
60+
assert.has.error f, "can't make target with given coins"
61+
62+
pending 'cannot find negative change values', ->
63+
f = -> make_change -5, {1, 2, 5}
64+
assert.has.error f, "target can't be negative"

0 commit comments

Comments
 (0)