-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday03.hs
86 lines (78 loc) · 2.69 KB
/
day03.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import Control.Monad (guard)
import Data.Char (digitToInt, isDigit)
import Data.Text qualified as T
import Lib (readFile')
-- i hate this problem, let's just do an ugly recursion and be done with it
type Symbol = Int
data Number = Number
{ value :: Int,
start :: Int,
end :: Int
}
deriving (Show)
parseLines :: [T.Text] -> ([[Symbol]], [[Number]])
parseLines lines =
foldl
( \(symbols, numbers) line ->
let (symbols', numbers') = parseLine line
in (symbols' : symbols, numbers' : numbers)
)
([], [])
lines
-- ugly, i know but runs p fast with -O2
parseLine :: T.Text -> ([Symbol], [Number])
parseLine line =
let (num, start, end, isNum, symbols, numbers) = T.foldl fn (0, 0, 0, False, [], []) line
in (symbols, if isNum then Number num start (end - 1) : numbers else numbers)
where
fn :: (Int, Int, Int, Bool, [Symbol], [Number]) -> Char -> (Int, Int, Int, Bool, [Symbol], [Number])
fn (num, start, end, isNum, symbols, numbers) char =
let isNum' = isDigit char
num' = if isNum' then num * 10 + digitToInt char else 0
start' = if not isNum' then end + 1 else start
symbols' =
if char /= '.' && not isNum'
then end : symbols
else symbols
numbers' =
if isNum && not isNum'
then Number num start (end - 1) : numbers
else numbers
in (num', start', end + 1, isNum', symbols', numbers')
groups3 :: [a] -> [[a]]
groups3 xs = take 3 xs : groups3 (tail xs)
first :: [[Symbol]] -> [[Number]] -> [[Int]]
first symbols numbers =
let zipped = zip numbers (init $ groups3 ([] : symbols))
in do
(numbersRow, neighbours) <- zipped
return $ do
Number value start end <- numbersRow
guard $ or $ do
neighboursRow <- neighbours
return $ or $ do
symbol <- neighboursRow
return $ symbol >= start - 1 && symbol <= end + 1
return value
second :: [[Symbol]] -> [[Number]] -> [Int]
second symbols numbers =
let zipped = zip symbols (init $ groups3 ([] : numbers))
in do
(symbols, neighbours) <- zipped
symbol <- symbols
let values = take 2 $ do
neighboursRow <- neighbours
Number value start end <- neighboursRow
guard $ symbol >= start - 1
guard $ symbol <= end + 1
return value
guard $ length values == 2
return $ product values
main :: IO ()
main = do
input <- T.lines <$> readFile' "day03.in"
let (symbols, numbers) = parseLines input
putStr "Q1: "
print . sum . concat $ first symbols numbers
putStr "Q2: "
print . sum $ second symbols numbers