Skip to content

Commit

Permalink
Merge pull requests #531, #532, #533, #534, and #535
Browse files Browse the repository at this point in the history
bowling 1.0.0.2: drop unneeded rolls, edit a description
leap 1.0.0.2: explain criteria in descriptions, put in progress order
luhn 1.0.0.2: only test isValid, use (most) x-common cases
phone-number 1.2.0.3: enforce area/exchange not starting with 1
roman-numerals 1.0.0.2: add descriptions
  • Loading branch information
petertseng committed May 9, 2017
6 parents 381d339 + d010efd + f00dab6 + 610ba69 + 0ed4ac7 + 11963b4 commit a142b26
Show file tree
Hide file tree
Showing 13 changed files with 188 additions and 193 deletions.
2 changes: 1 addition & 1 deletion exercises/bowling/package.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: bowling
version: 0.9.0.1 # 2016-11-20
version: 1.0.0.2

dependencies:
- base
Expand Down
8 changes: 4 additions & 4 deletions exercises/bowling/test/Tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ cases = [ Case { description = "should be able to score a game with all zeros"
, expected = Right 300
}
, Case { description = "rolls can not score negative points"
, rolls = [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
, rolls = [-1]
, expected = Left $ InvalidRoll 0 (-1)
}
, Case { description = "a roll can not score more than 10 points"
, rolls = [11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
, rolls = [11]
, expected = Left $ InvalidRoll 0 11
}
, Case { description = "two rolls in a frame can not score more than 10 points"
, rolls = [5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
, rolls = [5, 6]
, expected = Left $ InvalidRoll 1 6
}
, Case { description = "bonus roll after a strike in the last frame can not score more than 10 points"
Expand Down Expand Up @@ -121,7 +121,7 @@ cases = [ Case { description = "should be able to score a game with all zeros"
, rolls = [0, 0]
, expected = Left IncompleteGame
}
, Case { description = "a game with more than ten frames can not be scored"
, Case { description = "cannot roll if game already has ten frames"
, rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
, expected = Left $ InvalidRoll 20 0
}
Expand Down
2 changes: 1 addition & 1 deletion exercises/leap/package.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: leap
version: 0.9.0.1 # 2016-07-27
version: 1.0.0.2

dependencies:
- base
Expand Down
28 changes: 8 additions & 20 deletions exercises/leap/test/Tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,19 @@ data Case = Case { description :: String
}

cases :: [Case]
cases = [ Case { description = "leap year"
, input = 1996
, expected = True
}
, Case { description = "standard and odd year"
, input = 1997
, expected = False
}
, Case { description = "standard even year"
, input = 1998
cases = [ Case { description = "year not divisible by 4: common year"
, input = 2015
, expected = False
}
, Case { description = "standard nineteenth century"
, input = 1900
, expected = False
, Case { description = "year divisible by 4, not divisible by 100: leap year"
, input = 2016
, expected = True
}
, Case { description = "standard eighteenth century"
, input = 1800
, Case { description = "year divisible by 100, not divisible by 400: common year"
, input = 2100
, expected = False
}
, Case { description = "leap twenty fourth century"
, input = 2400
, expected = True
}
, Case { description = "leap y2k"
, Case { description = "year divisible by 400: leap year"
, input = 2000
, expected = True
}
Expand Down
31 changes: 8 additions & 23 deletions exercises/luhn/examples/success-standard/src/Luhn.hs
Original file line number Diff line number Diff line change
@@ -1,32 +1,17 @@
module Luhn (checkDigit, addends, checksum, isValid, create) where
module Luhn (isValid) where

revDigits :: Integral a => a -> [a]
revDigits n = rem10 : digits
where (quot10, rem10) = n `quotRem` 10
digits | quot10 == 0 = []
| otherwise = revDigits quot10
import Data.Char (digitToInt)

luhnDouble :: Integral a => a -> a
luhnDouble n | n < 5 = n * 2
| otherwise = n * 2 - 9

luhnDigits :: Integral a => a -> [a]
luhnDigits = zipWith ($) (cycle [id, luhnDouble]) . revDigits
luhnDigits :: Integral a => [a] -> [a]
luhnDigits = zipWith ($) (cycle [id, luhnDouble]) . reverse

checkDigit :: Integral a => a -> a
checkDigit = head . revDigits

addends :: Integral a => a -> [a]
addends = reverse . luhnDigits

checksum :: Integral a => a -> a
checksum :: Integral a => [a] -> a
checksum = (`rem` 10) . sum . luhnDigits

isValid :: Integral a => a -> Bool
isValid = (0 ==) . checksum

create :: Integral a => a -> a
create n | chk == 0 = n10
| otherwise = n10 + (10 - chk)
where n10 = n * 10
chk = checksum n10 `rem` 10
isValid :: String -> Bool
isValid s = length digits > 1 && checksum digits == 0
where digits = map digitToInt $ filter (/= ' ') s
2 changes: 1 addition & 1 deletion exercises/luhn/package.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: luhn
version: 0.9.0.1 # 2016-08-04
version: 1.0.0.2

dependencies:
- base
Expand Down
16 changes: 2 additions & 14 deletions exercises/luhn/src/Luhn.hs
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
module Luhn (addends, checkDigit, checksum, create, isValid) where
module Luhn (isValid) where

addends :: Integer -> [Integer]
addends n = error "You need to implement this function."

checkDigit :: Integer -> Integer
checkDigit n = error "You need to implement this function."

checksum :: Integer -> Integer
checksum n = error "You need to implement this function."

create :: Integer -> Integer
create n = error "You need to implement this function."

isValid :: Integer -> Bool
isValid :: String -> Bool
isValid n = error "You need to implement this function."
138 changes: 68 additions & 70 deletions exercises/luhn/test/Tests.hs
Original file line number Diff line number Diff line change
@@ -1,79 +1,77 @@
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-# LANGUAGE RecordWildCards #-}

import Data.Foldable (for_)
import Test.Hspec (Spec, describe, it, shouldBe)
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith)

import Luhn (addends, checkDigit, checksum, create, isValid)
import Luhn (isValid)

main :: IO ()
main = hspecWith defaultConfig {configFastFail = True} specs

specs :: Spec
specs = describe "luhn" $ do
describe "standard tests" $ do

it "check digit" $
checkDigit 34567 `shouldBe` 7

it "check digit with input ending in zero" $
checkDigit 91370 `shouldBe` 0

it "check addends" $
addends 12121 `shouldBe` [1, 4, 1, 4, 1]

it "check too large addends" $
addends 8631 `shouldBe` [7, 6, 6, 1]

-- The reference test cases expect the checksum function to return
-- the simple sum of the transformed digits, not their `mod 10` sum.
-- In this track, we insist on the `mod 10`. :)

it "checksum" $
checksum 4913 `shouldBe` 2 -- The reference test expects 22.

it "checksum of larger number" $
checksum 201773 `shouldBe` 1 -- The reference test expects 21.

it "check invalid number" $
isValid 738 `shouldBe` False

it "check valid number" $
isValid 8739567 `shouldBe` True

it "create valid number" $
create 123 `shouldBe` 1230

it "create larger valid number" $
create 873956 `shouldBe` 8739567

it "create even larger valid number" $
create 837263756 `shouldBe` 8372637564

describe "track-specific tests" $ do

-- This track has some tests that were not included in the
-- reference test cases from `exercism/x-common/leap.json`.

it "checksum 1111" $
checksum 1111 `shouldBe` 6

it "checksum 8763" $
checksum 8763 `shouldBe` 0

it "checksum 8739567" $
checksum 8739567 `shouldBe` 0

it "checksum 2323200577663554" $
checksum 2323200577663554 `shouldBe` 0

it "isValid 1111" $
isValid 1111 `shouldBe` False

it "isValid 8763" $
isValid 8763 `shouldBe` True

it "isValid 2323200577663554" $
isValid 2323200577663554 `shouldBe` True

it "create 232320057766355" $
create 232320057766355 `shouldBe` 2323200577663554
specs = describe "valid" $ for_ cases test
where
test Case{..} = it description $ isValid input `shouldBe` expected

data Case = Case { description :: String
, input :: String
, expected :: Bool
}

cases :: [Case]
cases = [ Case { description = "single digit strings can not be valid"
, input = "1"
, expected = False
}
, Case { description = "A single zero is invalid"
, input = "0"
, expected = False
}
, Case { description = "a simple valid SIN that remains valid if reversed"
, input = "059"
, expected = True
}
, Case { description = "a simple valid SIN that becomes invalid if reversed"
, input = "59"
, expected = True
}
, Case { description = "a valid Canadian SIN"
, input = "055 444 285"
, expected = True
}
, Case { description = "invalid Canadian SIN"
, input = "055 444 286"
, expected = False
}
, Case { description = "invalid credit card"
, input = "8273 1232 7352 0569"
, expected = False
}
-- This track is not testing these cases, since we would rather focus on the algorithm,
-- and because it seems strange to be unable to distinguish between well-formed invalid input and malformed input.
-- , Case { description = "valid strings with a non-digit included become invalid"
-- , input = "055a 444 285"
-- , expected = False
-- }
-- , Case { description = "valid strings with punctuation included become invalid"
-- , input = "055-444-285"
-- , expected = False
-- }
-- , Case { description = "valid strings with symbols included become invalid"
-- , input = "055£ 444$ 285"
-- , expected = False
-- }
, Case { description = "single zero with space is invalid"
, input = " 0"
, expected = False
}
, Case { description = "more than a single zero is valid"
, input = "0000 0"
, expected = True
}
, Case { description = "input digit 9 is correctly converted to output digit 9"
, input = "091"
, expected = True
}
]
15 changes: 12 additions & 3 deletions exercises/phone-number/examples/success-standard/src/Phone.hs
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
module Phone (number) where
import Data.Char (isDigit, isLetter)
import Data.Char (isDigit)

number :: String -> Maybe String
number input
| any isLetter input = Nothing
number input = clean input >>= check

check :: String -> Maybe String
check ('0':_) = Nothing
check ('1':_) = Nothing
check (_:_:_:'0':_) = Nothing
check (_:_:_:'1':_) = Nothing
check s = Just s

clean :: String -> Maybe String
clean input
| len == 10 = Just digits
| len == 11 && head digits == '1' = Just $ tail digits
| otherwise = Nothing
Expand Down
2 changes: 1 addition & 1 deletion exercises/phone-number/package.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: phone-number
version: 1.0.0.2
version: 1.2.0.3

dependencies:
- base
Expand Down
38 changes: 23 additions & 15 deletions exercises/phone-number/test/Tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,34 @@ data Case = Case { description :: String
cases :: [Case]
cases =
[ Case { description = "cleans the number"
, input = "(123) 456-7890"
, expected = Just "1234567890"
, input = "(223) 456-7890"
, expected = Just "2234567890"
}
, Case { description = "cleans number with dots"
, input = "123.456.7890"
, expected = Just "1234567890"
, Case { description = "cleans numbers with dots"
, input = "223.456.7890"
, expected = Just "2234567890"
}
, Case { description = "cleans numbers with multiple spaces"
, input = "123 456 7890 "
, expected = Just "1234567890"
, input = "223 456 7890 "
, expected = Just "2234567890"
}
, Case { description = "invalid when 9 digits"
, input = "123456789"
, expected = Nothing
}
, Case { description = "invalid when 11 digits"
, input = "21234567890"
, Case { description = "invalid when 11 digits does not start with a 1"
, input = "22234567890"
, expected = Nothing
}
, Case { description = "valid when 11 digits and first is 1"
, input = "11234567890"
, expected = Just "1234567890"
, Case { description = "valid when 11 digits and starting with 1"
, input = "12234567890"
, expected = Just "2234567890"
}
, Case { description = "valid when 11 digits and starting with 1 even with punctuation"
, input = "+1 (223) 456-7890"
, expected = Just "2234567890"
}
, Case { description = "invalid when 12 digits"
, Case { description = "invalid when more than 11 digits"
, input = "321234567890"
, expected = Nothing
}
Expand All @@ -58,8 +62,12 @@ cases =
, input = "123-@:!-7890"
, expected = Nothing
}
, Case { description = "invalid with right number of digits but letters mixed in"
, input = "1a2b3c4d5e6f7g8h9i0j"
, Case { description = "invalid if area code does not start with 2-9"
, input = "(123) 456-7890"
, expected = Nothing
}
, Case { description = "invalid if exchange code does not start with 2-9"
, input = "(223) 056-7890"
, expected = Nothing
}
]
2 changes: 1 addition & 1 deletion exercises/roman-numerals/package.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: roman-numerals
version: 0.9.0.1 # 2016-07-26
version: 1.0.0.2

dependencies:
- base
Expand Down
Loading

1 comment on commit a142b26

@petertseng
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.