(function :FerrySquare floor [:Array n :SeatsChanged changed] floor) (function :FerrySquare emptySeat [:Array n :SeatsChanged changed] // Empty seats with completely empty neighbors, fill up (cond ((= true (apply = (for neighbor n #{neighbor != fullSeat;}#))) (set changed.changed true) fullSeat) (true emptySeat))) (function :FerrySquare fullSeat [:Array n :SeatsChanged changed] // Full seats with 4 or more full neighbors become empty (cond ((<= 4 (count n (lambda [neighbor] #{neighbor == fullSeat;}#))) (set changed.changed true) emptySeat) (true fullSeat))) (function neighbors [x y :Array> grid] (localVar &mut n []) (doFor xx (range (- x 1) (+ x 2)) (doFor yy (range (- y 1) (+ y 2)) (unless (and (= x xx) (= y yy)) (when (and (<= 0 xx) (<= 0 yy) (> grid.length yy) (> .length (nth grid yy) xx)) (n.push (nth (nth grid yy) xx)))))) n) (prop &mut :Array> state []) (method simulate [] (localVar changed (object changed false)) (set state (for rowIdx (range state.length) (let [:Array row (nth state rowIdx)] (for seatIdx (range row.length) ((nth row seatIdx) (neighbors seatIdx rowIdx state) changed))))) changed.changed) (method fullSimulate [] (when (simulate) (fullSimulate))) (method countFullSeats [] (apply + (for :Array row state (apply + (for :FerrySquare seat row (if #{seat == fullSeat;}# 1 0)))))) (defReaderMacro "L" [stream] `emptySeat) (defReaderMacro "#" [stream] `fullSeat) (defReaderMacro "." [stream] `floor) (undefReaderMacro "...") (defReaderMacro &start "" [stream] `(state.push ,(ReaderExp.ListExp (readExpArray stream "\n"))))