Skip to content

Commit 84472e8

Browse files
Add change exercise (#51)
1 parent 99829c6 commit 84472e8

File tree

8 files changed

+199
-6
lines changed

8 files changed

+199
-6
lines changed

config.json

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -335,17 +335,17 @@
335335
"difficulty": 5
336336
},
337337
{
338-
"slug": "run-length-encoding",
339-
"name": "Run-Length Encoding",
340-
"uuid": "9b14d6e1-bd0e-4450-817f-e6e2c3958a3d",
338+
"slug": "nth-prime",
339+
"name": "Nth Prime",
340+
"uuid": "fe8e3e7e-f239-40dc-8f3e-e07fa099da36",
341341
"practices": [],
342342
"prerequisites": [],
343343
"difficulty": 5
344344
},
345345
{
346-
"slug": "nth-prime",
347-
"name": "Nth Prime",
348-
"uuid": "fe8e3e7e-f239-40dc-8f3e-e07fa099da36",
346+
"slug": "run-length-encoding",
347+
"name": "Run-Length Encoding",
348+
"uuid": "9b14d6e1-bd0e-4450-817f-e6e2c3958a3d",
349349
"practices": [],
350350
"prerequisites": [],
351351
"difficulty": 5
@@ -365,6 +365,14 @@
365365
"practices": [],
366366
"prerequisites": [],
367367
"difficulty": 6
368+
},
369+
{
370+
"slug": "change",
371+
"name": "Change",
372+
"uuid": "3aa8ad23-2691-478f-9a50-4c14ad6b753e",
373+
"practices": [],
374+
"prerequisites": [],
375+
"difficulty": 7
368376
}
369377
]
370378
},
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+
"keiravillekode"
4+
],
5+
"files": {
6+
"solution": [
7+
"change.fut"
8+
],
9+
"test": [
10+
"test.fut"
11+
],
12+
"example": [
13+
".meta/example.fut"
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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
def find_fewest_coins (coins: []i32) (target: i32): []i32 =
2+
let capacity = assert (target >= 0) (target + 1)
3+
let (table_coins, table_counts) = loop (table_coins, table_counts) = (replicate (i64.i32 capacity) 0, replicate (i64.i32 capacity) 0) for i in 1..<capacity do
4+
let (best_coin, best_count) = loop (best_coin, best_count) = (0, capacity) for coin in coins do
5+
if coin > i || table_counts[i - coin] + 1 >= best_count then (best_coin, best_count) else
6+
(coin, table_counts[i - coin] + 1)
7+
in
8+
(table_coins with [i] = best_coin, table_counts with [i] = best_count)
9+
in
10+
let (result, _, _) = loop (result, remaining, j) = assert (table_counts[target] < capacity) (replicate (i64.i32 table_counts[target]) 0, target, 0) while remaining > 0 do
11+
(result with [j] = table_coins[remaining], remaining - table_coins[remaining], j + 1)
12+
in
13+
result
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"

exercises/practice/change/change.fut

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
def find_fewest_coins (coins: []i32) (target: i32): []i32 = ???

exercises/practice/change/test.fut

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import "change"
2+
3+
-- change for 1 cent
4+
-- ==
5+
-- input { [1, 5, 10, 25] 1 }
6+
-- output { [1] }
7+
8+
-- single coin change
9+
-- ==
10+
-- input { [1, 5, 10, 25, 100] 25 }
11+
-- output { [25] }
12+
13+
-- multiple coin change
14+
-- ==
15+
-- input { [1, 5, 10, 25, 100] 15 }
16+
-- output { [5, 10] }
17+
18+
-- change with Lilliputian Coins
19+
-- ==
20+
-- input { [1, 4, 15, 20, 50] 23 }
21+
-- output { [4, 4, 15] }
22+
23+
-- change with Lower Elbonia Coins
24+
-- ==
25+
-- input { [1, 5, 10, 21, 25] 63 }
26+
-- output { [21, 21, 21] }
27+
28+
-- large target values
29+
-- ==
30+
-- input { [1, 2, 5, 10, 20, 50, 100] 999 }
31+
-- output { [2, 2, 5, 20, 20, 50, 100, 100, 100, 100, 100, 100, 100, 100, 100] }
32+
33+
-- possible change without unit coins available
34+
-- ==
35+
-- input { [2, 5, 10, 20, 50] 21 }
36+
-- output { [2, 2, 2, 5, 10] }
37+
38+
-- another possible change without unit coins available
39+
-- ==
40+
-- input { [4, 5] 27 }
41+
-- output { [4, 4, 4, 5, 5, 5] }
42+
43+
-- a greedy approach is not optimal
44+
-- ==
45+
-- input { [1, 10, 11] 20 }
46+
-- output { [10, 10] }
47+
48+
-- no coins make 0 change
49+
-- ==
50+
-- input { [1, 5, 10, 21, 25] 0 }
51+
-- output { empty([0]i32) }
52+
53+
-- error testing for change smaller than the smallest of coins
54+
-- ==
55+
-- input { [5, 10] 3 }
56+
-- error: Error*
57+
58+
-- error if no combination can add up to target
59+
-- ==
60+
-- input { [5, 10] 94 }
61+
-- error: Error*
62+
63+
-- cannot find negative change values
64+
-- ==
65+
-- input { [1, 2, 5] -5 }
66+
-- error: Error*
67+
68+
def main (coins: []i32) (target: i32): []i32 =
69+
find_fewest_coins coins target

0 commit comments

Comments
 (0)