make work for non rectangular fields as well
[aoc20.git] / 11 / one.icl
1 module one
2
3 import StdEnv
4 import Data.Func
5
6 import Text
7
8 read :: *File -> [String]
9 read f
10 # (l, f) = freadline f
11 | l.[size l - 1] <> '\n' = []
12 = [l % (0, size l - 2):read f]
13
14 Start w
15 # (io, w) = stdio w
16 # ls = read io
17 # ls = {l\\l<-ls}
18 = (one ls, two ls)
19
20 one = numOccupied o cell isOccupied ((==)0) ((<=)4)
21 two = numOccupied o cell seeOccupied ((==)0) ((<=)5)
22
23 isOccupied :: Int Int Int Int {#String} -> Bool
24 isOccupied x y dx dy ls = seat (x+dx) (y+dy) ls == '#'
25
26 seeOccupied :: Int Int Int Int {#String} -> Bool
27 seeOccupied x y dx dy ls = case seat (x+dx) (y+dy) ls of
28 '#' = True
29 'L' = False
30 '-' = False
31 '.' = seeOccupied (x+dx) (y+dy) dx dy ls
32
33 numOccupied :: {#String} -> Int
34 numOccupied ls = length [()\\r<-:ls, c<-:r | c == '#']
35
36 cell :: (Int Int Int Int {#String} -> Bool) (Int -> Bool) (Int -> Bool) {#String} -> {#String}
37 cell lookfun live die ls
38 # ls` = {{step x y\\x<-[0..size ls.[y] - 1]}\\y<-[0..size ls - 1]}
39 = if (and [l==r\\l<-:ls` & r<-:ls]) ls (cell lookfun live die ls`)
40 where
41 step x y = case ls.[y,x] of
42 '.' = '.'
43 'L' = if (live numOccupied) '#' 'L'
44 '#' = if (die numOccupied) 'L' '#'
45 where
46 numOccupied = length [()\\dx<-[-1..1], dy<-[-1..1] | not (dx == 0 && dy == 0) && lookfun x y dx dy ls]
47
48 seat :: Int Int {#String} -> Char
49 seat x y ls
50 | y < 0 || y >= size ls || x < 0 || x >= size ls.[y] = '-'
51 = ls.[y,x]