trackler 1.0.4.0 → 1.0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/common/CONTRIBUTING.md +17 -2
  3. data/common/exercises/anagram/canonical-data.json +0 -14
  4. data/common/exercises/pig-latin/canonical-data.json +6 -1
  5. data/common/exercises/raindrops/description.md +4 -4
  6. data/common/exercises/raindrops/metadata.yml +1 -1
  7. data/common/exercises/roman-numerals/metadata.yml +1 -1
  8. data/lib/trackler/version.rb +1 -1
  9. data/tracks/c/config.json +12 -1
  10. data/tracks/c/exercises/roman-numerals/makefile +16 -0
  11. data/tracks/c/exercises/roman-numerals/src/example.c +43 -0
  12. data/tracks/c/exercises/roman-numerals/src/example.h +6 -0
  13. data/tracks/c/exercises/roman-numerals/test/test_roman_numerals.c +126 -0
  14. data/tracks/c/exercises/roman-numerals/test/vendor/unity.c +1300 -0
  15. data/tracks/c/exercises/roman-numerals/test/vendor/unity.h +274 -0
  16. data/tracks/c/exercises/roman-numerals/test/vendor/unity_internals.h +701 -0
  17. data/tracks/clojure/exercises/flatten-array/project.clj +4 -0
  18. data/tracks/csharp/exercises/protein-translation/ProteinTranslationTest.cs +1 -1
  19. data/tracks/elixir/exercises/bowling/bowling_test.exs +157 -62
  20. data/tracks/elixir/exercises/bowling/example.exs +33 -4
  21. data/tracks/erlang/config.json +176 -36
  22. data/tracks/go/.travis.yml +7 -1
  23. data/tracks/go/bin/test-without-stubs +29 -0
  24. data/tracks/go/exercises/robot-simulator/defs.go +1 -1
  25. data/tracks/go/exercises/variable-length-quantity/variable_length_quantity_test.go +31 -25
  26. data/tracks/haskell/.travis.yml +9 -5
  27. data/tracks/haskell/config.json +127 -121
  28. data/tracks/haskell/exercises/leap/src/LeapYear.hs +1 -1
  29. data/tracks/haskell/exercises/space-age/HINTS.md +14 -2
  30. data/tracks/haskell/exercises/space-age/{src/Example.hs → examples/success-double/SpaceAge.hs} +0 -0
  31. data/tracks/haskell/exercises/space-age/examples/success-double/package.yaml +19 -0
  32. data/tracks/haskell/exercises/space-age/examples/success-rational/SpaceAge.hs +24 -0
  33. data/tracks/haskell/exercises/space-age/examples/success-rational/package.yaml +19 -0
  34. data/tracks/haskell/exercises/space-age/src/SpaceAge.hs +4 -1
  35. data/tracks/haskell/exercises/space-age/test/Tests.hs +12 -5
  36. data/tracks/haskell/exercises/word-count/HINTS.md +21 -0
  37. data/tracks/haskell/exercises/word-count/examples/success-newtype/WordCount.hs +31 -0
  38. data/tracks/haskell/exercises/word-count/examples/success-newtype/package.yaml +21 -0
  39. data/tracks/haskell/exercises/word-count/examples/success-simple/WordCount.hs +13 -0
  40. data/tracks/haskell/exercises/word-count/examples/success-simple/package.yaml +20 -0
  41. data/tracks/haskell/exercises/word-count/package.yaml +0 -2
  42. data/tracks/haskell/exercises/word-count/src/WordCount.hs +2 -1
  43. data/tracks/haskell/exercises/word-count/test/Tests.hs +15 -6
  44. data/tracks/haskell/exercises/zebra-puzzle/package.yaml +19 -0
  45. data/tracks/haskell/exercises/zebra-puzzle/src/Example.hs +113 -0
  46. data/tracks/haskell/exercises/zebra-puzzle/src/ZebraPuzzle.hs +12 -0
  47. data/tracks/haskell/exercises/zebra-puzzle/stack.yaml +1 -0
  48. data/tracks/haskell/exercises/zebra-puzzle/test/Tests.hs +13 -0
  49. data/tracks/javascript/exercises/beer-song/beer-song.spec.js +5 -0
  50. data/tracks/lisp/config.json +147 -0
  51. data/tracks/ocaml/config.json +12 -0
  52. data/tracks/ocaml/exercises/atbash-cipher/.merlin +5 -0
  53. data/tracks/ocaml/exercises/atbash-cipher/HINTS.md +17 -0
  54. data/tracks/ocaml/exercises/atbash-cipher/Makefile +11 -0
  55. data/tracks/ocaml/exercises/atbash-cipher/atbash_cipher.mli +5 -0
  56. data/tracks/ocaml/exercises/atbash-cipher/example.ml +47 -0
  57. data/tracks/ocaml/exercises/atbash-cipher/test.ml +37 -0
  58. data/tracks/ocaml/exercises/meetup/.merlin +5 -0
  59. data/tracks/ocaml/exercises/meetup/Makefile +11 -0
  60. data/tracks/ocaml/exercises/meetup/example.ml +63 -0
  61. data/tracks/ocaml/exercises/meetup/meetup.mli +7 -0
  62. data/tracks/ocaml/exercises/meetup/test.ml +786 -0
  63. data/tracks/php/exercises/bowling/bowling_test.php +233 -10
  64. data/tracks/php/exercises/bowling/example.php +49 -6
  65. data/tracks/python/.travis.yml +5 -0
  66. data/tracks/python/config.json +33 -1
  67. data/tracks/python/exercises/flatten-array/example.py +18 -0
  68. data/tracks/python/exercises/flatten-array/flatten_array_test.py +40 -0
  69. data/tracks/python/exercises/robot-name/robot_name_test.py +8 -2
  70. data/tracks/r/config.json +32 -8
  71. data/tracks/ruby/bin/enable-executable +9 -5
  72. data/tracks/ruby/bin/executable-tests-check +7 -3
  73. data/tracks/ruby/bin/local-status-check +4 -4
  74. data/tracks/ruby/config.json +8 -1
  75. data/tracks/ruby/exercises/acronym/acronym_test.rb +0 -1
  76. data/tracks/ruby/exercises/anagram/.version +1 -0
  77. data/tracks/ruby/exercises/anagram/anagram_test.rb +101 -31
  78. data/tracks/ruby/exercises/anagram/example.rb +4 -0
  79. data/tracks/ruby/exercises/anagram/example.tt +19 -0
  80. data/tracks/ruby/exercises/gigasecond/.version +1 -1
  81. data/tracks/ruby/exercises/gigasecond/example.rb +1 -1
  82. data/tracks/ruby/exercises/gigasecond/gigasecond_test.rb +2 -2
  83. data/tracks/ruby/exercises/isogram/.version +1 -0
  84. data/tracks/ruby/exercises/isogram/example.rb +10 -0
  85. data/tracks/ruby/exercises/isogram/example.tt +20 -0
  86. data/tracks/ruby/exercises/isogram/isogram_test.rb +90 -0
  87. data/tracks/ruby/exercises/poker/example.rb +97 -39
  88. data/tracks/ruby/exercises/poker/poker_test.rb +67 -36
  89. data/tracks/ruby/exercises/sieve/.version +1 -0
  90. data/tracks/ruby/exercises/sieve/example.rb +4 -0
  91. data/tracks/ruby/exercises/sieve/example.tt +21 -0
  92. data/tracks/ruby/exercises/sieve/sieve_test.rb +36 -13
  93. data/tracks/ruby/exercises/word-count/example.tt +4 -3
  94. data/tracks/ruby/exercises/word-count/word_count_test.rb +38 -48
  95. data/tracks/ruby/lib/anagram_cases.rb +42 -0
  96. data/tracks/ruby/lib/isogram_cases.rb +24 -0
  97. data/tracks/ruby/lib/sieve_cases.rb +33 -0
  98. data/tracks/ruby/lib/word_count_cases.rb +19 -0
  99. data/tracks/scala/config.json +21 -0
  100. data/tracks/scala/docs/RESOURCES.md +1 -0
  101. data/tracks/scala/exercises/bracket-push/build.sbt +4 -0
  102. data/tracks/scala/exercises/bracket-push/example.scala +23 -0
  103. data/tracks/scala/exercises/bracket-push/src/main/scala/.keep +0 -0
  104. data/tracks/scala/exercises/bracket-push/src/test/scala/BracketsTest.scala +68 -0
  105. data/tracks/scala/exercises/change/src/test/scala/ChangeTest.scala +7 -0
  106. data/tracks/scala/exercises/sgf-parsing/build.sbt +7 -0
  107. data/tracks/scala/exercises/sgf-parsing/example.scala +66 -0
  108. data/tracks/scala/exercises/sgf-parsing/src/main/scala/.keep +0 -0
  109. data/tracks/scala/exercises/sgf-parsing/src/main/scala/Sgf.scala +17 -0
  110. data/tracks/scala/exercises/sgf-parsing/src/test/scala/SgfTest.scala +66 -0
  111. data/tracks/scala/exercises/zebra-puzzle/build.sbt +3 -0
  112. data/tracks/scala/exercises/zebra-puzzle/example.scala +152 -0
  113. data/tracks/scala/exercises/zebra-puzzle/src/main/scala/.keep +0 -0
  114. data/tracks/scala/exercises/zebra-puzzle/src/main/scala/ZebraPuzzle.scala +14 -0
  115. data/tracks/scala/exercises/zebra-puzzle/src/test/scala/ZebraPuzzleTest.scala +11 -0
  116. data/tracks/scala/testgen/src/main/scala/BracketPushTestGenerator.scala +44 -0
  117. metadata +63 -3
  118. data/tracks/haskell/exercises/word-count/src/Example.hs +0 -8
@@ -1,4 +1,4 @@
1
1
  module LeapYear (isLeapYear) where
2
2
 
3
3
  isLeapYear :: Integer -> Bool
4
- isLeapYear = undefined
4
+ isLeapYear year = undefined
@@ -1,4 +1,16 @@
1
1
  ## Hints
2
2
 
3
- To complete this exercise, you need to create the data type `Planet`
4
- and implement the `ageOn` function.
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`.
@@ -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
@@ -1,3 +1,6 @@
1
1
  module SpaceAge (Planet(..), ageOn) where
2
2
 
3
- ageOn = undefined
3
+ data Planet
4
+
5
+ ageOn :: Planet -> Float -> Float
6
+ ageOn planet seconds = undefined
@@ -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 Case{..} = it description assertion
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 = ageOn planet $ fromIntegral seconds
21
- assertion = roundAge expression `shouldBe` roundAge expected
22
- roundAge = (/ 100) . fromIntegral . round . (* 100)
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,3 +1,4 @@
1
1
  module WordCount (wordCount) where
2
2
 
3
- wordCount = undefined
3
+ wordCount :: String -> [(String, Int)]
4
+ wordCount xs = undefined
@@ -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 Data.Map (fromList)
6
- import Test.Hspec (Spec, describe, it, shouldBe)
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
- test Case{..} = it description $ returnedMap `shouldBe` expectedMap
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
- returnedMap = wordCount input
22
- expectedMap = fromIntegral <$> fromList expected
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
+