improved 12
This commit is contained in:
parent
46a6c20cde
commit
cec5485fda
|
@ -3,25 +3,79 @@ module Main where
|
||||||
import Data.Char
|
import Data.Char
|
||||||
import Data.List
|
import Data.List
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import Debug.Trace
|
|
||||||
|
|
||||||
type Db = M.Map String Node
|
type Db = M.Map String Node
|
||||||
|
data Path =
|
||||||
|
Simple [String]
|
||||||
|
| Extra [String]
|
||||||
|
deriving Show
|
||||||
data Node = Node {
|
data Node = Node {
|
||||||
big :: Bool
|
big :: Bool
|
||||||
, nbs :: [String]
|
, nbs :: [String]
|
||||||
} deriving Show
|
} deriving Show
|
||||||
|
|
||||||
type Path = [String]
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
raw <- getContents
|
raw <- getContents
|
||||||
let input = mkDb $ map splitInp $ lines raw
|
let input = findPaths [ Simple ["start"] ] [] $ mkDb $ map splitInp $ lines raw
|
||||||
in do
|
in do
|
||||||
putStrLn $ "day12a: " ++ (show $ solveA input)
|
putStrLn $ "day12a: " ++ (show $ solveA input)
|
||||||
putStrLn $ "day12b: " ++ (show $ solveB input)
|
putStrLn $ "day12b: " ++ (show $ solveB input)
|
||||||
|
|
||||||
|
solveA :: [Path] -> Int
|
||||||
|
solveA ps = length $ [ x | Simple x <- ps ]
|
||||||
|
|
||||||
|
solveB :: [Path] -> Int
|
||||||
|
solveB = length
|
||||||
|
|
||||||
|
findPaths :: [Path] -> [Path] -> Db -> [Path]
|
||||||
|
findPaths [] comp _ = comp
|
||||||
|
findPaths (k:ks) comp db =
|
||||||
|
if rec k == "end"
|
||||||
|
then findPaths ks (k:comp) db
|
||||||
|
else case k of
|
||||||
|
(Extra ps) -> go stepExtra ps
|
||||||
|
(Simple ps) -> go stepSimple ps
|
||||||
|
where
|
||||||
|
rec (Extra (k:_)) = k
|
||||||
|
rec (Simple (k:_)) = k
|
||||||
|
rec _ = error "empty path"
|
||||||
|
go f ps = findPaths ((f db ps) ++ ks) comp db
|
||||||
|
|
||||||
|
stepExtra :: Db -> [String] -> [Path]
|
||||||
|
stepExtra _ [] = error "empty list"
|
||||||
|
stepExtra db ps = map (Extra . (flip (:) ps)) (l (head ps) db)
|
||||||
|
where
|
||||||
|
isBig s = isUpper $ head s
|
||||||
|
l k db = filter (\n -> (n /= "start") && ((isBig n) || not (n `elem` ps))) $ nbs $ db M.! k
|
||||||
|
|
||||||
|
stepSimple :: Db -> [String] -> [Path]
|
||||||
|
stepSimple _ [] = error "empty list"
|
||||||
|
stepSimple db ps = map (\p -> (c (p:ps))) (l (head ps) db)
|
||||||
|
where
|
||||||
|
isBig s = isUpper $ head s
|
||||||
|
c ps = if isBig (head ps)
|
||||||
|
then Simple ps
|
||||||
|
else
|
||||||
|
let smalls = filter (not . isBig) ps
|
||||||
|
in if any (== (head smalls)) (tail smalls)
|
||||||
|
then Extra ps
|
||||||
|
else Simple ps
|
||||||
|
l k db = filter (/= "start") $ nbs $ db M.! k
|
||||||
|
|
||||||
|
-- io and parsing
|
||||||
|
|
||||||
|
splitInp :: String -> (String,String)
|
||||||
|
splitInp s = (\(a,b) -> (a, drop 1 b)) $ splitAt n s
|
||||||
|
where
|
||||||
|
n = findIn '-' s
|
||||||
|
|
||||||
|
findIn :: Char -> String -> Int
|
||||||
|
findIn c s = go 0 c s
|
||||||
|
where
|
||||||
|
go n c (s:ss) = if c == s then n else go (n+1) c ss
|
||||||
|
go n c [] = error "bad parse"
|
||||||
|
|
||||||
mkDb :: [(String,String)] -> Db
|
mkDb :: [(String,String)] -> Db
|
||||||
mkDb adjs = foldl f (M.fromList $ (map mkInitDb $ getUniques adjs)) adjs
|
mkDb adjs = foldl f (M.fromList $ (map mkInitDb $ getUniques adjs)) adjs
|
||||||
where
|
where
|
||||||
|
@ -36,49 +90,3 @@ mkInitDb s = (,) s
|
||||||
|
|
||||||
getUniques :: [(String,String)] -> [String]
|
getUniques :: [(String,String)] -> [String]
|
||||||
getUniques is = nub $ foldl (\t (a,b) -> (a:b:t)) [] is
|
getUniques is = nub $ foldl (\t (a,b) -> (a:b:t)) [] is
|
||||||
|
|
||||||
findPaths :: (Db -> [String] -> [[String]]) -> [[String]] -> [[String]] -> Db -> [[String]]
|
|
||||||
findPaths f [] comp _ = comp
|
|
||||||
findPaths f (k:ks) comp db = findPaths f (ks ++ new) (nk comp) db
|
|
||||||
where
|
|
||||||
nk = if (head k) == "end"
|
|
||||||
then (k:)
|
|
||||||
else id
|
|
||||||
new = if (head k) /= "end"
|
|
||||||
then f db k
|
|
||||||
else []
|
|
||||||
|
|
||||||
nextSteps :: Db -> [String] -> [[String]]
|
|
||||||
nextSteps db me = filter f $ map (\n -> (n:me)) nobs
|
|
||||||
where
|
|
||||||
f ss = (isUpper $ (head . head) ss)
|
|
||||||
|| not (any (\n -> n == (head ss)) (tail ss))
|
|
||||||
nobs = (nbs $ db M.! (head me))
|
|
||||||
|
|
||||||
nextSteps' :: Db -> [String] -> [[String]]
|
|
||||||
nextSteps' db me = filter f $ map (\n -> (n:me)) nobs
|
|
||||||
where
|
|
||||||
f ss = (isUpper $ (head . head) ss)
|
|
||||||
|| length (g ss) == length (nub (g ss))+1
|
|
||||||
|| not (any (\n -> n == (head ss)) (tail ss))
|
|
||||||
nobs = filter (/= "start") (nbs $ db M.! (head me))
|
|
||||||
g ss = filter (\s -> not $ isUpper (head s)) ss
|
|
||||||
|
|
||||||
solveA :: Db -> Int
|
|
||||||
solveA db = length $ findPaths nextSteps [["start"]] [] db
|
|
||||||
|
|
||||||
solveB :: Db -> Int
|
|
||||||
solveB db = length $ findPaths nextSteps' [["start"]] [] db
|
|
||||||
|
|
||||||
-- io and parsing
|
|
||||||
|
|
||||||
splitInp :: String -> (String,String)
|
|
||||||
splitInp s = (\(a,b) -> (a, drop 1 b)) $ splitAt n s
|
|
||||||
where
|
|
||||||
n = findIn '-' s
|
|
||||||
|
|
||||||
findIn :: Char -> String -> Int
|
|
||||||
findIn c s = go 0 c s
|
|
||||||
where
|
|
||||||
go n c (s:ss) = if c == s then n else go (n+1) c ss
|
|
||||||
go n c [] = error "bad parse"
|
|
||||||
|
|
7
code/src/12/test.txt
Normal file
7
code/src/12/test.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
start-A
|
||||||
|
start-b
|
||||||
|
A-c
|
||||||
|
A-b
|
||||||
|
b-d
|
||||||
|
A-end
|
||||||
|
b-end
|
Loading…
Reference in a new issue