Skip to content

Commit 48b614d

Browse files
Add zebra-puzzle exercise (#60)
1 parent 21b35a1 commit 48b614d

File tree

8 files changed

+226
-0
lines changed

8 files changed

+226
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,14 @@
424424
"practices": [],
425425
"prerequisites": [],
426426
"difficulty": 7
427+
},
428+
{
429+
"slug": "zebra-puzzle",
430+
"name": "Zebra Puzzle",
431+
"uuid": "c317b776-57ef-4776-9a1e-70a928171e2d",
432+
"practices": [],
433+
"prerequisites": [],
434+
"difficulty": 10
427435
}
428436
]
429437
},
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Instructions
2+
3+
Your task is to solve the Zebra Puzzle to find the answer to these two questions:
4+
5+
- Which of the residents drinks water?
6+
- Who owns the zebra?
7+
8+
## Puzzle
9+
10+
The following 15 statements are all known to be true:
11+
12+
1. There are five houses.
13+
2. The Englishman lives in the red house.
14+
3. The Spaniard owns the dog.
15+
4. The person in the green house drinks coffee.
16+
5. The Ukrainian drinks tea.
17+
6. The green house is immediately to the right of the ivory house.
18+
7. The snail owner likes to go dancing.
19+
8. The person in the yellow house is a painter.
20+
9. The person in the middle house drinks milk.
21+
10. The Norwegian lives in the first house.
22+
11. The person who enjoys reading lives in the house next to the person with the fox.
23+
12. The painter's house is next to the house with the horse.
24+
13. The person who plays football drinks orange juice.
25+
14. The Japanese person plays chess.
26+
15. The Norwegian lives next to the blue house.
27+
28+
Additionally, each of the five houses is painted a different color, and their inhabitants are of different national extractions, own different pets, drink different beverages and engage in different hobbies.
29+
30+
~~~~exercism/note
31+
There are 24 billion (5!⁵ = 24,883,200,000) possible solutions, so try ruling out as many solutions as possible.
32+
~~~~
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Introduction
2+
3+
The Zebra Puzzle is a famous logic puzzle in which there are five houses, each painted a different color.
4+
The houses have different inhabitants, who have different nationalities, own different pets, drink different beverages and enjoy different hobbies.
5+
6+
To help you solve the puzzle, you're given 15 statements describing the solution.
7+
However, only by combining the information in _all_ statements will you be able to find the solution to the puzzle.
8+
9+
~~~~exercism/note
10+
The Zebra Puzzle is a [Constraint satisfaction problem (CSP)][constraint-satisfaction-problem].
11+
In such a problem, you have a set of possible values and a set of constraints that limit which values are valid.
12+
Another well-known CSP is Sudoku.
13+
14+
[constraint-satisfaction-problem]: https://en.wikipedia.org/wiki/Constraint_satisfaction_problem
15+
~~~~
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+
"zebra_puzzle.fut"
8+
],
9+
"test": [
10+
"test.fut"
11+
],
12+
"example": [
13+
".meta/example.fut"
14+
]
15+
},
16+
"blurb": "Solve the zebra puzzle.",
17+
"source": "Wikipedia",
18+
"source_url": "https://en.wikipedia.org/wiki/Zebra_Puzzle"
19+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
2+
def next_permutation [n] (a: *[n]i32): *[n]i32 =
3+
-- Step 1. find j
4+
let j = loop j = n - 2 while a[j] >= a[j + 1] do
5+
j - 1
6+
in
7+
8+
-- Step 2. increase a[j]
9+
let l = loop l = n - 1 while a[j] >= a[l] do
10+
l - 1
11+
in
12+
let aj = a[j]
13+
let al = a[l]
14+
let a = a with [j] = al with [l] = aj
15+
16+
-- Step 3. reverse a[j+1] ... a[n-1]
17+
let (a, _, _) = loop (a, k, l) = (a, j + 1, n - 1) while k < l do
18+
let ak = a[k]
19+
let al = a[l]
20+
in
21+
(a with [k] = al with [l] = ak, k + 1, l - 1)
22+
in
23+
a
24+
25+
def not_adjacent (i: i32) (j: i32): bool =
26+
i + 1 != j && j + 1 != i
27+
28+
type zebra_question = #drinks_water | #owns_zebra
29+
30+
def answer(question: zebra_question): []u8 =
31+
let (solution, _) = loop (solution, nationalities) = ("", [0, 1, 2, 3, 4, 5]) while length solution == 0 do
32+
let englishman = nationalities[1]
33+
let japanese = nationalities[2]
34+
let norwegian = nationalities[3]
35+
let spaniard = nationalities[4]
36+
let ukrainian = nationalities[5]
37+
in
38+
39+
-- 10. The Norwegian lives in the first house.
40+
if norwegian != 1 then ("", next_permutation nationalities) else
41+
let (solution2, _) = loop (solution2, colors) = ("", [0, 1, 2, 3, 4, 5]) while colors[0] == 0 && length solution2 == 0 do
42+
let blue = colors[1]
43+
let green = colors[2]
44+
let ivory = colors[3]
45+
let red = colors[4]
46+
let yellow = colors[5]
47+
in
48+
49+
-- 2. The Englishman lives in the red house.
50+
-- 6. The green house is immediately to the right of the ivory house.
51+
-- 15. The Norwegian lives next to the blue house.
52+
if englishman != red || green != ivory + 1 || not_adjacent norwegian blue then ("", next_permutation colors) else
53+
let (solution3, _) = loop (solution3, drinks) = ("", [0, 1, 2, 3, 4, 5]) while drinks[0] == 0 && length solution3 == 0 do
54+
let coffee = drinks[1]
55+
let milk = drinks[2]
56+
let orangeJuice = drinks[3]
57+
let tea = drinks[4]
58+
let water = drinks[5]
59+
in
60+
61+
-- 4. Coffee is drunk in the green house.
62+
-- 5. The Ukrainian drinks tea.
63+
-- 9. Milk is drunk in the middle house.
64+
if coffee != green || ukrainian != tea || milk != 3 then ("", next_permutation drinks) else
65+
let (solution4, _) = loop (solution4, hobbies) = ("", [0, 1, 2, 3, 4, 5]) while hobbies[0] == 0 && length solution4 == 0 do
66+
let reading = hobbies[1]
67+
let painting = hobbies[2]
68+
let football = hobbies[3]
69+
let dancing = hobbies[4]
70+
let chess = hobbies[5]
71+
in
72+
73+
-- 8. The person in the yellow house is a painter.
74+
-- 13. The person who plays football drinks orange juice.
75+
-- 14. The Japanese person plays chess.
76+
if painting != yellow || football != orangeJuice || japanese != chess then ("", next_permutation hobbies) else
77+
let (solution5, _) = loop (solution5, pets) = ("", [0, 1, 2, 3, 4, 5]) while pets[0] == 0 && length solution5 == 0 do
78+
let dog = pets[1]
79+
let fox = pets[2]
80+
let horse = pets[3]
81+
let snails = pets[4]
82+
let zebra = pets[5]
83+
let selection = match question
84+
case #drinks_water -> water
85+
case #owns_zebra -> zebra
86+
in
87+
88+
-- 3. The Spaniard owns the dog.
89+
-- 7. The snail owner likes to go dancing.
90+
-- 11. The person who enjoys reading lives in the house next to the person with the fox.
91+
-- 12. The painter's house is next to the house with the horse.
92+
if spaniard != dog || dancing != snails || not_adjacent reading fox || not_adjacent painting horse then ("", next_permutation pets) else
93+
if selection == englishman then ("Englishman", [1]) else
94+
if selection == japanese then ("Japanese", [1]) else
95+
if selection == norwegian then ("Norwegian", [1]) else
96+
if selection == spaniard then ("Spaniard", [1]) else
97+
if selection == ukrainian then ("Ukrainian", [1]) else
98+
assert false ("", [])
99+
in
100+
(solution5, next_permutation hobbies)
101+
in
102+
(solution4, next_permutation drinks)
103+
in
104+
(solution3, next_permutation colors)
105+
in
106+
(solution2, next_permutation nationalities)
107+
in
108+
solution
109+
110+
def drinks_water: []u8 =
111+
answer #drinks_water
112+
113+
def owns_zebra: []u8 =
114+
answer #owns_zebra
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
[16efb4e4-8ad7-4d5e-ba96-e5537b66fd42]
13+
description = "resident who drinks water"
14+
15+
[084d5b8b-24e2-40e6-b008-c800da8cd257]
16+
description = "resident who owns zebra"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import "zebra_puzzle"
2+
3+
-- resident who drinks water
4+
-- ==
5+
-- entry: test_drinks_water
6+
-- input {}
7+
-- output { "Norwegian" }
8+
9+
-- resident who owns zebra
10+
-- ==
11+
-- entry: test_owns_zebra
12+
-- input {}
13+
-- output { "Japanese" }
14+
15+
entry test_drinks_water: []u8 =
16+
drinks_water
17+
18+
entry test_owns_zebra: []u8 =
19+
owns_zebra
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
def drinks_water: []u8 = ???
2+
3+
def owns_zebra: []u8 = ???

0 commit comments

Comments
 (0)