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.
- 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
|
+
|