Skip to content

Commit fd0e9fc

Browse files
Add dominoes exercise (#101)
1 parent d2c1526 commit fd0e9fc

File tree

13 files changed

+559
-0
lines changed

13 files changed

+559
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,14 @@
595595
"prerequisites": [],
596596
"difficulty": 8
597597
},
598+
{
599+
"slug": "dominoes",
600+
"name": "Dominoes",
601+
"uuid": "5a28cae2-cd44-4c8c-ac6e-b0ac38e9c2d2",
602+
"practices": [],
603+
"prerequisites": [],
604+
"difficulty": 8
605+
},
598606
{
599607
"slug": "grep",
600608
"name": "Grep",
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Instructions
2+
3+
Make a chain of dominoes.
4+
5+
Compute a way to order a given set of domino stones so that they form a correct domino chain.
6+
In the chain, the dots on one half of a stone must match the dots on the neighboring half of an adjacent stone.
7+
Additionally, the dots on the halves of the stones without neighbors (the first and last stone) must match each other.
8+
9+
For example given the stones `[2|1]`, `[2|3]` and `[1|3]` you should compute something
10+
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.
11+
12+
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.
13+
4 != 3
14+
15+
Some test cases may use duplicate stones in a chain solution, assume that multiple Domino sets are being used.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Introduction
2+
3+
In Toyland, the trains are always busy delivering treasures across the city, from shiny marbles to rare building blocks.
4+
The tracks they run on are made of colorful domino-shaped pieces, each marked with two numbers.
5+
For the trains to move, the dominoes must form a perfect chain where the numbers match.
6+
7+
Today, an urgent delivery of rare toys is on hold.
8+
You've been handed a set of track pieces to inspect.
9+
If they can form a continuous chain, the train will be on its way, bringing smiles across Toyland.
10+
If not, the set will be discarded, and another will be tried.
11+
12+
The toys are counting on you to solve this puzzle.
13+
Will the dominoes connect the tracks and send the train rolling, or will the set be left behind?
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
namespace Dominoes
2+
3+
def Half := { x : Nat // x ≥ 1 ∧ x ≤ 6 }
4+
5+
def Stone := Half × Half
6+
7+
def findRoot (parents : Array Nat) (entry : Nat) : Nat := Id.run do
8+
let mut current := entry
9+
while current != parents[current]! do
10+
current := parents[current]!
11+
return current
12+
13+
def canChain (dominoes : List Stone) : Bool := Id.run do
14+
let mut tally := Array.replicate 7 (0 : Nat)
15+
for stone in dominoes do
16+
let first := stone.1.val
17+
let firstCount := tally[first]! + 1
18+
tally := tally.set! first firstCount
19+
let second := stone.2.val
20+
let secondCount := tally[second]! + 1
21+
tally := tally.set! second secondCount
22+
for entry in tally do
23+
if (entry &&& 1) != 0 then return false
24+
25+
let mut parents : Array Nat := List.range 7 |> List.toArray
26+
for stone in dominoes do
27+
let firstRoot := findRoot parents stone.1.val
28+
let secondRoot := findRoot parents stone.2.val
29+
parents := parents.set! secondRoot firstRoot
30+
31+
let mut count := 0
32+
for i in [0:7] do
33+
if (tally[i]! > 0) && (i == parents[i]!) then count := count + 1
34+
return count ≤ 1
35+
36+
end Dominoes
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"authors": [
3+
"keiravillekode"
4+
],
5+
"files": {
6+
"solution": [
7+
"Dominoes.lean"
8+
],
9+
"test": [
10+
"DominoesTest.lean"
11+
],
12+
"example": [
13+
".meta/Example.lean"
14+
]
15+
},
16+
"blurb": "Make a chain of dominoes."
17+
}
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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Dominoes
2+
3+
def Half := { x : Nat // x ≥ 1 ∧ x ≤ 6 }
4+
5+
def Stone := Half × Half
6+
7+
def canChain (dominoes : List Stone) : Bool :=
8+
sorry
9+
10+
end Dominoes
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import LeanTest
2+
import Dominoes
3+
4+
open LeanTest
5+
6+
def dominoesTests : TestSuite :=
7+
(TestSuite.empty "Dominoes")
8+
|>.addTest "empty input = empty output" (do
9+
return assertTrue (Dominoes.canChain []))
10+
|>.addTest "singleton input = singleton output" (do
11+
return assertTrue (Dominoes.canChain [
12+
(⟨1, by decide⟩, ⟨1, by decide⟩)
13+
]))
14+
|>.addTest "singleton that can't be chained" (do
15+
return assertFalse (Dominoes.canChain [
16+
(⟨1, by decide⟩, ⟨2, by decide⟩)
17+
]))
18+
|>.addTest "three elements" (do
19+
return assertTrue (Dominoes.canChain [
20+
(⟨1, by decide⟩, ⟨2, by decide⟩),
21+
(⟨3, by decide⟩, ⟨1, by decide⟩),
22+
(⟨2, by decide⟩, ⟨3, by decide⟩)
23+
]))
24+
|>.addTest "can reverse dominoes" (do
25+
return assertTrue (Dominoes.canChain [
26+
(⟨1, by decide⟩, ⟨2, by decide⟩),
27+
(⟨1, by decide⟩, ⟨3, by decide⟩),
28+
(⟨2, by decide⟩, ⟨3, by decide⟩)
29+
]))
30+
|>.addTest "can't be chained" (do
31+
return assertFalse (Dominoes.canChain [
32+
(⟨1, by decide⟩, ⟨2, by decide⟩),
33+
(⟨4, by decide⟩, ⟨1, by decide⟩),
34+
(⟨2, by decide⟩, ⟨3, by decide⟩)
35+
]))
36+
|>.addTest "disconnected - simple" (do
37+
return assertFalse (Dominoes.canChain [
38+
(⟨1, by decide⟩, ⟨1, by decide⟩),
39+
(⟨2, by decide⟩, ⟨2, by decide⟩)
40+
]))
41+
|>.addTest "disconnected - double loop" (do
42+
return assertFalse (Dominoes.canChain [
43+
(⟨1, by decide⟩, ⟨2, by decide⟩),
44+
(⟨2, by decide⟩, ⟨1, by decide⟩),
45+
(⟨3, by decide⟩, ⟨4, by decide⟩),
46+
(⟨4, by decide⟩, ⟨3, by decide⟩)
47+
]))
48+
|>.addTest "disconnected - single isolated" (do
49+
return assertFalse (Dominoes.canChain [
50+
(⟨1, by decide⟩, ⟨2, by decide⟩),
51+
(⟨2, by decide⟩, ⟨3, by decide⟩),
52+
(⟨3, by decide⟩, ⟨1, by decide⟩),
53+
(⟨4, by decide⟩, ⟨4, by decide⟩)
54+
]))
55+
|>.addTest "need backtrack" (do
56+
return assertTrue (Dominoes.canChain [
57+
(⟨1, by decide⟩, ⟨2, by decide⟩),
58+
(⟨2, by decide⟩, ⟨3, by decide⟩),
59+
(⟨3, by decide⟩, ⟨1, by decide⟩),
60+
(⟨2, by decide⟩, ⟨4, by decide⟩),
61+
(⟨2, by decide⟩, ⟨4, by decide⟩)
62+
]))
63+
|>.addTest "separate loops" (do
64+
return assertTrue (Dominoes.canChain [
65+
(⟨1, by decide⟩, ⟨2, by decide⟩),
66+
(⟨2, by decide⟩, ⟨3, by decide⟩),
67+
(⟨3, by decide⟩, ⟨1, by decide⟩),
68+
(⟨1, by decide⟩, ⟨1, by decide⟩),
69+
(⟨2, by decide⟩, ⟨2, by decide⟩),
70+
(⟨3, by decide⟩, ⟨3, by decide⟩)
71+
]))
72+
|>.addTest "nine elements" (do
73+
return assertTrue (Dominoes.canChain [
74+
(⟨1, by decide⟩, ⟨2, by decide⟩),
75+
(⟨5, by decide⟩, ⟨3, by decide⟩),
76+
(⟨3, by decide⟩, ⟨1, by decide⟩),
77+
(⟨1, by decide⟩, ⟨2, by decide⟩),
78+
(⟨2, by decide⟩, ⟨4, by decide⟩),
79+
(⟨1, by decide⟩, ⟨6, by decide⟩),
80+
(⟨2, by decide⟩, ⟨3, by decide⟩),
81+
(⟨3, by decide⟩, ⟨4, by decide⟩),
82+
(⟨5, by decide⟩, ⟨6, by decide⟩)
83+
]))
84+
|>.addTest "separate three-domino loops" (do
85+
return assertFalse (Dominoes.canChain [
86+
(⟨1, by decide⟩, ⟨2, by decide⟩),
87+
(⟨2, by decide⟩, ⟨3, by decide⟩),
88+
(⟨3, by decide⟩, ⟨1, by decide⟩),
89+
(⟨4, by decide⟩, ⟨5, by decide⟩),
90+
(⟨5, by decide⟩, ⟨6, by decide⟩),
91+
(⟨6, by decide⟩, ⟨4, by decide⟩)
92+
]))
93+
94+
def main : IO UInt32 := do
95+
runTestSuitesWithExitCode [dominoesTests]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name = "dominoes"
2+
version = "0.1.0"
3+
defaultTargets = ["DominoesTest"]
4+
testDriver = "DominoesTest"
5+
6+
[[lean_lib]]
7+
name = "LeanTest"
8+
srcDir = "vendor/LeanTest"
9+
10+
[[lean_lib]]
11+
name = "Dominoes"
12+
13+
[[lean_exe]]
14+
name = "DominoesTest"
15+
root = "DominoesTest"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
leanprover/lean4:v4.25.2

0 commit comments

Comments
 (0)