module Euler.Problems.Problem15
( answer
, countPaths
, countPaths'
, P
, Counts
) where
import Euler.Prelude
import qualified Data.Foldable as Foldable
import qualified Data.List as List
import qualified Data.Map as Map
import qualified Data.Maybe as Maybe
answer :: Integer
answer = countPaths (20, 20)
countPaths :: P
-> Integer
countPaths d = (Maybe.fromJust . Map.lookup d) (countPaths' Map.empty [d])
type P = (Integer, Integer)
type Counts = Map P Integer
countPaths'
:: Counts
-> [P]
-> Counts
countPaths' counts [] = counts
countPaths' counts stack@((x, y):restOfStack)
| Map.member (x, y) counts = countPaths' counts restOfStack
| x == 0 || y == 0 = countPaths' (Map.insert (x, y) 1 counts) restOfStack
| Foldable.null unknownAdjacencies =
let c = Foldable.sum $ mapMaybe (`Map.lookup` counts) adjacencies
in countPaths' (Map.insert (x, y) c counts) restOfStack
| otherwise = countPaths' counts (unknownAdjacencies <> stack)
where
adjacencies = [(x - 1, y), (x, y - 1)]
unknownAdjacencies = List.filter (`Map.notMember` counts) adjacencies