#!/usr/bin/env nix-shell
#!nix-shell --pure -i "runghc -- -i../" -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ ])"
import Aoc (parseMultiChoiceGrid, readAndParseStdin)
import Data.List (findIndices, transpose)
import Data.Maybe (isJust, isNothing)
main = do
input <- readAndParseStdin parseMultiChoiceGrid
print $ part1 input
print $ part2 input
part1 :: [[Maybe Bool]] -> Int
part1 = countScore . tiltNorth
part2 :: [[Maybe Bool]] -> Int
part2 = countScore . spinCycle 1000
where
spinCycle 0 acc = acc
spinCycle n acc = spinCycle (n - 1) ((tiltEast . tiltSouth . tiltWest . tiltNorth) acc)
countScore :: [[Maybe Bool]] -> Int
countScore [] = 0
countScore (x : xs) = length (filter (== Just True) x) * (length xs + 1) + countScore xs
tiltNorth :: [[Maybe Bool]] -> [[Maybe Bool]]
tiltNorth = transpose . map (move [] 0) . transpose
where
move :: [Maybe Bool] -> Int -> [Maybe Bool] -> [Maybe Bool]
move acc _ [] = acc
move acc lastSeenJust (x : xs)
| x == Just True = move (take lastSeenJust acc ++ x : drop lastSeenJust acc) (lastSeenJust + 1) xs
| x == Just False = move (acc ++ [x]) (length acc + 1) xs
| isNothing x = move (acc ++ [x]) lastSeenJust xs
tiltWest :: [[Maybe Bool]] -> [[Maybe Bool]]
tiltWest = transpose . tiltNorth . transpose
tiltEast :: [[Maybe Bool]] -> [[Maybe Bool]]
tiltEast = transpose . reverse . tiltNorth . reverse . transpose
tiltSouth :: [[Maybe Bool]] -> [[Maybe Bool]]
tiltSouth = reverse . tiltNorth . reverse