## Part 1

Alright, a Conway’s Game of Life/cellular automata problem. Also see AoC 2019 day 24, which I happened to do just a week ago (finally!) in Julia. May as well leverage that code…

I immediately hit a bit of a problem, I used a `BitArray` for that, while this is a trinary state (empty seat, filled seat, floor). An enum may be handy here, let’s see how Julia’s `@enum` macro works.

``````@enum Ferry empty filled floor
``````

Trying to construct an array of Enums is a bit more complicated, since `zeros()` etc. don’t work. Comprehension it is!

``````board = [floor for j in 1:rows, i in 1:cols]
``````

Logic is simple: loop over `board`, count neighbors, and update. I leverage Julia’s views to concisely grab the neighbors (without copying!) and count the filled seats:

``````v = @view board[max(j-1,1):min(j+1,r), max(i-1,1):min(i+1,c)]
n = count(x->x==filled, v)
``````

I do, however, make a new copy of the board with each `update`, rather than trying to juggle two boards for instance. So I won’t win any allocation prizes.

## Part 2

Is there a clever way to do this? My first thought was an overlay filter, but no, since we need to actually “walk” away from the seat to find the first seat, filled or not. I’ll at least take advantage of Julia’s array slicing, e.g.:

``````up(board, j, i) = j==1 ? Ferry[] : board[j-1:-1:1, i]
upright(board, j, i) = j==1 || i==size(board,2) ? Ferry[] :
[board[j-x,i+x] for x in 1:min(j-1, size(board,2)-i)]
``````

Then it’s just a `reduce()` call to walk through and find the first seat.

``````firstfilled(v:Vector{Ferry})::Bool = reduce((x,y)->x==floor ? y : x, v; init=floor) == filled
``````

Do this for every direction, and we get the number of occupied seats:

``````n = [up,upright,right,downright,down,downleft,left,upleft] .|> f->firstfilled(f(board,j,i)) |> sum
``````

Admittedly this solution gets a bit ugly. Maybe there’s some clever topological math we can use instead?