Skip to content

Commit 264fc11

Browse files
authored
Add dominoes exercise (#525)
* Skeleton and tests * Example solution and stub * Simplify the example solution.
1 parent 257ff32 commit 264fc11

File tree

10 files changed

+234
-1
lines changed

10 files changed

+234
-1
lines changed

bin/generate-spec

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ local function process(node)
8585
%s
8686
end)]]
8787

88-
return template:format(node.description:lower(), spec_generator.generate_test(node))
88+
return template:format(
89+
node.description:lower():gsub('\'', '\\\''),
90+
spec_generator.generate_test(node)
91+
)
8992
end
9093
end
9194

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,14 @@
986986
"prerequisites": [],
987987
"difficulty": 4
988988
},
989+
{
990+
"slug": "dominoes",
991+
"name": "Dominoes",
992+
"uuid": "0ea6977c-5032-40ab-bd67-be23e052c69f",
993+
"practices": [],
994+
"prerequisites": [],
995+
"difficulty": 4
996+
},
989997
{
990998
"slug": "affine-cipher",
991999
"name": "Affine Cipher",

exercises/practice/dominoes/.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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Instructions
2+
3+
Make a chain of dominoes.
4+
5+
Compute a way to order a given set of dominoes in such a way that they form a correct domino chain (the dots on one half of a stone match the dots on the neighboring half of an adjacent stone) and that dots on the halves of the stones which don't have a neighbor (the first and last stone) match each other.
6+
7+
For example given the stones `[2|1]`, `[2|3]` and `[1|3]` you should compute something
8+
like `[1|2] [2|3] [3|1]` or `[3|2] [2|1] [1|3]` or `[1|3] [3|2] [2|1]` etc, where the first and last numbers are the same.
9+
10+
For stones `[1|2]`, `[4|1]` and `[2|3]` the resulting chain is not valid: `[4|1] [1|2] [2|3]`'s first and last numbers are not the same.
11+
4 != 3
12+
13+
Some test cases may use duplicate stones in a chain solution, assume that multiple Domino sets are being used.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"authors": [
3+
"ryanplusplus"
4+
],
5+
"files": {
6+
"solution": [
7+
"dominoes.lua"
8+
],
9+
"test": [
10+
"dominoes_spec.lua"
11+
],
12+
"example": [
13+
".meta/example.lua"
14+
]
15+
},
16+
"blurb": "Make a chain of dominoes."
17+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
local function reversed(domino)
2+
return { domino[2], domino[1] }
3+
end
4+
5+
local function without_domino(dominoes, target)
6+
local without = {}
7+
for i = 1, #dominoes do
8+
if i ~= target then
9+
table.insert(without, dominoes[i])
10+
end
11+
end
12+
return without
13+
end
14+
15+
local function can_chain(dominoes)
16+
if #dominoes == 0 then
17+
return true
18+
end
19+
20+
local function recur(left, dominoes, right)
21+
if #dominoes == 0 then
22+
return left == right
23+
end
24+
25+
for i, domino in ipairs(dominoes) do
26+
for _, domino in ipairs({ domino, reversed(domino) }) do
27+
if domino[1] == left and recur(domino[2], without_domino(dominoes, i), right) then
28+
return true
29+
end
30+
end
31+
end
32+
33+
return false
34+
end
35+
36+
return recur(dominoes[1][1], without_domino(dominoes, 1), dominoes[1][2])
37+
end
38+
39+
return { can_chain = can_chain }
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
local map = function(t, f)
2+
local mapped = {}
3+
for i, v in ipairs(t) do
4+
mapped[i] = f(v)
5+
end
6+
return mapped
7+
end
8+
9+
local function render_dominoes(dominoes)
10+
return table.concat(map(dominoes, function(domino)
11+
return ('{ %s }'):format(table.concat(domino, ', '))
12+
end), ', ')
13+
end
14+
15+
return {
16+
module_name = 'dominoes',
17+
18+
generate_test = function(case)
19+
local template = [[
20+
local input = {
21+
%s
22+
}
23+
assert.is_%s(dominoes.can_chain(input))]]
24+
return template:format(render_dominoes(case.input.dominoes), case.expected)
25+
end
26+
}
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+
[31a673f2-5e54-49fe-bd79-1c1dae476c9c]
13+
description = "empty input = empty output"
14+
15+
[4f99b933-367b-404b-8c6d-36d5923ee476]
16+
description = "singleton input = singleton output"
17+
18+
[91122d10-5ec7-47cb-b759-033756375869]
19+
description = "singleton that can't be chained"
20+
21+
[be8bc26b-fd3d-440b-8e9f-d698a0623be3]
22+
description = "three elements"
23+
24+
[99e615c6-c059-401c-9e87-ad7af11fea5c]
25+
description = "can reverse dominoes"
26+
27+
[51f0c291-5d43-40c5-b316-0429069528c9]
28+
description = "can't be chained"
29+
30+
[9a75e078-a025-4c23-8c3a-238553657f39]
31+
description = "disconnected - simple"
32+
33+
[0da0c7fe-d492-445d-b9ef-1f111f07a301]
34+
description = "disconnected - double loop"
35+
36+
[b6087ff0-f555-4ea0-a71c-f9d707c5994a]
37+
description = "disconnected - single isolated"
38+
39+
[2174fbdc-8b48-4bac-9914-8090d06ef978]
40+
description = "need backtrack"
41+
42+
[167bb480-dfd1-4318-a20d-4f90adb4a09f]
43+
description = "separate loops"
44+
45+
[cd061538-6046-45a7-ace9-6708fe8f6504]
46+
description = "nine elements"
47+
48+
[44704c7c-3adb-4d98-bd30-f45527cf8b49]
49+
description = "separate three-domino loops"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
local function can_chain(dominoes)
2+
3+
end
4+
5+
return { can_chain = can_chain }
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
local dominoes = require('dominoes')
2+
3+
describe('dominoes', function()
4+
it('empty input = empty output', function()
5+
local input = {}
6+
assert.is_true(dominoes.can_chain(input))
7+
end)
8+
9+
it('singleton input = singleton output', function()
10+
local input = { { 1, 1 } }
11+
assert.is_true(dominoes.can_chain(input))
12+
end)
13+
14+
it('singleton that can\'t be chained', function()
15+
local input = { { 1, 2 } }
16+
assert.is_false(dominoes.can_chain(input))
17+
end)
18+
19+
it('three elements', function()
20+
local input = { { 1, 2 }, { 3, 1 }, { 2, 3 } }
21+
assert.is_true(dominoes.can_chain(input))
22+
end)
23+
24+
it('can reverse dominoes', function()
25+
local input = { { 1, 2 }, { 1, 3 }, { 2, 3 } }
26+
assert.is_true(dominoes.can_chain(input))
27+
end)
28+
29+
it('can\'t be chained', function()
30+
local input = { { 1, 2 }, { 4, 1 }, { 2, 3 } }
31+
assert.is_false(dominoes.can_chain(input))
32+
end)
33+
34+
it('disconnected - simple', function()
35+
local input = { { 1, 1 }, { 2, 2 } }
36+
assert.is_false(dominoes.can_chain(input))
37+
end)
38+
39+
it('disconnected - double loop', function()
40+
local input = { { 1, 2 }, { 2, 1 }, { 3, 4 }, { 4, 3 } }
41+
assert.is_false(dominoes.can_chain(input))
42+
end)
43+
44+
it('disconnected - single isolated', function()
45+
local input = { { 1, 2 }, { 2, 3 }, { 3, 1 }, { 4, 4 } }
46+
assert.is_false(dominoes.can_chain(input))
47+
end)
48+
49+
it('need backtrack', function()
50+
local input = { { 1, 2 }, { 2, 3 }, { 3, 1 }, { 2, 4 }, { 2, 4 } }
51+
assert.is_true(dominoes.can_chain(input))
52+
end)
53+
54+
it('separate loops', function()
55+
local input = { { 1, 2 }, { 2, 3 }, { 3, 1 }, { 1, 1 }, { 2, 2 }, { 3, 3 } }
56+
assert.is_true(dominoes.can_chain(input))
57+
end)
58+
59+
it('nine elements', function()
60+
local input = { { 1, 2 }, { 5, 3 }, { 3, 1 }, { 1, 2 }, { 2, 4 }, { 1, 6 }, { 2, 3 }, { 3, 4 }, { 5, 6 } }
61+
assert.is_true(dominoes.can_chain(input))
62+
end)
63+
64+
it('separate three-domino loops', function()
65+
local input = { { 1, 2 }, { 2, 3 }, { 3, 1 }, { 4, 5 }, { 5, 6 }, { 6, 4 } }
66+
assert.is_false(dominoes.can_chain(input))
67+
end)
68+
end)

0 commit comments

Comments
 (0)