Starting with the parse step, the input is of the form
11-22,15-17,.... So we first split on commas, for
each item in the list (of the form "11-22"), we can
split again on "-", and finally, use
read to parse them to integers.
import Data.List.Split (splitOn)
parse :: String -> [[Int]]
parse = map (map read . splitOn "-") . splitOn ","We can move onto the problem itself now.
The check for invalidity for an integer in Part 1 requires us
to simply split the string in half and ensure that the two halves
are identical, this is easily produced using
splitAt:
invalid :: Int -> Bool
invalid n = l == r
where
s = show n
(l, r) = splitAt (length s `div` 2) sWith that in place, we can define the solution to part 1.
range is a utility to iterate through the pair, we
then filter out invalid items and add everything
up:
range [a, b] = [a .. b]
p1 i = sum $ concatMap (filter invalid . range) iThis part requires a slight modification to the invalidity
check. We now need to check for any number of repeating
substrings, so “123123123” is invalid because it is formed from
"123" + "123" + "123". The methodology here is
slightly involved, first we get all prefixes of the input using
inits. We can filter out the initial empty prefix
with tail. Upon repeated cyling the prefixes, if we
are able to form the original string, then the string can be
considered invalid!
import Data.List (inits, isPrefixOf)invalid2 :: Int -> Bool
invalid2 n = any ((s `isPrefixOf`) . cycle) $ tail $ inits l
where
s = show n
(l, _) = splitAt (length s `div` 2) sThen, part 2 is defined like so:
p2 i = sum $ concatMap (filter invalid2 . range) iFinally, a main function to wrap it all up:
main = do
n <- parse <$> getContents
print $ p1 n
print $ p2 n