···11+import Data.List ((!?))
22+import Text.Parsec
33+44+surrounding x y =
55+ [ (x - 1, y - 1),
66+ (x, y - 1),
77+ (x + 1, y - 1),
88+ (x - 1, y),
99+ (x + 1, y),
1010+ (x - 1, y + 1),
1111+ (x, y + 1),
1212+ (x + 1, y + 1)
1313+ ]
1414+1515+answer input =
1616+ length
1717+ [ 1 | y <- [0 .. length grid - 1],
1818+ x <- [0 .. (length $ grid !! y) - 1],
1919+ grid !! y !! x == '@',
2020+ length [1 | (x2, y2) <- surrounding x y,
2121+ ((grid !? y2) >>= (!? x2)) == (Just '@')] < 4
2222+ ]
2323+ where
2424+ Right grid = parse ((many $ oneOf "@.") `sepEndBy` char '\n') "" input
2525+2626+main = getContents >>= print . answer
+27
2025/4/p1.tri
···11+import "trilogy:debug" use dbg, tap
22+import "trilogy:core" use length
33+import "trilogy:io" use readall
44+import "trilogy:grid" as grid
55+import "trilogy:number" use im, re, swap
66+import "trilogy:array" use map, filter
77+import "trilogy:parsec" use parse, end_by, char, many, char_of
88+99+func get g p = with g.(swap <| im p).(re p) when 'mia cancel '.' else yield
1010+1111+proc main!() {
1212+ let rows = parse (end_by (char '\n') <| many <| char_of "@.") readall!()
1313+ let g = grid::from!(rows)
1414+1515+ let mut count = 0
1616+ for pos:'@' in g {
1717+ let around = grid::surrounding pos
1818+ # TODO: something is wrong when passing the large record around, the runtime freezes
1919+ # up. Accessing from the array here instead works a little better, but it's still way
2020+ # too slow, and not linearly
2121+ |> map (get rows)
2222+ |> filter ((==) '@')
2323+ |> length
2424+ if around < 4 { count += 1 }
2525+ }
2626+ dbg!(count)
2727+}
+31
2025/4/p2.hs
···11+import Data.List ((!?))
22+import Text.Parsec
33+44+surrounding x y =
55+ [ (x - 1, y - 1),
66+ (x, y - 1),
77+ (x + 1, y - 1),
88+ (x - 1, y),
99+ (x + 1, y),
1010+ (x - 1, y + 1),
1111+ (x, y + 1),
1212+ (x + 1, y + 1)
1313+ ]
1414+1515+at grid x y = case ((grid !? y) >>= (!? x)) of
1616+ Just ch -> ch
1717+ Nothing -> '.'
1818+1919+isBlocked grid (x, y) = at grid x y == '@'
2020+2121+clean grid = if cleaned == grid then grid else clean cleaned
2222+ where
2323+ cleaned = [[if at grid x y == '.' || (length $ filter (isBlocked grid) $ surrounding x y) < 4 then '.' else '@' | x <- [0 .. (length $ grid !! y) - 1]] | y <- [0 .. length grid - 1]]
2424+2525+answer input = init - final
2626+ where
2727+ Right grid = parse ((many $ oneOf "@.") `sepEndBy` char '\n') "" input
2828+ init = length $ filter ((==) '@') input
2929+ final = length $ filter ((==) '@') $ concat $ (clean grid)
3030+3131+main = getContents >>= print . answer