day 23, 25

This commit is contained in:
Jill 2022-12-27 05:25:37 +03:00
parent 87dc22df59
commit dca25b6003
5 changed files with 270 additions and 0 deletions

106
22-a.hs Normal file
View File

@ -0,0 +1,106 @@
import Common
import Prelude hiding (Right, Left)
import Data.List.Split (splitOn)
import Data.Char (isNumber)
import Data.List (elemIndex)
import Data.Maybe (fromJust, fromMaybe)
data Tile = Blank | Empty | Wall
deriving (Eq, Show, Enum)
data Direction = L | R
deriving (Eq, Show, Enum)
data Facing = Up | Down | Left | Right
deriving (Eq, Show, Enum)
data Instruction = Face Direction | Step Int
deriving (Eq, Show)
type State = (Pos, Facing)
parseMap :: String -> Grid Tile
parseMap s = map parseRow rows
where
parseRow = map parseTile
parseTile '#' = Wall
parseTile '.' = Empty
parseTile ' ' = Blank
parseTile _ = undefined
rows = lines s
turn :: Facing -> Direction -> Facing
turn Left R = Up
turn Up R = Right
turn Right R = Down
turn Down R = Left
turn Left L = Down
turn Up L = Left
turn Right L = Up
turn Down L = Right
charToDir :: Char -> Direction
charToDir 'L' = L
charToDir 'R' = R
charToDir _ = undefined
parseInstructions :: String -> [Instruction]
parseInstructions s = parseNum s
where
parseDirection :: String -> [Instruction]
parseDirection [] = []
parseDirection s = Face (charToDir (head s)) : parseNum (tail s)
parseNum :: String -> [Instruction]
parseNum [] = []
parseNum s = Step (read num) : parseDirection rest
where (num, rest) = span isNumber s
getInitialState :: Grid Tile -> State
getInitialState map = ((fromJust $ elemIndex Empty (head map), 0), Right)
forward :: Facing -> Pos
forward Right = (1, 0)
forward Down = (0, 1)
forward Left = (-1, 0)
forward Up = (0, -1)
opposite :: Facing -> Facing
opposite Right = Left
opposite Left = Right
opposite Up = Down
opposite Down = Up
getTile :: Grid Tile -> Pos -> Tile
getTile grid pos = fromMaybe Blank (grid !!? pos)
stepThrough :: (Grid Tile, [Instruction]) -> State
stepThrough (grid, instructions) = step (getInitialState grid) instructions
where
step :: State -> [Instruction] -> State
step state [] = state
step ((x, y), facing) (instruction:xs) = case instruction of
Face dir -> step ((x, y), turn facing dir) xs
Step 0 -> step ((x, y), facing) xs
Step n -> case wrappedTile of
Wall -> step ((x, y), facing) xs
Empty -> step (wrappedPos, facing) (Step (n - 1) : xs)
Blank -> error "huh?"
where
wrappedTile = getTile grid wrappedPos
wrappedPos = if newTile == Blank then (until (\pos -> getTile grid pos == Blank && pos /= newPos) (`subPos` forward facing) newPos) `addPos` forward facing else newPos
newTile = getTile grid newPos
newPos = (x, y) `addPos` forward facing
facingToInt :: Facing -> Int
facingToInt Right = 0
facingToInt Down = 1
facingToInt Left = 2
facingToInt Up = 3
getPassword :: State -> Int
getPassword ((x, y), f) = 1000 * (y + 1) + 4 * (x + 1) + facingToInt f
main = interact $
show
. getPassword
. stepThrough
. (\[a, b] -> (parseMap $ unlines a, parseInstructions $ head b)) . splitOn [""] . lines

66
23-a.hs Normal file
View File

@ -0,0 +1,66 @@
import Common hiding (Grid)
import Data.List (foldl', elemIndices)
import Data.Maybe (mapMaybe, catMaybes)
data Direction = North | West | East | South
deriving (Eq, Show, Enum)
parse :: String -> [Pos]
parse s = concat $ zipWith (\y l -> map fst $ filter (\(pos, t) -> t == '#') $ zipWith (\x t -> ((x, y), t)) [0..] l) [0..] $ lines s
directionOrder = [North, South, West, East]
consideredPositions North = [(0, -1), (-1, -1), (1, -1)]
consideredPositions South = [(0, 1), (-1, 1), (1, 1)]
consideredPositions West = [(-1, 0), (-1, -1), (-1, 1)]
consideredPositions East = [(1, 0), (1, -1), (1, 1)]
directPosition North = (0, -1)
directPosition South = (0, 1)
directPosition West = (-1, 0)
directPosition East = (1, 0)
removeDuplicatesBy :: (Eq b) => (a -> b) -> [a] -> [a]
removeDuplicatesBy f l = filter (\e -> length (f e `elemIndices` l') == 1) l
where l' = map f l
removeDuplicates :: (Eq a) => [a] -> [a]
removeDuplicates = removeDuplicatesBy id
countEmpty :: [Pos] -> Int
countEmpty elves = sum $ map (\y -> sum $ map (\x -> if (x, y) `elem` elves then 0 else 1) [minX .. maxX]) [minY .. maxY]
where
minX = minimum $ map fst elves
maxX = maximum $ map fst elves
minY = minimum $ map snd elves
maxY = maximum $ map snd elves
unwrap :: (a, Maybe b) -> Maybe (a, b)
unwrap (a, Just b) = Just (a, b)
unwrap (a, Nothing) = Nothing
step :: [Pos] -> Int -> [Pos]
step elves round = movedElves
where
movedElves = map snd newElves ++ filter (`notElem` map fst newElves) elves
newElves = removeDuplicatesBy snd $ mapMaybe unwrap $ zip elves $ map getElfPosition elves
getElfPosition :: Pos -> Maybe Pos
getElfPosition pos
| (not $ or positions) || (and positions) = Nothing
| otherwise = Just firstPos
where
firstPos = (pos `addPos`) $ directPosition firstDir
firstDir = fst $ head $ filter snd $ zip order positions
positions = map (all ((`notElem` elves) . (pos `addPos`)) . consideredPositions) order
order = map ((cycle directionOrder !!) . flip (-) 1 . (+ round)) [0..3]
roundsN = 10
main = interact $
show
. countEmpty
. (\elves -> foldl' step elves [1 .. roundsN])
. parse

62
23-b.hs Normal file
View File

@ -0,0 +1,62 @@
import Common hiding (Grid)
import Data.List (foldl', elemIndices)
import Data.Maybe (mapMaybe, catMaybes)
data Direction = North | West | East | South
deriving (Eq, Show, Enum)
parse :: String -> [Pos]
parse s = concat $ zipWith (\y l -> map fst $ filter (\(pos, t) -> t == '#') $ zipWith (\x t -> ((x, y), t)) [0..] l) [0..] $ lines s
directionOrder = [North, South, West, East]
consideredPositions North = [(0, -1), (-1, -1), (1, -1)]
consideredPositions South = [(0, 1), (-1, 1), (1, 1)]
consideredPositions West = [(-1, 0), (-1, -1), (-1, 1)]
consideredPositions East = [(1, 0), (1, -1), (1, 1)]
directPosition North = (0, -1)
directPosition South = (0, 1)
directPosition West = (-1, 0)
directPosition East = (1, 0)
removeDuplicatesBy :: (Eq b) => (a -> b) -> [a] -> [a]
removeDuplicatesBy f l = filter (\e -> length (f e `elemIndices` l') == 1) l
where l' = map f l
removeDuplicates :: (Eq a) => [a] -> [a]
removeDuplicates = removeDuplicatesBy id
unwrap :: (a, Maybe b) -> Maybe (a, b)
unwrap (a, Just b) = Just (a, b)
unwrap (a, Nothing) = Nothing
step :: [Pos] -> Int -> Maybe [Pos]
step elves round = if null newElves then Nothing else Just movedElves
where
movedElves = map snd newElves ++ filter (`notElem` map fst newElves) elves
newElves = removeDuplicatesBy snd $ mapMaybe unwrap $ zip elves $ map getElfPosition elves
getElfPosition :: Pos -> Maybe Pos
getElfPosition pos
| (not $ or positions) || (and positions) = Nothing
| otherwise = Just firstPos
where
firstPos = (pos `addPos`) $ directPosition firstDir
firstDir = fst $ head $ filter snd $ zip order positions
positions = map (all ((`notElem` elves) . (pos `addPos`)) . consideredPositions) order
order = map ((cycle directionOrder !!) . flip (-) 1 . (+ round)) [0..3]
repeatStepUntilStill :: [Pos] -> Int -> Int
repeatStepUntilStill elves round = case newElves of
Just e -> repeatStepUntilStill e (round + 1)
Nothing -> round
where
newElves = step elves round
main = interact $
show
. (\elves -> repeatStepUntilStill elves 1)
. parse

26
25-a.hs Normal file
View File

@ -0,0 +1,26 @@
readSNAFUDigit '2' = 2
readSNAFUDigit '1' = 1
readSNAFUDigit '0' = 0
readSNAFUDigit '-' = -1
readSNAFUDigit '=' = -2
readSNAFUDigit _ = undefined
readSNAFU :: String -> Int
readSNAFU s = sum $ zipWith (\c m -> readSNAFUDigit c * m) s (map (5 ^) (reverse [0 .. length s - 1]))
showSNAFUDigit 0 = '0'
showSNAFUDigit 1 = '1'
showSNAFUDigit 2 = '2'
showSNAFUDigit 3 = '='
showSNAFUDigit 4 = '-'
showSNAFUDigit _ = undefined
showSNAFU :: Int -> String
showSNAFU n
| n > 0 = showSNAFU ((n + 2) `div` 5) ++ [showSNAFUDigit (n `mod` 5)]
| otherwise = ""
main = interact $ showSNAFU
. sum
. map readSNAFU
. lines

View File

@ -27,9 +27,19 @@ add3 (x1, y1, z1) (x2, y2, z2) = (x1 + x2, y1 + y2, z1 + z2)
type Grid a = [[a]]
(!?) :: [a] -> Int -> Maybe a
xs !? n
| n < 0 = Nothing
| otherwise = foldr (\x r k -> case k of
0 -> Just x
_ -> r (k-1)) (const Nothing) xs n
(!!!) :: Grid a -> Pos -> a
(!!!) grid (x, y) = grid !! y !! x
(!!?) :: Grid a -> Pos -> Maybe a
(!!?) grid (x, y) = (grid !? y) >>= (!? x)
findPos :: (Eq a) => a -> Grid a -> Maybe Pos
findPos target grid = do
y <- findIndex (target `elem`) grid