day 16
This commit is contained in:
parent
3cd7b2e5ee
commit
749637707e
1 changed files with 168 additions and 0 deletions
168
16/solution.hs
Normal file
168
16/solution.hs
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
import Data.List
|
||||
import Data.Graph
|
||||
import Data.Maybe
|
||||
import Data.Array
|
||||
import Debug.Trace
|
||||
|
||||
data Square = Wall | Square {visited :: Bool, dir :: Maybe Direction, distance :: Maybe Int, start :: Bool, end :: Bool}
|
||||
|
||||
data Direction = DirUp | DirDown | DirLeft | DirRight deriving Eq
|
||||
|
||||
instance Show Square where
|
||||
show Wall = "#"
|
||||
show Square {dir=Just x} = show x
|
||||
show Square {dir=Nothing} = "."
|
||||
|
||||
instance Show Direction where
|
||||
show x
|
||||
| x == DirUp = "^"
|
||||
| x == DirDown = "v"
|
||||
| x == DirLeft = "<"
|
||||
| x == DirRight = ">"
|
||||
|
||||
toSquare :: Char -> Maybe Square
|
||||
toSquare '#' = Just Wall
|
||||
toSquare '.' = Just Square {visited=False, dir=Nothing, distance=Nothing, start=False, end=False}
|
||||
toSquare 'S' = Just Square {visited=True, dir=Just DirRight, distance=Just 0, start=True, end=False}
|
||||
toSquare 'E' = Just Square {visited=False, dir=Nothing, distance=Nothing, start=False, end=True}
|
||||
toSquare _ = Nothing
|
||||
|
||||
toDirection :: Char -> Maybe Direction
|
||||
toDirection '^' = Just DirUp
|
||||
toDirection 'v' = Just DirDown
|
||||
toDirection '<' = Just DirLeft
|
||||
toDirection '>' = Just DirRight
|
||||
toDirection _ = Nothing
|
||||
|
||||
addDir :: Direction -> (Int, Int) -> (Int, Int)
|
||||
addDir dir (x, y) = case dir of
|
||||
DirUp -> (x-1, y)
|
||||
DirDown -> (x+1, y)
|
||||
DirLeft -> (x, y-1)
|
||||
DirRight -> (x, y+1)
|
||||
|
||||
traceOut :: Show a => a -> a
|
||||
traceOut x = (traceShow x x)
|
||||
|
||||
addFirst :: [[a]] -> a -> [[a]]
|
||||
addFirst [] x = [[x]]
|
||||
addFirst (y:ys) x = ([x] ++ y) : ys
|
||||
|
||||
split :: [Char] -> String -> [String]
|
||||
split _ [] = []
|
||||
split delims (x:xs)
|
||||
| elem x delims = [[]] ++ split delims xs
|
||||
| otherwise = addFirst (split delims xs) x
|
||||
|
||||
splitInput :: String -> [[Char]]
|
||||
splitInput = split ['\n']
|
||||
|
||||
makeGraph :: [[Char]] -> (Graph, (Vertex -> ((Int, Int), (Int, Int), [(Int, Int)])), ((Int, Int) -> Maybe Vertex))
|
||||
makeGraph grid = graphFromEdgeList grid . concat . map (\(x, _) -> x) . concat . flipSecond . map (map (\(x, row) -> foldl' (combine x) ([], (-1, '#')) row)) . map (indexed . map indexed) . (\x -> [x, transpose x]) $ grid
|
||||
|
||||
graphFromEdgeList :: [[Char]] -> [((Int, Int), (Int, Int))] -> (Graph, (Vertex -> ((Int, Int), (Int, Int), [(Int, Int)])), ((Int, Int) -> Maybe Vertex))
|
||||
graphFromEdgeList grid edgePairs =
|
||||
graphFromEdges [((x, y), (x, y), [b | (a, b) <- edgePairs, a == (x, y)]) | (x, row) <- indexed grid, (y, value) <- indexed row]
|
||||
|
||||
makeArray :: [[Char]] -> (Array (Int, Int) Square)
|
||||
makeArray grid = listArray ((0, 0), ((length grid)-1, (length (grid!!0))-1)) . concat . map (map (fromJust . toSquare)) $ grid
|
||||
|
||||
combine :: Int -> ([((Int, Int), (Int, Int))], (Int, Char)) -> (Int, Char) -> ([((Int, Int), (Int, Int))], (Int, Char))
|
||||
combine x (edges, (prevy, prevv)) (nexty, nextv)
|
||||
| condition = ((((x, prevy), (x, nexty)):((x, nexty), (x, prevy)):edges), (nexty, nextv))
|
||||
| otherwise = (edges, (nexty, nextv))
|
||||
where condition = (prevv == '.' || prevv == 'E' || prevv == 'S') && (nextv == '.' || nextv == 'E' || nextv == 'S')
|
||||
|
||||
flipSecond :: [[([((Int, Int), (Int, Int))], (Int, Char))]] -> [[([((Int, Int), (Int, Int))], (Int, Char))]]
|
||||
flipSecond [a, xs] = [a, map (\(x, y) -> ((map (\((a, b), (c, d)) -> ((b, a), (d, c))) x), y)) xs]
|
||||
|
||||
indexed :: [a] -> [(Int, a)]
|
||||
indexed xs = zip [0..] xs
|
||||
|
||||
printGrid :: (Array (Int, Int) Square) -> String
|
||||
printGrid arr = concat $ [concat [show (arr!(x, y)) | y <- [0..140]] ++ "\n" | x <- [0..23]] ++ ["\n\n"] ++ [concat [show (arr!(x, y)) | y <- [0..140]] ++ "\n" | x <- [117..140]]
|
||||
--printGrid arr = concat $ [concat [show (arr!(x, y)) | y <- [0..14]] ++ "\n" | x <- [0..14]]
|
||||
|
||||
type ArrayGrid = Array (Int, Int) Square
|
||||
type GFunc = (Vertex -> ((Int, Int), (Int, Int), [(Int, Int)]))
|
||||
type GFunc2 = ((Int, Int) -> Maybe Vertex)
|
||||
|
||||
-- getDir from to
|
||||
getDir :: (Int, Int) -> (Int, Int) -> Maybe Direction
|
||||
getDir (a, b) (c, d) = case (a-c, b-d) of
|
||||
(1, 0) -> Just DirUp
|
||||
(-1, 0) -> Just DirDown
|
||||
(0, 1) -> Just DirLeft
|
||||
(0, -1) -> Just DirRight
|
||||
_ -> Nothing
|
||||
|
||||
getUpdate :: ArrayGrid -> (Int, Int) -> (Int, Int) -> [((Int, Int), Square)]
|
||||
getUpdate arr coord neighbour = case distance toSquare of
|
||||
Nothing -> [newSquare]
|
||||
Just x -> case compare x newDist of
|
||||
EQ -> undefined
|
||||
GT -> [newSquare]
|
||||
LT -> []
|
||||
where fromSquare = arr!coord
|
||||
dirMove = fromJust $ getDir coord neighbour
|
||||
toSquare = arr!neighbour
|
||||
newDist = (if (fromJust $ dir $ fromSquare) == (dirMove) then (+1) else (+1001)) $ fromJust $ distance fromSquare
|
||||
newSquare = (neighbour, Square {visited=True, dir=Just dirMove, distance=Just newDist, start=start toSquare, end=end toSquare})
|
||||
|
||||
updateArray :: ArrayGrid -> Graph -> GFunc -> GFunc2 -> [(Int, Int)] -> (ArrayGrid, [(Int, Int)])
|
||||
updateArray arr graph gfunc gfunc2 = (\x -> (doUpdate arr x, map (\(a, _) -> a) x)) . concat . concat . map (\(coord, neighbours) -> map (getUpdate arr coord) neighbours) . map (\coord -> let (_, _, neighbours) = gfunc $ fromJust $ gfunc2 coord in (coord, neighbours))
|
||||
|
||||
doUpdate :: ArrayGrid -> [((Int, Int), Square)] -> ArrayGrid
|
||||
doUpdate arr [] = arr
|
||||
doUpdate arr ((update@(pos, square)):updates) = case distance (arr!pos) of
|
||||
Nothing -> doUpdate (arr // [update]) updates
|
||||
Just x -> case compare x (fromJust $ distance square) of
|
||||
EQ -> doUpdate arr updates
|
||||
GT -> doUpdate (arr // [update]) updates
|
||||
LT -> doUpdate arr updates
|
||||
|
||||
findStart :: ArrayGrid -> (Int, Int)
|
||||
findStart = (\(a, _) -> a) . head . filter (\(_, b) -> case b of
|
||||
Wall -> False
|
||||
Square {start=s} -> s) . assocs
|
||||
findEnd :: ArrayGrid -> (Int, Int)
|
||||
findEnd = (\(a, _) -> a) . head . filter (\(_, b) -> case b of
|
||||
Wall -> False
|
||||
Square {end=e} -> e) . assocs
|
||||
|
||||
iterArray :: ArrayGrid -> Graph -> GFunc -> GFunc2 -> [(Int, Int)] -> ArrayGrid
|
||||
iterArray arr graph gfunc gfunc2 coords = case (nub newCoords) of
|
||||
[] -> newArray
|
||||
_ -> iterArray newArray graph gfunc gfunc2 newCoords
|
||||
where (newArray, newCoords) = updateArray (trace (printGrid arr) arr) graph gfunc gfunc2 coords
|
||||
|
||||
solve1 :: ArrayGrid -> Int
|
||||
solve1 arr = fromJust $ distance $ traceOut $ arr!(findEnd arr)
|
||||
|
||||
solve2 :: ArrayGrid -> ArrayGrid -> Int -> Int
|
||||
solve2 arr1 arr2 target = length $ (\x -> trace (test arr1 x) x) $ filter (\x -> case (arr1!x, arr2!x) of
|
||||
(Square {distance=a}, Square {distance=b}) -> elem (traceOut ((fromJust a) + (fromJust b))) [target, target+1000, target-1000]
|
||||
_ -> False
|
||||
) $ indices arr1
|
||||
|
||||
test :: (Array (Int, Int) Square) -> [(Int, Int)] -> String
|
||||
test arr matches = concat $ [concat [if (elem (x, y) matches) then "O" else case (arr!(x, y)) of
|
||||
Wall -> "#"
|
||||
_ -> " "
|
||||
| y <- [0..140]] ++ "\n" | x <- [0..140]]
|
||||
|
||||
main :: IO()
|
||||
main = do
|
||||
fileinp <- readFile "input.txt"
|
||||
let parsed = splitInput fileinp
|
||||
let (graph, gfunc, gfunc2) = makeGraph parsed
|
||||
-- print graph
|
||||
let array = makeArray parsed
|
||||
-- putStrLn $ printGrid array
|
||||
let solvedStart = iterArray array graph gfunc gfunc2 [findStart array]
|
||||
let solvedEnd = iterArray (array // [(findStart array, Square {visited=False, dir=Nothing, distance=Nothing, start=True, end=False}),
|
||||
(findEnd array, Square {visited=True, dir=(dir $ (solvedStart!) $ findEnd solvedStart), distance=Just 0, start=False, end=True})]) graph gfunc gfunc2 [findEnd array]
|
||||
let solved1 = solve1 solvedStart
|
||||
let solved2 = solve2 solvedStart solvedEnd solved1
|
||||
print solved1
|
||||
print solved2
|
||||
Loading…
Add table
Add a link
Reference in a new issue