Day 2
This commit is contained in:
parent
4512b18543
commit
136ba5bbc4
1 changed files with 99 additions and 0 deletions
99
src/Day2502.hs
Normal file
99
src/Day2502.hs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
module Main where
|
||||
|
||||
import Data.List (find, nub)
|
||||
import Data.Maybe (isNothing)
|
||||
|
||||
import Debug.Trace (trace)
|
||||
|
||||
-----------------
|
||||
----- Utils -----
|
||||
-----------------
|
||||
|
||||
dropEnd :: Int -> [a] -> [a]
|
||||
dropEnd n xs = reverse $ drop n $ reverse xs
|
||||
|
||||
split :: Char -> String -> [String]
|
||||
split _ "" = []
|
||||
split c str | isNothing $ find (==c) str = [str]
|
||||
| otherwise = takeWhile (/=c) str : split c (tail $ dropWhile (/=c) str)
|
||||
|
||||
-------------------
|
||||
----- Problem -----
|
||||
-------------------
|
||||
|
||||
digitCount :: Int -> Int
|
||||
digitCount 0 = 0
|
||||
digitCount n = 1 + digitCount (n `div` 10)
|
||||
|
||||
splitIntoSeeds :: Int -> (Int, Int)
|
||||
splitIntoSeeds n = ( n `div` part , n `mod` part )
|
||||
where
|
||||
l = digitCount n `div` 2
|
||||
part = 10 ^ l
|
||||
|
||||
fromSeed :: Int -> Int
|
||||
fromSeed n = n + part * n
|
||||
where
|
||||
l = digitCount n
|
||||
part = 10 ^ l
|
||||
|
||||
nextValid :: Int -> Int
|
||||
nextValid = fromSeed . (+1) . fst . splitIntoSeeds
|
||||
|
||||
findFirstNumber :: Int -> Int
|
||||
findFirstNumber n | l `mod` 2 == 1 = nextValid $ fromSeed $ 10 ^ seedLength - 1
|
||||
| otherwise = fromSeed seed
|
||||
where
|
||||
l = digitCount n
|
||||
seedLength = digitCount n `div` 2
|
||||
|
||||
(a,b) = splitIntoSeeds n
|
||||
seed = if b > a then a+1 else a
|
||||
|
||||
part1 :: String -> Int
|
||||
part1 str = sum $ map runOne bounds
|
||||
where
|
||||
bounds :: [(Int, Int)]
|
||||
bounds = (map ((\(x:y:_) -> (read x, read y)) . split '-') . split ',' . dropEnd 1) str
|
||||
|
||||
runOne :: (Int, Int) -> Int
|
||||
runOne (lo,hi) = go $ findFirstNumber lo
|
||||
where
|
||||
go :: Int -> Int
|
||||
go n | n > hi = 0
|
||||
| otherwise = n + go (nextValid n)
|
||||
|
||||
|
||||
partition :: Int -> Int -> [Int]
|
||||
partition n size = map (\it -> (n `div` (10 ^ (size*it))) `mod` 10 ^ size) [0..shift-1]
|
||||
where
|
||||
l = digitCount n
|
||||
shift = l `div` size
|
||||
|
||||
allEqual :: Eq a => [a] -> Bool
|
||||
allEqual = (==1) . length . nub
|
||||
|
||||
isValidNumber :: Int -> Bool
|
||||
isValidNumber n = any (\it -> l `mod` it == 0 && allEqual (partition n it)) [1..l`div`2]
|
||||
where
|
||||
l = digitCount n
|
||||
|
||||
part2 :: String -> Int
|
||||
part2 str = sum $ map runOne bounds
|
||||
where
|
||||
bounds :: [(Int, Int)]
|
||||
bounds = (map ((\(x:y:_) -> (read x, read y)) . split '-') . split ',' . dropEnd 1) str
|
||||
|
||||
runOne :: (Int, Int) -> Int
|
||||
runOne (lo,hi) = go lo
|
||||
where
|
||||
go :: Int -> Int
|
||||
go n | n > hi = 0
|
||||
| otherwise = (if isValidNumber n then n else 0) + go (n + 1)
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
str <- getContents
|
||||
|
||||
print $ part1 str
|
||||
print $ part2 str
|
||||
Loading…
Add table
Add a link
Reference in a new issue