{-# Language ImportQualifiedPost #-}
{-|
Module      : Main
Description : Day  solution
Copyright   : (c) Eric Mertens, 2021
License     : ISC
Maintainer  : emertens@gmail.com

<https://adventofcode.com/2021/day/25>

-}
module Main (main) where

import Advent.Coord (Coord(..), below, right)
import Advent.Input (getInputMap)
import Data.Map (Map)
import Data.Map qualified as Map

-- | >>> :main
-- 582
main :: IO ()
IO ()
main =
 do Map Coord Char
inp <- Int -> Int -> IO (Map Coord Char)
getInputMap Int
2021 Int
25
    let C Int
ny Int
nx = Coord
1 Coord -> Coord -> Coord
forall a. Num a => a -> a -> a
+ [Coord] -> Coord
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum (Map Coord Char -> [Coord]
forall k a. Map k a -> [k]
Map.keys Map Coord Char
inp)
    let inp' :: Map Coord Char
inp' = (Char -> Bool) -> Map Coord Char -> Map Coord Char
forall a k. (a -> Bool) -> Map k a -> Map k a
Map.filter (Char -> [Char] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char]
">v") Map Coord Char
inp
    let steps :: [Map Coord Char]
steps = (Map Coord Char -> Map Coord Char)
-> Map Coord Char -> [Map Coord Char]
forall a. (a -> a) -> a -> [a]
iterate (Int -> Int -> Map Coord Char -> Map Coord Char
step Int
ny Int
nx) Map Coord Char
inp'
    Int -> IO ()
forall a. Show a => a -> IO ()
print ([Map Coord Char] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Map Coord Char] -> [Map Coord Char]
forall a. Eq a => [a] -> [a]
evolution [Map Coord Char]
steps))

evolution :: Eq a => [a] -> [a]
evolution :: forall a. Eq a => [a] -> [a]
evolution (a
x:a
y:[a]
_) | a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
y = [a
x]
evolution (a
x:[a]
xs) = a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a] -> [a]
forall a. Eq a => [a] -> [a]
evolution [a]
xs
evolution [] = []

step :: Int -> Int -> Map Coord Char -> Map Coord Char
step :: Int -> Int -> Map Coord Char -> Map Coord Char
step Int
ny Int
nx = Int
-> Int
-> Char
-> (Coord -> Coord)
-> Map Coord Char
-> Map Coord Char
step1 Int
ny Int
nx Char
'v' Coord -> Coord
below (Map Coord Char -> Map Coord Char)
-> (Map Coord Char -> Map Coord Char)
-> Map Coord Char
-> Map Coord Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int
-> Int
-> Char
-> (Coord -> Coord)
-> Map Coord Char
-> Map Coord Char
step1 Int
ny Int
nx Char
'>' Coord -> Coord
right

step1 :: Int -> Int -> Char -> (Coord -> Coord) -> Map Coord Char -> Map Coord Char
step1 :: Int
-> Int
-> Char
-> (Coord -> Coord)
-> Map Coord Char
-> Map Coord Char
step1 Int
ny Int
nx Char
c Coord -> Coord
f Map Coord Char
inp =
  [(Coord, Char)] -> Map Coord Char
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [
    (if Char
v Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c Bool -> Bool -> Bool
&& Coord -> Map Coord Char -> Bool
forall k a. Ord k => k -> Map k a -> Bool
Map.notMember Coord
k' Map Coord Char
inp then Coord
k' else Coord
k, Char
v) 
    | (Coord
k, Char
v) <- Map Coord Char -> [(Coord, Char)]
forall k a. Map k a -> [(k, a)]
Map.toList Map Coord Char
inp
    , let k' :: Coord
k' = Coord -> Coord
fixup (Coord -> Coord
f Coord
k)
    ]
  where
    fixup :: Coord -> Coord
fixup (C Int
y Int
x) = Int -> Int -> Coord
C (Int
y Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
ny) (Int
x Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
nx)