2023-12-14 17:31:44 +01:00
import Control.Arrow
2023-12-15 17:58:28 +01:00
import Data.List
import Data.List.Split
2023-12-14 17:31:44 +01:00
import qualified Data.Map as M
main :: IO ()
2023-12-15 17:58:28 +01:00
main = interact $ show . ( day14a &&& day14b 1000000000 ) . lines
2023-12-14 17:31:44 +01:00
2023-12-15 17:58:28 +01:00
day14a :: [ String ] -> Int
day14a = calc . turn . turn . turn . gravity . turn
2023-12-14 17:31:44 +01:00
2023-12-15 17:58:28 +01:00
turn :: [ String ] -> [ String ]
turn = transpose . reverse
2023-12-14 17:31:44 +01:00
2023-12-15 17:58:28 +01:00
gravity :: [ String ] -> [ String ]
gravity = map ( intercalate " # " . map sort . splitOn " # " )
calc :: [ String ] -> Int
calc = sum . zipWith ( * ) [ 1 .. ] . map ( count 'O' ) . reverse
2023-12-14 17:31:44 +01:00
where
2023-12-15 17:58:28 +01:00
count c = length . filter ( == c )
2023-12-14 17:31:44 +01:00
2023-12-15 17:58:28 +01:00
genStates :: [ String ] -> [ [ String ] ]
genStates = map snd . filter f . zip [ 0 .. ] . iterate ( gravity . turn )
where
f ( x , _ ) = x ` mod ` 4 == 0
2023-12-14 17:31:44 +01:00
2023-12-15 17:58:28 +01:00
findDupe :: M . Map [ String ] Int -> Int -> [ [ String ] ] -> ( Int , Int )
findDupe m n ( x : xs ) =
if x ` M . member ` m
then ( m M .! x , n )
else findDupe ( M . insert x n m ) ( succ n ) xs
2023-12-14 17:31:44 +01:00
2023-12-15 17:58:28 +01:00
day14b :: Int -> [ String ] -> Int
day14b n input = calc ( states !! num )
2023-12-14 17:31:44 +01:00
where
2023-12-15 17:58:28 +01:00
num = ( n - s1 ) ` mod ` ( s2 - s1 ) + s1
( s1 , s2 ) = findDupe M . empty 0 states
states = genStates input