Updated blog link
[advent-of-code-21.git] / advent13 / Main.hs
1 -- Writeup at https://work.njae.me.uk/2021/12/13/advent-of-code-2021-day-13/
2
3 import Data.Text ()
4 import qualified Data.Text.IO as TIO
5
6 import Data.Attoparsec.Text
7 import Control.Applicative
8
9 import qualified Data.Set as S
10 -- import Data.Set ((\\))
11 import Linear (V2(..), (^+^))
12 import Data.List
13
14
15 type Coord = V2 Int
16 type Sheet = S.Set Coord
17
18 data Axis = X | Y
19 deriving (Eq, Ord, Show)
20
21 data Fold = Fold Axis Int
22 deriving (Eq, Ord, Show)
23
24 main :: IO ()
25 main =
26 do text <- TIO.readFile "data/advent13.txt"
27 let (sheet, folds) = successfulParse text
28 print $ part1 sheet folds
29 putStrLn $ part2 sheet folds
30
31 part1 :: Sheet -> [Fold] -> Int
32 part1 sheet folds = S.size $ doFold sheet $ head folds
33
34 part2 :: Sheet -> [Fold] -> String
35 part2 sheet folds = showSheet foldedSheet
36 where foldedSheet = foldl' doFold sheet folds
37
38 doFold :: Sheet -> Fold -> Sheet
39 doFold sheet (Fold X i) = S.union left foldedRight
40 where (left, right) = S.partition ((<= i) . getX) sheet
41 foldedRight = S.map foldDot right
42 foldDot (V2 x y) = V2 (i - (x - i)) y
43
44 doFold sheet (Fold Y i) = S.union top foldedBottom
45 where (top, bottom) = S.partition ((<= i) . getY) sheet
46 foldedBottom = S.map foldDot bottom
47 foldDot (V2 x y) = V2 x (i - (y - i))
48
49 getX :: Coord -> Int
50 getX (V2 x _) = x
51
52 getY :: Coord -> Int
53 getY (V2 _ y) = y
54
55
56 showSheet :: Sheet -> String
57 showSheet sheet = unlines [ concat [showPoint (V2 x y) | x <- ([0..maxX] :: [Int])
58 ] | y <- ([0..maxY] :: [Int]) ]
59 where showPoint here = if here `S.member` sheet then "█" else " "
60 maxX = S.findMax $ S.map getX sheet
61 maxY = S.findMax $ S.map getY sheet
62
63
64 -- Parse the input file
65
66 inputP = (,) <$> sheetP <* many1 endOfLine <*> foldsP
67
68 sheetP = S.fromList <$> dotP `sepBy` endOfLine
69 dotP = V2 <$> decimal <* "," <*> decimal
70
71 foldsP = foldP `sepBy` endOfLine
72 foldP = Fold <$> ("fold along " *> axisP) <* "=" <*> decimal
73
74 axisP = ("x" *> pure X) <|> ("y" *> pure Y)
75
76 -- successfulParse :: Text -> (Integer, [Maybe Integer])
77 successfulParse input =
78 case parseOnly inputP input of
79 Left _err -> (S.empty, []) -- TIO.putStr $ T.pack $ parseErrorPretty err
80 Right indata -> indata