2019-12-03 17:57:43 -05:00
|
|
|
import Data.List
|
|
|
|
|
import Data.List.Split
|
|
|
|
|
import Flow
|
|
|
|
|
|
|
|
|
|
main :: IO ()
|
|
|
|
|
main = do
|
|
|
|
|
inputText <- getContents
|
|
|
|
|
let input = parseInput inputText
|
|
|
|
|
putStr "Part 1: "
|
|
|
|
|
putStrLn $ part1 input
|
2019-12-05 08:22:07 -05:00
|
|
|
--putStrLn $ show $ applyAt (-4, 4) emptyBoard
|
2019-12-03 17:57:43 -05:00
|
|
|
|
2019-12-04 12:55:38 -05:00
|
|
|
part1 :: (Wires, Wires) -> String
|
2019-12-05 08:22:07 -05:00
|
|
|
part1 (first:wires1, _) = do
|
|
|
|
|
let _ = applyWire first emptyBoard
|
2019-12-03 17:57:43 -05:00
|
|
|
|
2019-12-04 12:55:38 -05:00
|
|
|
parseInput :: String -> (Wires, Wires)
|
2019-12-03 17:57:43 -05:00
|
|
|
parseInput input = (wires1, wires2)
|
|
|
|
|
where
|
2019-12-05 08:22:07 -05:00
|
|
|
wires1:wires2:_ = input |> lines |> fmap (splitOn "," .> fmap parseWire)
|
|
|
|
|
|
|
|
|
|
applyWire :: Wire -> Board -> Board
|
|
|
|
|
applyWire wire board
|
|
|
|
|
| wireMag wire == 0 = board
|
|
|
|
|
| otherwise = applyWire (wireMap (pred) wire) $ moveBoardPos wire (applyAtPos board)
|
2019-12-04 12:55:38 -05:00
|
|
|
|
|
|
|
|
applyAtPos :: Board -> Board
|
|
|
|
|
applyAtPos board = applyAt (pos board) board
|
|
|
|
|
|
|
|
|
|
applyAt :: (Int, Int) -> Board -> Board
|
2019-12-05 08:22:07 -05:00
|
|
|
applyAt (x, y) board = board |> growBoard (x + 2, y + 2) |> mapBoardMat (updateMat (x, y))
|
2019-12-04 12:55:38 -05:00
|
|
|
|
|
|
|
|
--applyWires :: Wires -> Board -> Board
|
|
|
|
|
--applyWires wires board =
|
2019-12-05 08:22:07 -05:00
|
|
|
--applyWire :: Wire -> Board -> Board
|
|
|
|
|
type Wires = [Wire]
|
2019-12-03 17:57:43 -05:00
|
|
|
|
|
|
|
|
type Mat = [[Bool]]
|
|
|
|
|
|
|
|
|
|
data Board =
|
|
|
|
|
Board
|
|
|
|
|
{ mat :: Mat
|
|
|
|
|
, pos :: (Int, Int)
|
|
|
|
|
, origin :: (Int, Int)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emptyBoard :: Board
|
|
|
|
|
emptyBoard = Board {mat = [], pos = (0, 0), origin = (0, 0)}
|
|
|
|
|
|
|
|
|
|
growBoard :: (Int, Int) -> Board -> Board
|
|
|
|
|
growBoard (x, y) board = growBoardX x (growBoardY y board)
|
|
|
|
|
|
|
|
|
|
growBoardY :: Int -> Board -> Board
|
|
|
|
|
growBoardY 0 board = board
|
|
|
|
|
growBoardY y board = do
|
|
|
|
|
let incY (x0, y0) = (x0, y0 + abs y)
|
|
|
|
|
let newBoard = mapBoardMat (growMatY y) board
|
|
|
|
|
if y < 0
|
|
|
|
|
then mapBoardPos incY $ mapBoardOrigin incY newBoard
|
|
|
|
|
else newBoard
|
|
|
|
|
|
|
|
|
|
growBoardX :: Int -> Board -> Board
|
|
|
|
|
growBoardX 0 board = board
|
|
|
|
|
growBoardX x board = do
|
|
|
|
|
let incX (x0, y0) = (x0 + abs x, y0)
|
|
|
|
|
let newBoard = mapBoardMat (growMatX x) board
|
|
|
|
|
if x < 0
|
|
|
|
|
then mapBoardPos incX $ mapBoardOrigin incX newBoard
|
|
|
|
|
else newBoard
|
|
|
|
|
|
|
|
|
|
mapBoardMat :: (Mat -> Mat) -> Board -> Board
|
|
|
|
|
mapBoardMat mapping board =
|
2019-12-05 08:22:07 -05:00
|
|
|
Board {mat = withBoardMat mapping board, pos = (pos board), origin = (origin board)}
|
2019-12-03 17:57:43 -05:00
|
|
|
|
|
|
|
|
withBoardMat :: (Mat -> a) -> Board -> a
|
|
|
|
|
withBoardMat mapping board = (mapping (mat board))
|
|
|
|
|
|
|
|
|
|
mapBoardOrigin :: ((Int, Int) -> (Int, Int)) -> Board -> Board
|
|
|
|
|
mapBoardOrigin mapping board =
|
|
|
|
|
Board {mat = mat board, pos = pos board, origin = mapping (origin board)}
|
|
|
|
|
|
|
|
|
|
withBoardOrigin :: ((Int, Int) -> a) -> Board -> a
|
|
|
|
|
withBoardOrigin mapping board = (mapping (origin board))
|
|
|
|
|
|
2019-12-05 08:22:07 -05:00
|
|
|
moveBoardPos :: Wire -> Board -> Board
|
|
|
|
|
moveBoardPos wire board = newBoard
|
|
|
|
|
where
|
|
|
|
|
(wireX, wireY) = wireDir wire
|
|
|
|
|
newBoard = mapBoardPos (\(posX, posY) -> (posX + wireX, posY + wireY)) board
|
|
|
|
|
|
2019-12-03 17:57:43 -05:00
|
|
|
mapBoardPos :: ((Int, Int) -> (Int, Int)) -> Board -> Board
|
|
|
|
|
mapBoardPos mapping board =
|
|
|
|
|
Board {mat = mat board, pos = mapping (pos board), origin = origin board}
|
|
|
|
|
|
|
|
|
|
withBoardPos :: ((Int, Int) -> a) -> Board -> a
|
|
|
|
|
withBoardPos mapping board = (mapping (pos board))
|
|
|
|
|
|
|
|
|
|
instance Show Board where
|
|
|
|
|
show board =
|
|
|
|
|
concat $
|
|
|
|
|
intersperse
|
|
|
|
|
"\n"
|
2019-12-05 08:22:07 -05:00
|
|
|
[[boardChar (x, y) board | (x, _) <- zip [0 ..] row] | (y, row) <- zip [0 ..] (mat board)]
|
2019-12-03 17:57:43 -05:00
|
|
|
|
|
|
|
|
boardChar :: (Int, Int) -> Board -> Char
|
|
|
|
|
boardChar loc board
|
|
|
|
|
| (origin board) == loc = 'o'
|
|
|
|
|
| (pos board) == loc = '*'
|
|
|
|
|
| otherwise = do
|
|
|
|
|
let (x, y) = loc
|
|
|
|
|
if (mat board) !! y !! x
|
|
|
|
|
then '+'
|
|
|
|
|
else '.'
|
|
|
|
|
|
2019-12-05 08:22:07 -05:00
|
|
|
data Wire
|
2019-12-03 17:57:43 -05:00
|
|
|
= Up Int
|
|
|
|
|
| Dn Int
|
|
|
|
|
| Lt Int
|
|
|
|
|
| Rt Int
|
|
|
|
|
|
2019-12-05 08:22:07 -05:00
|
|
|
parseWire :: String -> Wire
|
|
|
|
|
parseWire text = do
|
2019-12-03 17:57:43 -05:00
|
|
|
let n = read $ tail text
|
|
|
|
|
case text !! 0 of
|
|
|
|
|
'U' -> Up n
|
|
|
|
|
'D' -> Dn n
|
|
|
|
|
'L' -> Lt n
|
|
|
|
|
'R' -> Rt n
|
|
|
|
|
|
2019-12-05 08:22:07 -05:00
|
|
|
wireMap :: (Int -> Int) -> Wire -> Wire
|
|
|
|
|
wireMap mapping (Up n) = Up (mapping n)
|
|
|
|
|
wireMap mapping (Dn n) = Dn (mapping n)
|
|
|
|
|
wireMap mapping (Lt n) = Lt (mapping n)
|
|
|
|
|
wireMap mapping (Rt n) = Rt (mapping n)
|
|
|
|
|
|
|
|
|
|
wireMag :: Wire -> Int
|
|
|
|
|
wireMag (Up n) = n
|
|
|
|
|
wireMag (Dn n) = n
|
|
|
|
|
wireMag (Lt n) = n
|
|
|
|
|
wireMag (Rt n) = n
|
|
|
|
|
|
|
|
|
|
wirePair :: Wire -> (Int, Int)
|
|
|
|
|
wirePair (Up n) = (0, -n)
|
|
|
|
|
wirePair (Dn n) = (0, n)
|
|
|
|
|
wirePair (Lt n) = (-n, 0)
|
|
|
|
|
wirePair (Rt n) = (n, 0)
|
|
|
|
|
|
|
|
|
|
wireDir :: Wire -> (Int, Int)
|
|
|
|
|
wireDir (Up n) = (0, -1)
|
|
|
|
|
wireDir (Dn n) = (0, 1)
|
|
|
|
|
wireDir (Lt n) = (-1, 0)
|
|
|
|
|
wireDir (Rt n) = (1, 0)
|
2019-12-03 17:57:43 -05:00
|
|
|
|
2019-12-04 12:55:38 -05:00
|
|
|
updateMat :: (Int, Int) -> Mat -> Mat
|
|
|
|
|
updateMat (x, y) mat = newMat
|
|
|
|
|
where
|
|
|
|
|
(rowHead, _:rowTail) = splitAt y mat
|
|
|
|
|
row = mat !! y
|
|
|
|
|
(colHead, _:colTail) = splitAt x row
|
|
|
|
|
newMat = rowHead ++ [colHead ++ True : colTail] ++ rowTail
|
|
|
|
|
|
2019-12-05 08:22:07 -05:00
|
|
|
growMatWire :: Wire -> Mat -> Mat
|
|
|
|
|
growMatWire wire mat
|
|
|
|
|
| wireMag wire == 0 = mat
|
|
|
|
|
| otherwise = growMat (wirePair wire) mat
|
2019-12-03 17:57:43 -05:00
|
|
|
|
|
|
|
|
growMat :: (Int, Int) -> Mat -> Mat
|
|
|
|
|
growMat (x, y) mat = growMatX x (growMatY y mat)
|
|
|
|
|
|
|
|
|
|
growMatX :: Int -> Mat -> Mat
|
|
|
|
|
growMatX 0 mat = mat
|
|
|
|
|
growMatX x mat =
|
|
|
|
|
if x < 0
|
|
|
|
|
then [take (abs x) (repeat False) ++ row | row <- mat]
|
|
|
|
|
else [row ++ take (abs x) (repeat False) | row <- mat]
|
|
|
|
|
|
|
|
|
|
growMatY :: Int -> Mat -> Mat
|
|
|
|
|
growMatY 0 mat = mat
|
|
|
|
|
growMatY y mat =
|
|
|
|
|
if y < 0
|
|
|
|
|
then (take (abs y) (repeat (take (matW mat) (repeat False)))) ++ mat
|
|
|
|
|
else mat ++ (take (abs y) (repeat (take (matW mat) (repeat False))))
|
|
|
|
|
|
|
|
|
|
matSize :: Mat -> (Int, Int)
|
|
|
|
|
matSize mat = (matW mat, matH mat)
|
|
|
|
|
|
|
|
|
|
matW :: Mat -> Int
|
|
|
|
|
matW mat =
|
|
|
|
|
if matH mat == 0
|
|
|
|
|
then 0
|
2019-12-04 12:55:38 -05:00
|
|
|
else mx (fmap length mat)
|
2019-12-03 17:57:43 -05:00
|
|
|
|
|
|
|
|
matH :: Mat -> Int
|
|
|
|
|
matH mat = length mat
|
|
|
|
|
|
|
|
|
|
mx :: [Int] -> Int
|
|
|
|
|
mx [] = 0
|
|
|
|
|
mx [x] = x
|
|
|
|
|
mx (x:xs)
|
|
|
|
|
| (mx xs) > x = mx xs
|
|
|
|
|
| otherwise = x
|