67 lines
1.9 KiB
Haskell
67 lines
1.9 KiB
Haskell
{-# LANGUAGE InstanceSigs #-}
|
|
import Common
|
|
-- not to be confused with AStar.hs! that one was bugged :)
|
|
import Data.Graph.AStar
|
|
import Data.List.Split (splitOn)
|
|
import Data.List (elemIndex)
|
|
import Data.Maybe (fromJust, mapMaybe)
|
|
import qualified Data.Map.Strict as M
|
|
import Data.Map.Strict (Map, (!))
|
|
import qualified Data.HashSet as HS
|
|
import Data.HashSet (HashSet)
|
|
import Data.Hashable (Hashable (hash, hashWithSalt))
|
|
import Data.Bits
|
|
|
|
data Material = Ore | Clay | Obsidian | Geode
|
|
deriving (Eq, Show)
|
|
|
|
newtype Robot = Robot Material
|
|
deriving (Eq, Show)
|
|
|
|
data Recipe = Recipe [(Int, Material)] Robot
|
|
deriving (Eq, Show)
|
|
|
|
type Blueprint = [Recipe]
|
|
|
|
parseMaterial :: String -> Material
|
|
parseMaterial "ore" = Ore
|
|
parseMaterial "clay" = Clay
|
|
parseMaterial "obsidian" = Obsidian
|
|
parseMaterial "geode" = Geode
|
|
parseMaterial _ = undefined
|
|
|
|
parseRecipe :: String -> Maybe Recipe
|
|
parseRecipe s = do
|
|
let split = words s
|
|
typeIndex <- elemIndex "Each" split
|
|
recipeIndex <- elemIndex "costs" split
|
|
let ingredients = map ((\[a, b] -> (read a, parseMaterial b)) . words . trim) $ splitOn "and" $ unwords $ drop (recipeIndex + 1) split
|
|
let robotType = parseMaterial $ split !! (typeIndex + 1)
|
|
return $ Recipe ingredients (Robot robotType)
|
|
|
|
parse :: String -> [Recipe]
|
|
parse s = mapMaybe parseRecipe recipes
|
|
where
|
|
recipes = map trim $ splitOn "." s
|
|
|
|
newtype State = State (Map Material Int, Map Robot Int, Int)
|
|
deriving (Eq)
|
|
|
|
-- for Some reason hashable doesn't export these. Cool :)
|
|
hashInt s x = (s * 16777619) `xor` x
|
|
defaultHashWithSalt salt x = salt `hashInt` hash x
|
|
|
|
instance Hashable State where
|
|
hash :: State -> Int
|
|
hash (State (materials, robots, minute)) = foldr hashInt minute (M.elems materials ++ M.elems robots)
|
|
|
|
hashWithSalt :: Int -> State -> Int
|
|
hashWithSalt = defaultHashWithSalt
|
|
|
|
nextNodes :: Blueprint -> State -> HashSet State
|
|
nextNodes recipes s = set
|
|
where set = HS.fromList [s]
|
|
|
|
main = interact $
|
|
show
|
|
. map parse . lines |