diff --git a/bin/add-practice-exercise b/bin/add-practice-exercise index 114f3f2..c12a0d7 100755 --- a/bin/add-practice-exercise +++ b/bin/add-practice-exercise @@ -67,7 +67,7 @@ fi ./bin/fetch-configlet ./bin/configlet create --practice-exercise "${slug}" --author "${author}" --difficulty "${difficulty}" -filter='.exercises.practice = (.exercises.practice | sort_by(.difficulty, (.name|ascii_upcase))' +filter='.exercises.practice = (.exercises.practice | sort_by(.difficulty, (.name|ascii_upcase)))' jq "${filter}" config.json > config.sorted && mv config.sorted config.json exercise_dir="exercises/practice/${slug}" diff --git a/config.json b/config.json index 11ec49d..4a0afe0 100644 --- a/config.json +++ b/config.json @@ -1459,6 +1459,14 @@ "strings" ] }, + { + "slug": "zebra-puzzle", + "name": "Zebra Puzzle", + "uuid": "87be2159-daf5-4a6f-b7e1-61dc93edb1e7", + "practices": [], + "prerequisites": [], + "difficulty": 8 + }, { "slug": "pov", "name": "POV", diff --git a/exercises/practice/zebra-puzzle/.busted b/exercises/practice/zebra-puzzle/.busted new file mode 100644 index 0000000..86b84e7 --- /dev/null +++ b/exercises/practice/zebra-puzzle/.busted @@ -0,0 +1,5 @@ +return { + default = { + ROOT = { '.' } + } +} diff --git a/exercises/practice/zebra-puzzle/.docs/instructions.md b/exercises/practice/zebra-puzzle/.docs/instructions.md new file mode 100644 index 0000000..aedce9b --- /dev/null +++ b/exercises/practice/zebra-puzzle/.docs/instructions.md @@ -0,0 +1,32 @@ +# Instructions + +Your task is to solve the Zebra Puzzle to find the answer to these two questions: + +- Which of the residents drinks water? +- Who owns the zebra? + +## Puzzle + +The following 15 statements are all known to be true: + +1. There are five houses. +2. The Englishman lives in the red house. +3. The Spaniard owns the dog. +4. The person in the green house drinks coffee. +5. The Ukrainian drinks tea. +6. The green house is immediately to the right of the ivory house. +7. The snail owner likes to go dancing. +8. The person in the yellow house is a painter. +9. The person in the middle house drinks milk. +10. The Norwegian lives in the first house. +11. The person who enjoys reading lives in the house next to the person with the fox. +12. The painter's house is next to the house with the horse. +13. The person who plays football drinks orange juice. +14. The Japanese person plays chess. +15. The Norwegian lives next to the blue house. + +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. + +~~~~exercism/note +There are 24 billion (5!⁵ = 24,883,200,000) possible solutions, so try ruling out as many solutions as possible. +~~~~ diff --git a/exercises/practice/zebra-puzzle/.docs/introduction.md b/exercises/practice/zebra-puzzle/.docs/introduction.md new file mode 100644 index 0000000..bbcaa6f --- /dev/null +++ b/exercises/practice/zebra-puzzle/.docs/introduction.md @@ -0,0 +1,15 @@ +# Introduction + +The Zebra Puzzle is a famous logic puzzle in which there are five houses, each painted a different color. +The houses have different inhabitants, who have different nationalities, own different pets, drink different beverages and enjoy different hobbies. + +To help you solve the puzzle, you're given 15 statements describing the solution. +However, only by combining the information in _all_ statements will you be able to find the solution to the puzzle. + +~~~~exercism/note +The Zebra Puzzle is a [Constraint satisfaction problem (CSP)][constraint-satisfaction-problem]. +In such a problem, you have a set of possible values and a set of constraints that limit which values are valid. +Another well-known CSP is Sudoku. + +[constraint-satisfaction-problem]: https://en.wikipedia.org/wiki/Constraint_satisfaction_problem +~~~~ diff --git a/exercises/practice/zebra-puzzle/.meta/config.json b/exercises/practice/zebra-puzzle/.meta/config.json new file mode 100644 index 0000000..017d98d --- /dev/null +++ b/exercises/practice/zebra-puzzle/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "zebra-puzzle.lua" + ], + "test": [ + "zebra-puzzle_spec.lua" + ], + "example": [ + ".meta/example.lua" + ] + }, + "blurb": "Solve the zebra puzzle.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Zebra_Puzzle" +} diff --git a/exercises/practice/zebra-puzzle/.meta/example.lua b/exercises/practice/zebra-puzzle/.meta/example.lua new file mode 100644 index 0000000..4747f25 --- /dev/null +++ b/exercises/practice/zebra-puzzle/.meta/example.lua @@ -0,0 +1,115 @@ +local zebra_puzzle = {} + +local function permutations(a) + local n + + return function() + if not n then + n = #a + return a + end + + -- Step 1. Find largest j such that a[j] > a[j + 1]. + local j = n - 1 + while j >= 1 and a[j] <= a[j + 1] do + j = j - 1 + end + if j < 1 then + return nil + end + + -- Step 2. Find largest l such that a[j] > a[l], then swap. + local l = n + while a[j] <= a[l] do + l = l - 1 + end + a[j], a[l] = a[l], a[j] + + -- Step 3. Reverse a[j+1] ... a[n]. + local lo, hi = j + 1, n + while lo < hi do + a[lo], a[hi] = a[hi], a[lo] + lo = lo + 1 + hi = hi - 1 + end + + return a + end +end + +local function index_of(t, val) + for i, v in ipairs(t) do + if v == val then + return i + end + end + return nil +end + +local function next_to(a, b) + return math.abs(a - b) == 1 +end + +local water_drinker, zebra_owner + +local function solve() + for colors in permutations({ 'yellow', 'red', 'ivory', 'green', 'blue' }) do + -- 6. The green house is immediately to the right of the ivory house. + if index_of(colors, 'green') == index_of(colors, 'ivory') + 1 then + for drinks in permutations({ 'water', 'tea', 'orange juice', 'milk', 'coffee' }) do + -- 4. Coffee is drunk in the green house. + -- 9. Milk is drunk in the middle house. + if index_of(drinks, 'coffee') == index_of(colors, 'green') and drinks[3] == 'milk' then + for hobbies in permutations({ 'reading', 'painting', 'football', 'dancing', 'chess' }) do + -- 8. The person in the yellow house is a painter. + -- 13. The person who plays football drinks orange juice. + if index_of(hobbies, 'painting') == index_of(colors, 'yellow') and index_of(hobbies, 'football') == + index_of(drinks, 'orange juice') then + for nationalities in permutations({ 'Ukrainian', 'Spaniard', 'Norwegian', 'Japanese', 'Englishman' }) do + -- 10. The Norwegian lives in the first house. + -- 2. The Englishman lives in the red house. + -- 15. The Norwegian lives next to the blue house. + -- 5. The Ukrainian drinks tea. + -- 14. The Japanese person plays chess. + if nationalities[1] == 'Norwegian' and index_of(colors, 'red') == index_of(nationalities, 'Englishman') and + next_to(index_of(nationalities, 'Norwegian'), index_of(colors, 'blue')) and index_of(drinks, 'tea') == + index_of(nationalities, 'Ukrainian') and index_of(hobbies, 'chess') == + index_of(nationalities, 'Japanese') then + for pets in permutations({ 'zebra', 'snail', 'horse', 'fox', 'dog' }) do + -- 3. The Spaniard owns the dog. + -- 7. The snail owner likes to go dancing. + -- 11. The person who enjoys reading lives in the house next to the person with the fox. + -- 12. The painter's house is next to the house with the horse. + if index_of(pets, 'dog') == index_of(nationalities, 'Spaniard') and index_of(pets, 'snail') == + index_of(hobbies, 'dancing') and next_to(index_of(hobbies, 'reading'), index_of(pets, 'fox')) and + next_to(index_of(hobbies, 'painting'), index_of(pets, 'horse')) then + return nationalities[index_of(drinks, 'water')], nationalities[index_of(pets, 'zebra')] + end + end + end + end + end + end + end + end + end + end +end + +local function ensure_solved() + if not water_drinker then + water_drinker, zebra_owner = solve() + end +end + +function zebra_puzzle.drinks_water() + ensure_solved() + return water_drinker +end + +function zebra_puzzle.owns_zebra() + ensure_solved() + return zebra_owner +end + +return zebra_puzzle diff --git a/exercises/practice/zebra-puzzle/.meta/spec_generator.lua b/exercises/practice/zebra-puzzle/.meta/spec_generator.lua new file mode 100644 index 0000000..e3e3997 --- /dev/null +++ b/exercises/practice/zebra-puzzle/.meta/spec_generator.lua @@ -0,0 +1,19 @@ +local function snake_case(str) + local s = str:gsub('%u', function(c) + return '_' .. c:lower() + end) + if s:sub(1, 1) == '_' then + s = s:sub(2) + end + return s +end + +return { + module_name = 'zebra_puzzle', + + generate_test = function(case) + local template = [[ + assert.equal('%s', zebra_puzzle.%s())]] + return template:format(case.expected, snake_case(case.property)) + end +} diff --git a/exercises/practice/zebra-puzzle/.meta/tests.toml b/exercises/practice/zebra-puzzle/.meta/tests.toml new file mode 100644 index 0000000..56c21c7 --- /dev/null +++ b/exercises/practice/zebra-puzzle/.meta/tests.toml @@ -0,0 +1,16 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[16efb4e4-8ad7-4d5e-ba96-e5537b66fd42] +description = "resident who drinks water" + +[084d5b8b-24e2-40e6-b008-c800da8cd257] +description = "resident who owns zebra" diff --git a/exercises/practice/zebra-puzzle/zebra-puzzle.lua b/exercises/practice/zebra-puzzle/zebra-puzzle.lua new file mode 100644 index 0000000..723094e --- /dev/null +++ b/exercises/practice/zebra-puzzle/zebra-puzzle.lua @@ -0,0 +1,9 @@ +local zebra_puzzle = {} + +function zebra_puzzle.drinks_water() +end + +function zebra_puzzle.owns_zebra() +end + +return zebra_puzzle diff --git a/exercises/practice/zebra-puzzle/zebra-puzzle_spec.lua b/exercises/practice/zebra-puzzle/zebra-puzzle_spec.lua new file mode 100644 index 0000000..bf18f74 --- /dev/null +++ b/exercises/practice/zebra-puzzle/zebra-puzzle_spec.lua @@ -0,0 +1,11 @@ +local zebra_puzzle = require('zebra-puzzle') + +describe('zebra-puzzle', function() + it('resident who drinks water', function() + assert.equal('Norwegian', zebra_puzzle.drinks_water()) + end) + + it('resident who owns zebra', function() + assert.equal('Japanese', zebra_puzzle.owns_zebra()) + end) +end)