b4855cb88e
You can do it the easy way or the hard way. This is the hard way.
49 lines
1.7 KiB
Haskell
49 lines
1.7 KiB
Haskell
import Data.List
|
|
import Data.List.Split
|
|
import Data.Maybe
|
|
import qualified Data.Text as T
|
|
|
|
main :: IO ()
|
|
main = do
|
|
let toDigit = T.unpack . T.replace (T.pack "10") (T.pack ":") . T.pack
|
|
input <- map (map toDigit . lines) . splitOn "\n\n" <$> readFile "input"
|
|
print $
|
|
sum $ zipWith (*) [1 ..] $ map (fromEnum . isOrdered 0) input
|
|
let divider = ["[[6]]", "[[2]]"]
|
|
let sorted = sortBy mySort (divider ++ concat input)
|
|
print $ product $ map (+ 1) $ mapMaybe (`elemIndex` sorted) divider
|
|
|
|
isOrdered :: Int -> [String] -> Bool
|
|
isOrdered n [l:ls, r:rs]
|
|
| n < 0 && l == ',' = False
|
|
| n > 0 && r == ',' = True
|
|
| l == r = isOrdered n [ls, rs]
|
|
| l == ']' = (r /= ',') || isOrdered (succ n) [ls, r : rs]
|
|
| r == ']' = l == ',' && isOrdered (pred n) [l : ls, rs]
|
|
| l == '[' = r /= ']' && isOrdered (pred n) [ls, r : rs]
|
|
| r == '[' = l == ']' || isOrdered (succ n) [l : ls, rs]
|
|
| l > r = False
|
|
| l < r = True
|
|
| otherwise = False
|
|
isOrdered _ [[], _] = True
|
|
isOrdered _ [_, []] = False
|
|
isOrdered _ _ = True
|
|
|
|
addBrackets :: [String] -> [String] -> [String]
|
|
addBrackets [accl,accr] [l:ls,r:rs]
|
|
| l == r = addBrackets [l:accl,r:accr] [ls,rs]
|
|
| l `elem` ['0'..':'] && r `elem` ['0' .. ':'] = addBrackets [l:accl,r:accr] [ls,rs]
|
|
| l == '[' = addBrackets [l:accl,l:accr] [ls,r:rs]
|
|
| r == '[' = addBrackets [r:accl,r:accr] [l:ls,rs]
|
|
| l == ']' = addBrackets [accl,r:accr] [l:ls,rs]
|
|
| r == ']' = addBrackets [l:accl,accr] [ls,r:rs]
|
|
addBrackets [accl,accr] ["",rs]= map reverse [accl,reverse rs ++ accr]
|
|
addBrackets [accl,accr] [ls,""] = map reverse [reverse ls ++ accl,accr]
|
|
addBrackets _ acc = map reverse acc
|
|
|
|
mySort :: String -> String -> Ordering
|
|
mySort x y =
|
|
if isOrdered 0 (addBrackets ["",""] [x, y])
|
|
then LT
|
|
else GT
|