trackler 1.0.4.0 → 1.0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/common/CONTRIBUTING.md +17 -2
- data/common/exercises/anagram/canonical-data.json +0 -14
- data/common/exercises/pig-latin/canonical-data.json +6 -1
- data/common/exercises/raindrops/description.md +4 -4
- data/common/exercises/raindrops/metadata.yml +1 -1
- data/common/exercises/roman-numerals/metadata.yml +1 -1
- data/lib/trackler/version.rb +1 -1
- data/tracks/c/config.json +12 -1
- data/tracks/c/exercises/roman-numerals/makefile +16 -0
- data/tracks/c/exercises/roman-numerals/src/example.c +43 -0
- data/tracks/c/exercises/roman-numerals/src/example.h +6 -0
- data/tracks/c/exercises/roman-numerals/test/test_roman_numerals.c +126 -0
- data/tracks/c/exercises/roman-numerals/test/vendor/unity.c +1300 -0
- data/tracks/c/exercises/roman-numerals/test/vendor/unity.h +274 -0
- data/tracks/c/exercises/roman-numerals/test/vendor/unity_internals.h +701 -0
- data/tracks/clojure/exercises/flatten-array/project.clj +4 -0
- data/tracks/csharp/exercises/protein-translation/ProteinTranslationTest.cs +1 -1
- data/tracks/elixir/exercises/bowling/bowling_test.exs +157 -62
- data/tracks/elixir/exercises/bowling/example.exs +33 -4
- data/tracks/erlang/config.json +176 -36
- data/tracks/go/.travis.yml +7 -1
- data/tracks/go/bin/test-without-stubs +29 -0
- data/tracks/go/exercises/robot-simulator/defs.go +1 -1
- data/tracks/go/exercises/variable-length-quantity/variable_length_quantity_test.go +31 -25
- data/tracks/haskell/.travis.yml +9 -5
- data/tracks/haskell/config.json +127 -121
- data/tracks/haskell/exercises/leap/src/LeapYear.hs +1 -1
- data/tracks/haskell/exercises/space-age/HINTS.md +14 -2
- data/tracks/haskell/exercises/space-age/{src/Example.hs → examples/success-double/SpaceAge.hs} +0 -0
- data/tracks/haskell/exercises/space-age/examples/success-double/package.yaml +19 -0
- data/tracks/haskell/exercises/space-age/examples/success-rational/SpaceAge.hs +24 -0
- data/tracks/haskell/exercises/space-age/examples/success-rational/package.yaml +19 -0
- data/tracks/haskell/exercises/space-age/src/SpaceAge.hs +4 -1
- data/tracks/haskell/exercises/space-age/test/Tests.hs +12 -5
- data/tracks/haskell/exercises/word-count/HINTS.md +21 -0
- data/tracks/haskell/exercises/word-count/examples/success-newtype/WordCount.hs +31 -0
- data/tracks/haskell/exercises/word-count/examples/success-newtype/package.yaml +21 -0
- data/tracks/haskell/exercises/word-count/examples/success-simple/WordCount.hs +13 -0
- data/tracks/haskell/exercises/word-count/examples/success-simple/package.yaml +20 -0
- data/tracks/haskell/exercises/word-count/package.yaml +0 -2
- data/tracks/haskell/exercises/word-count/src/WordCount.hs +2 -1
- data/tracks/haskell/exercises/word-count/test/Tests.hs +15 -6
- data/tracks/haskell/exercises/zebra-puzzle/package.yaml +19 -0
- data/tracks/haskell/exercises/zebra-puzzle/src/Example.hs +113 -0
- data/tracks/haskell/exercises/zebra-puzzle/src/ZebraPuzzle.hs +12 -0
- data/tracks/haskell/exercises/zebra-puzzle/stack.yaml +1 -0
- data/tracks/haskell/exercises/zebra-puzzle/test/Tests.hs +13 -0
- data/tracks/javascript/exercises/beer-song/beer-song.spec.js +5 -0
- data/tracks/lisp/config.json +147 -0
- data/tracks/ocaml/config.json +12 -0
- data/tracks/ocaml/exercises/atbash-cipher/.merlin +5 -0
- data/tracks/ocaml/exercises/atbash-cipher/HINTS.md +17 -0
- data/tracks/ocaml/exercises/atbash-cipher/Makefile +11 -0
- data/tracks/ocaml/exercises/atbash-cipher/atbash_cipher.mli +5 -0
- data/tracks/ocaml/exercises/atbash-cipher/example.ml +47 -0
- data/tracks/ocaml/exercises/atbash-cipher/test.ml +37 -0
- data/tracks/ocaml/exercises/meetup/.merlin +5 -0
- data/tracks/ocaml/exercises/meetup/Makefile +11 -0
- data/tracks/ocaml/exercises/meetup/example.ml +63 -0
- data/tracks/ocaml/exercises/meetup/meetup.mli +7 -0
- data/tracks/ocaml/exercises/meetup/test.ml +786 -0
- data/tracks/php/exercises/bowling/bowling_test.php +233 -10
- data/tracks/php/exercises/bowling/example.php +49 -6
- data/tracks/python/.travis.yml +5 -0
- data/tracks/python/config.json +33 -1
- data/tracks/python/exercises/flatten-array/example.py +18 -0
- data/tracks/python/exercises/flatten-array/flatten_array_test.py +40 -0
- data/tracks/python/exercises/robot-name/robot_name_test.py +8 -2
- data/tracks/r/config.json +32 -8
- data/tracks/ruby/bin/enable-executable +9 -5
- data/tracks/ruby/bin/executable-tests-check +7 -3
- data/tracks/ruby/bin/local-status-check +4 -4
- data/tracks/ruby/config.json +8 -1
- data/tracks/ruby/exercises/acronym/acronym_test.rb +0 -1
- data/tracks/ruby/exercises/anagram/.version +1 -0
- data/tracks/ruby/exercises/anagram/anagram_test.rb +101 -31
- data/tracks/ruby/exercises/anagram/example.rb +4 -0
- data/tracks/ruby/exercises/anagram/example.tt +19 -0
- data/tracks/ruby/exercises/gigasecond/.version +1 -1
- data/tracks/ruby/exercises/gigasecond/example.rb +1 -1
- data/tracks/ruby/exercises/gigasecond/gigasecond_test.rb +2 -2
- data/tracks/ruby/exercises/isogram/.version +1 -0
- data/tracks/ruby/exercises/isogram/example.rb +10 -0
- data/tracks/ruby/exercises/isogram/example.tt +20 -0
- data/tracks/ruby/exercises/isogram/isogram_test.rb +90 -0
- data/tracks/ruby/exercises/poker/example.rb +97 -39
- data/tracks/ruby/exercises/poker/poker_test.rb +67 -36
- data/tracks/ruby/exercises/sieve/.version +1 -0
- data/tracks/ruby/exercises/sieve/example.rb +4 -0
- data/tracks/ruby/exercises/sieve/example.tt +21 -0
- data/tracks/ruby/exercises/sieve/sieve_test.rb +36 -13
- data/tracks/ruby/exercises/word-count/example.tt +4 -3
- data/tracks/ruby/exercises/word-count/word_count_test.rb +38 -48
- data/tracks/ruby/lib/anagram_cases.rb +42 -0
- data/tracks/ruby/lib/isogram_cases.rb +24 -0
- data/tracks/ruby/lib/sieve_cases.rb +33 -0
- data/tracks/ruby/lib/word_count_cases.rb +19 -0
- data/tracks/scala/config.json +21 -0
- data/tracks/scala/docs/RESOURCES.md +1 -0
- data/tracks/scala/exercises/bracket-push/build.sbt +4 -0
- data/tracks/scala/exercises/bracket-push/example.scala +23 -0
- data/tracks/scala/exercises/bracket-push/src/main/scala/.keep +0 -0
- data/tracks/scala/exercises/bracket-push/src/test/scala/BracketsTest.scala +68 -0
- data/tracks/scala/exercises/change/src/test/scala/ChangeTest.scala +7 -0
- data/tracks/scala/exercises/sgf-parsing/build.sbt +7 -0
- data/tracks/scala/exercises/sgf-parsing/example.scala +66 -0
- data/tracks/scala/exercises/sgf-parsing/src/main/scala/.keep +0 -0
- data/tracks/scala/exercises/sgf-parsing/src/main/scala/Sgf.scala +17 -0
- data/tracks/scala/exercises/sgf-parsing/src/test/scala/SgfTest.scala +66 -0
- data/tracks/scala/exercises/zebra-puzzle/build.sbt +3 -0
- data/tracks/scala/exercises/zebra-puzzle/example.scala +152 -0
- data/tracks/scala/exercises/zebra-puzzle/src/main/scala/.keep +0 -0
- data/tracks/scala/exercises/zebra-puzzle/src/main/scala/ZebraPuzzle.scala +14 -0
- data/tracks/scala/exercises/zebra-puzzle/src/test/scala/ZebraPuzzleTest.scala +11 -0
- data/tracks/scala/testgen/src/main/scala/BracketPushTestGenerator.scala +44 -0
- metadata +63 -3
- data/tracks/haskell/exercises/word-count/src/Example.hs +0 -8
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
## Hints
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
In this exercise, you need to complete the definition of the
|
|
4
|
+
[algebric data data](http://learnyouahaskell.com/making-our-own-types-and-typeclasses)
|
|
5
|
+
named `Planet`, and implement the `ageOn` function, that calculates how many
|
|
6
|
+
years old someone would be on a `Planet`, given an age in seconds.
|
|
7
|
+
|
|
8
|
+
Your can use the provided signature if you are unsure about the types, but
|
|
9
|
+
don't let it restrict your creativity:
|
|
10
|
+
|
|
11
|
+
```haskell
|
|
12
|
+
ageOn :: Planet -> Float -> Float
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Keep in mind that the test suite will not compile until you correctly
|
|
16
|
+
implement the data type `Planet`.
|
data/tracks/haskell/exercises/space-age/{src/Example.hs → examples/success-double/SpaceAge.hs}
RENAMED
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: space-age
|
|
2
|
+
|
|
3
|
+
dependencies:
|
|
4
|
+
- base
|
|
5
|
+
|
|
6
|
+
library:
|
|
7
|
+
exposed-modules: SpaceAge
|
|
8
|
+
source-dirs: src
|
|
9
|
+
dependencies:
|
|
10
|
+
# - foo # List here the packages you
|
|
11
|
+
# - bar # want to use in your solution.
|
|
12
|
+
|
|
13
|
+
tests:
|
|
14
|
+
test:
|
|
15
|
+
main: Tests.hs
|
|
16
|
+
source-dirs: test
|
|
17
|
+
dependencies:
|
|
18
|
+
- space-age
|
|
19
|
+
- hspec
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module SpaceAge (Planet(..), ageOn) where
|
|
2
|
+
|
|
3
|
+
data Planet = Mercury
|
|
4
|
+
| Venus
|
|
5
|
+
| Earth
|
|
6
|
+
| Mars
|
|
7
|
+
| Jupiter
|
|
8
|
+
| Saturn
|
|
9
|
+
| Uranus
|
|
10
|
+
| Neptune
|
|
11
|
+
|
|
12
|
+
ageOn :: Real a => Planet -> a -> Rational
|
|
13
|
+
ageOn planet seconds = toRational seconds / (earthPeriod * planetMultiplier)
|
|
14
|
+
where
|
|
15
|
+
planetMultiplier = case planet of
|
|
16
|
+
Mercury -> 0.2408467
|
|
17
|
+
Venus -> 0.61519726
|
|
18
|
+
Earth -> 1
|
|
19
|
+
Mars -> 1.8808158
|
|
20
|
+
Jupiter -> 11.862615
|
|
21
|
+
Saturn -> 29.447498
|
|
22
|
+
Uranus -> 84.016846
|
|
23
|
+
Neptune -> 164.79132
|
|
24
|
+
earthPeriod = 31557600
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: space-age
|
|
2
|
+
|
|
3
|
+
dependencies:
|
|
4
|
+
- base
|
|
5
|
+
|
|
6
|
+
library:
|
|
7
|
+
exposed-modules: SpaceAge
|
|
8
|
+
source-dirs: src
|
|
9
|
+
dependencies:
|
|
10
|
+
# - foo # List here the packages you
|
|
11
|
+
# - bar # want to use in your solution.
|
|
12
|
+
|
|
13
|
+
tests:
|
|
14
|
+
test:
|
|
15
|
+
main: Tests.hs
|
|
16
|
+
source-dirs: test
|
|
17
|
+
dependencies:
|
|
18
|
+
- space-age
|
|
19
|
+
- hspec
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
{-# LANGUAGE RecordWildCards #-}
|
|
3
3
|
|
|
4
4
|
import Data.Foldable (for_)
|
|
5
|
+
import Data.Function (on)
|
|
5
6
|
import Test.Hspec (Spec, describe, it, shouldBe)
|
|
6
7
|
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith)
|
|
7
8
|
|
|
@@ -14,12 +15,18 @@ specs :: Spec
|
|
|
14
15
|
specs = describe "space-age" $
|
|
15
16
|
describe "ageOn" $ for_ cases test
|
|
16
17
|
where
|
|
17
|
-
|
|
18
|
-
test
|
|
18
|
+
-- Here we used `fromIntegral`, `fromRational` and `toRational` to
|
|
19
|
+
-- generalize the test suite, allowing any function that takes a
|
|
20
|
+
-- `Planet` and a number, returning an instance of `Real`.
|
|
21
|
+
test Case{..} = it description $ expression `shouldBeAround` expected
|
|
19
22
|
where
|
|
20
|
-
expression
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
expression = fromRational
|
|
24
|
+
. toRational
|
|
25
|
+
. ageOn planet
|
|
26
|
+
. fromIntegral
|
|
27
|
+
$ seconds
|
|
28
|
+
shouldBeAround = shouldBe `on` roundTo 2
|
|
29
|
+
roundTo n = (/ 10 ^ n) . fromIntegral . round . (* 10 ^ n)
|
|
23
30
|
|
|
24
31
|
-- Test cases adapted from `exercism/x-common/space-age.json` on 2016-07-27.
|
|
25
32
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
## Hints
|
|
2
|
+
|
|
3
|
+
To complete this exercise you need to implement the function `wordCount`,
|
|
4
|
+
that takes a *text* and returns how many times each *word* appears.
|
|
5
|
+
|
|
6
|
+
If it is your first time solving this exercise, it is recommended that you
|
|
7
|
+
stick to the provided signature:
|
|
8
|
+
|
|
9
|
+
```haskell
|
|
10
|
+
wordCount :: String -> [(String, Int)]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Later, it may be a good idea to revisit this problem and play with other data
|
|
14
|
+
types and libraries:
|
|
15
|
+
|
|
16
|
+
- `Text`, from package *text*.
|
|
17
|
+
- `Map`, from package *containers*.
|
|
18
|
+
- `MultiSet`, from package *multiset*
|
|
19
|
+
|
|
20
|
+
The test suite was intentionally designed to accept almost any type signature
|
|
21
|
+
that makes sense, so you are encouraged to find the one you think is the best.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{-# LANGUAGE TypeFamilies #-}
|
|
2
|
+
|
|
3
|
+
module WordCount (wordCount) where
|
|
4
|
+
|
|
5
|
+
import Prelude hiding (null)
|
|
6
|
+
import Data.Char (isAlphaNum)
|
|
7
|
+
import Data.Text (Text, null, split, toLower)
|
|
8
|
+
import Data.MultiSet (MultiSet, Occur, fromList, fromOccurList, toOccurList)
|
|
9
|
+
|
|
10
|
+
import qualified GHC.Exts (IsList(..))
|
|
11
|
+
|
|
12
|
+
wordCount :: Text -> Bag Text
|
|
13
|
+
wordCount = Bag
|
|
14
|
+
. fromList
|
|
15
|
+
. map toLower
|
|
16
|
+
. wordsBy (not . isAlphaNum)
|
|
17
|
+
|
|
18
|
+
-- The `text` package misses this function that
|
|
19
|
+
-- exists in package `split`, but works on lists.
|
|
20
|
+
wordsBy :: (Char -> Bool) -> Text -> [Text]
|
|
21
|
+
wordsBy p = filter (not . null) . split p
|
|
22
|
+
|
|
23
|
+
-- MultiSet is not an instance of `IsList`, so we create
|
|
24
|
+
-- a newtype to wrap it, avoiding an orphan instance.
|
|
25
|
+
newtype Bag a = Bag { toMultiSet :: MultiSet a }
|
|
26
|
+
|
|
27
|
+
instance (Ord a) => GHC.Exts.IsList (Bag a)
|
|
28
|
+
where
|
|
29
|
+
type Item (Bag a) = (a, Occur)
|
|
30
|
+
fromList = Bag . fromOccurList
|
|
31
|
+
toList = toOccurList . toMultiSet
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: word-count
|
|
2
|
+
|
|
3
|
+
dependencies:
|
|
4
|
+
- base
|
|
5
|
+
|
|
6
|
+
library:
|
|
7
|
+
exposed-modules: WordCount
|
|
8
|
+
source-dirs: src
|
|
9
|
+
dependencies:
|
|
10
|
+
# - foo # List here the packages you
|
|
11
|
+
# - bar # want to use in your solution.
|
|
12
|
+
- multiset
|
|
13
|
+
- text
|
|
14
|
+
|
|
15
|
+
tests:
|
|
16
|
+
test:
|
|
17
|
+
main: Tests.hs
|
|
18
|
+
source-dirs: test
|
|
19
|
+
dependencies:
|
|
20
|
+
- word-count
|
|
21
|
+
- hspec
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module WordCount (wordCount) where
|
|
2
|
+
|
|
3
|
+
import Control.Arrow ((&&&))
|
|
4
|
+
import Data.Char (toLower, isAlphaNum)
|
|
5
|
+
import Data.List (group, sort)
|
|
6
|
+
import Data.List.Split (wordsBy)
|
|
7
|
+
|
|
8
|
+
wordCount :: String -> [(String, Int)]
|
|
9
|
+
wordCount = map (head &&& length)
|
|
10
|
+
. group
|
|
11
|
+
. sort
|
|
12
|
+
. map (map toLower)
|
|
13
|
+
. wordsBy (not . isAlphaNum)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: word-count
|
|
2
|
+
|
|
3
|
+
dependencies:
|
|
4
|
+
- base
|
|
5
|
+
|
|
6
|
+
library:
|
|
7
|
+
exposed-modules: WordCount
|
|
8
|
+
source-dirs: src
|
|
9
|
+
dependencies:
|
|
10
|
+
# - foo # List here the packages you
|
|
11
|
+
# - bar # want to use in your solution.
|
|
12
|
+
- split
|
|
13
|
+
|
|
14
|
+
tests:
|
|
15
|
+
test:
|
|
16
|
+
main: Tests.hs
|
|
17
|
+
source-dirs: test
|
|
18
|
+
dependencies:
|
|
19
|
+
- word-count
|
|
20
|
+
- hspec
|
|
@@ -2,7 +2,6 @@ name: word-count
|
|
|
2
2
|
|
|
3
3
|
dependencies:
|
|
4
4
|
- base
|
|
5
|
-
- containers
|
|
6
5
|
|
|
7
6
|
library:
|
|
8
7
|
exposed-modules: WordCount
|
|
@@ -10,7 +9,6 @@ library:
|
|
|
10
9
|
dependencies:
|
|
11
10
|
# - foo # List here the packages you
|
|
12
11
|
# - bar # want to use in your solution.
|
|
13
|
-
- split
|
|
14
12
|
|
|
15
13
|
tests:
|
|
16
14
|
test:
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
|
|
2
2
|
{-# LANGUAGE RecordWildCards #-}
|
|
3
3
|
|
|
4
|
+
import Data.Bifunctor (bimap)
|
|
5
|
+
import Data.Char (toLower)
|
|
4
6
|
import Data.Foldable (for_)
|
|
5
|
-
import
|
|
6
|
-
import Test.Hspec (Spec, describe, it,
|
|
7
|
+
import GHC.Exts (fromList, toList)
|
|
8
|
+
import Test.Hspec (Spec, describe, it, shouldMatchList)
|
|
7
9
|
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith)
|
|
8
10
|
|
|
9
11
|
import WordCount (wordCount)
|
|
@@ -15,11 +17,18 @@ specs :: Spec
|
|
|
15
17
|
specs = describe "word-count" $
|
|
16
18
|
describe "wordCount" $ for_ cases test
|
|
17
19
|
where
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
-- Here we used `fromIntegral`, `fromList` and `toList` to generalize
|
|
21
|
+
-- the tests, accepting any function that receives a string-like argumment
|
|
22
|
+
-- and returns a type that can be converted to [(String, Integer)].
|
|
23
|
+
-- Also, the words are lower-cased before comparison and the output's
|
|
24
|
+
-- order is ignored.
|
|
25
|
+
test Case{..} = it description $ expression `shouldMatchList` expected
|
|
20
26
|
where
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
expression = map (bimap (map toLower . toList) fromIntegral)
|
|
28
|
+
. toList
|
|
29
|
+
. wordCount
|
|
30
|
+
. fromList
|
|
31
|
+
$ input
|
|
23
32
|
|
|
24
33
|
-- Test cases adapted from `exercism/x-common/word-count.json` on 2016-07-26.
|
|
25
34
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: zebra-puzzle
|
|
2
|
+
|
|
3
|
+
dependencies:
|
|
4
|
+
- base
|
|
5
|
+
|
|
6
|
+
library:
|
|
7
|
+
exposed-modules: ZebraPuzzle
|
|
8
|
+
source-dirs: src
|
|
9
|
+
dependencies:
|
|
10
|
+
# - foo # List here the packages you
|
|
11
|
+
# - bar # want to use in your solution.
|
|
12
|
+
|
|
13
|
+
tests:
|
|
14
|
+
test:
|
|
15
|
+
main: Tests.hs
|
|
16
|
+
source-dirs: test
|
|
17
|
+
dependencies:
|
|
18
|
+
- zebra-puzzle
|
|
19
|
+
- hspec
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
module ZebraPuzzle (Resident(..), Solution(..), solve) where
|
|
2
|
+
|
|
3
|
+
import Control.Monad (guard)
|
|
4
|
+
import Data.List (nub, find)
|
|
5
|
+
import Data.Maybe (fromJust)
|
|
6
|
+
|
|
7
|
+
data Color = Red | Green | Yellow | Blue | Ivory
|
|
8
|
+
deriving (Eq, Show, Enum)
|
|
9
|
+
data Resident = Englishman | Spaniard | Ukrainian | Norwegian | Japanese
|
|
10
|
+
deriving (Eq, Show, Enum)
|
|
11
|
+
data Pet = Dog | Snails | Fox | Horse | Zebra
|
|
12
|
+
deriving (Eq, Show, Enum)
|
|
13
|
+
data Beverage = Coffee | Tea | Milk | OrangeJuice | Water
|
|
14
|
+
deriving (Eq, Show, Enum)
|
|
15
|
+
data Cigarette = OldGold | Kools | Chesterfields | LuckyStrike | Parliaments
|
|
16
|
+
deriving (Eq, Show, Enum)
|
|
17
|
+
data Position = One | Two | Three | Four | Five
|
|
18
|
+
deriving (Eq, Show, Enum)
|
|
19
|
+
|
|
20
|
+
data House = House { position :: Position
|
|
21
|
+
, color :: Color
|
|
22
|
+
, resident :: Resident
|
|
23
|
+
, beverage :: Beverage
|
|
24
|
+
, cigarette :: Cigarette
|
|
25
|
+
, pet :: Pet
|
|
26
|
+
} deriving (Show)
|
|
27
|
+
|
|
28
|
+
data Solution = Solution { waterDrinker :: Resident
|
|
29
|
+
, zebraOwner :: Resident
|
|
30
|
+
} deriving (Eq, Show)
|
|
31
|
+
|
|
32
|
+
solve :: Solution
|
|
33
|
+
solve = Solution waterDrinker' zebraOwner'
|
|
34
|
+
where
|
|
35
|
+
waterDrinker' = residentWith beverage Water
|
|
36
|
+
zebraOwner' = residentWith pet Zebra
|
|
37
|
+
residentWith :: (Eq a) => (House -> a) -> a -> Resident
|
|
38
|
+
residentWith what value = resident $ houseWith what value fiveHouses
|
|
39
|
+
|
|
40
|
+
fiveHouses :: [House]
|
|
41
|
+
fiveHouses = head $ do
|
|
42
|
+
one <- housesAtPosition One
|
|
43
|
+
two <- housesAtPosition Two
|
|
44
|
+
guard $ uniqueHouses [one, two] -- prune search tree as early as possible
|
|
45
|
+
three <- housesAtPosition Three
|
|
46
|
+
guard $ uniqueHouses [one, two, three]
|
|
47
|
+
four <- housesAtPosition Four
|
|
48
|
+
guard $ uniqueHouses [one, two, three, four]
|
|
49
|
+
five <- housesAtPosition Five
|
|
50
|
+
let candidates = [one, two, three, four, five]
|
|
51
|
+
guard $ uniqueHouses candidates
|
|
52
|
+
guard $ validPositions candidates
|
|
53
|
+
return candidates
|
|
54
|
+
where
|
|
55
|
+
housesAtPosition :: Position -> [House]
|
|
56
|
+
housesAtPosition pos = filter ((== pos) . position) validHouses
|
|
57
|
+
|
|
58
|
+
validHouses :: [House]
|
|
59
|
+
validHouses = do
|
|
60
|
+
position' <- [One .. Five]
|
|
61
|
+
color' <- [Red .. Ivory]
|
|
62
|
+
resident' <- [Englishman .. Japanese]
|
|
63
|
+
beverage' <- [Coffee .. Water]
|
|
64
|
+
cigarette' <- [OldGold .. Parliaments]
|
|
65
|
+
pet' <- [Dog .. Zebra]
|
|
66
|
+
let house = House position' color' resident' beverage' cigarette' pet'
|
|
67
|
+
guard $ validHouse house
|
|
68
|
+
return house
|
|
69
|
+
|
|
70
|
+
validHouse :: House -> Bool
|
|
71
|
+
validHouse (House position' color' resident' beverage' cigarette' pet') =
|
|
72
|
+
all (uncurry iff) [
|
|
73
|
+
(color' == Red, resident' == Englishman),
|
|
74
|
+
(resident' == Spaniard, pet' == Dog),
|
|
75
|
+
(color' == Green, beverage' == Coffee),
|
|
76
|
+
(resident' == Ukrainian, beverage' == Tea),
|
|
77
|
+
(cigarette' == OldGold, pet' == Snails),
|
|
78
|
+
(color' == Yellow, cigarette' == Kools),
|
|
79
|
+
(position' == Three, beverage' == Milk),
|
|
80
|
+
(position' == One, resident' == Norwegian),
|
|
81
|
+
(beverage' == OrangeJuice, cigarette' == LuckyStrike),
|
|
82
|
+
(resident' == Japanese, cigarette' == Parliaments)
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
iff :: Bool -> Bool -> Bool
|
|
86
|
+
iff True True = True
|
|
87
|
+
iff False False = True
|
|
88
|
+
iff _ _ = False
|
|
89
|
+
|
|
90
|
+
uniqueHouses :: [House] -> Bool
|
|
91
|
+
uniqueHouses houses =
|
|
92
|
+
unique color && unique resident && unique beverage &&
|
|
93
|
+
unique cigarette && unique pet
|
|
94
|
+
where
|
|
95
|
+
unique :: (Eq a) => (House -> a) -> Bool
|
|
96
|
+
unique what = (== length houses) . length . nub $ map what houses
|
|
97
|
+
|
|
98
|
+
houseWith :: (Eq a) => (House -> a) -> a -> [House] -> House
|
|
99
|
+
houseWith what value = fromJust . find ((== value) . what)
|
|
100
|
+
|
|
101
|
+
validPositions :: [House] -> Bool
|
|
102
|
+
validPositions houses =
|
|
103
|
+
houseWith' color Green `toTheRight` houseWith' color Ivory &&
|
|
104
|
+
houseWith' cigarette Chesterfields `nextTo` houseWith' pet Fox &&
|
|
105
|
+
houseWith' cigarette Kools `nextTo` houseWith' pet Horse &&
|
|
106
|
+
houseWith' resident Norwegian `nextTo` houseWith' color Blue
|
|
107
|
+
where
|
|
108
|
+
houseWith' what value = houseWith what value houses
|
|
109
|
+
toTheRight :: House -> House -> Bool
|
|
110
|
+
toTheRight h1 h2 = fromEnum (position h1) == fromEnum (position h2) + 1
|
|
111
|
+
nextTo :: House -> House -> Bool
|
|
112
|
+
nextTo h1 h2 = abs (fromEnum (position h1) - fromEnum (position h2)) == 1
|
|
113
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module ZebraPuzzle (Resident(..), Solution(..), solve) where
|
|
2
|
+
|
|
3
|
+
data Resident = Englishman | Spaniard | Ukrainian | Norwegian | Japanese
|
|
4
|
+
deriving (Eq, Show)
|
|
5
|
+
|
|
6
|
+
data Solution = Solution { waterDrinker :: Resident
|
|
7
|
+
, zebraOwner :: Resident
|
|
8
|
+
} deriving (Eq, Show)
|
|
9
|
+
|
|
10
|
+
solve :: Solution
|
|
11
|
+
solve = undefined
|
|
12
|
+
|