Advent of Code 2020 solutions in Racket, I guess
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

104 lines
3.2 KiB

#lang racket
(require "lib/common.rkt")
(provide (all-defined-out))
(define (count-occupied board)
(for/sum ([row (in-vector board)])
(vector-count (lambda (v) (char=? v #\#)) row)))
(define (board-dim board)
(cons (vector-length (vector-ref board 0))
(vector-length board)))
(define (board-set! board x y val)
(vector-set! (vector-ref board y) x val))
(define (board-ref board x y)
(vector-ref (vector-ref board y) x))
(define (board-copy board)
(vector-copy (vector-map vector-copy board)))
(define (dbg-board board)
(for ([row (in-vector board)])
(displayln (vector->list row)))
board)
(define (occupied? board x y)
(char=? (board-ref board x y) #\#))
(define (unoccupied? board x y)
(char=? (board-ref board x y) #\L))
(define (floor? board x y)
(char=? (board-ref board x y) #\.))
(define (count-neighbors/a board x y)
(match-define (cons m n) (board-dim board))
(for*/sum ([dx (in-range (sub1 x) (+ 2 x))]
[dy (in-range (sub1 y) (+ 2 y))]
#:unless (and (= dx x) (= dy y))
#:unless (or (< dx 0) (< dy 0)
(>= dx m)
(>= dy n)))
(if (occupied? board dx dy) 1 0)))
(define (count-neighbors/b board x y)
(match-define (cons m n) (board-dim board))
(define (occupied?/b sx sy dx dy)
(cond [(or (< sx 0) (< sy 0) (>= sx m) (>= sy n)) #f]
[else
(define val (board-ref board sx sy))
(match val
[#\# #t]
[#\L #f]
[#\. (occupied?/b (+ sx dx) (+ sy dy) dx dy)])]))
(for/sum ([path (in-list '((1 . 1) (1 . 0) (1 . -1)
(0 . 1) (0 . -1)
(-1 . 1) (-1 . 0) (-1 . -1)))])
(match-define (cons dx dy) path)
(if (occupied?/b (+ dx x) (+ dy y) dx dy) 1 0)))
(define ((tick-state count-neighbors num-neighbors) board)
(match-define (cons m n) (board-dim board))
(define res (board-copy board))
(for* ([i (in-range 0 m)]
[j (in-range 0 n)])
(define neighbors (count-neighbors board i j))
(cond [(floor? board i j) (void)]
[(and (unoccupied? board i j)
(zero? neighbors))
(board-set! res i j #\#)]
[(and (occupied? board i j)
(>= neighbors num-neighbors))
(board-set! res i j #\L)]))
res)
(define (fix f arg)
(define res (f arg))
(if (equal? res arg)
arg
(fix f res)))
(define (day11a input)
(count-occupied (fix (tick-state count-neighbors/a 4) input)))
(define (day11b input)
(count-occupied (fix (tick-state count-neighbors/b 5) input)))
(define (preprocess prt)
(list->vector (map (compose1 list->vector string->list)
(port->lines prt))))
(module+ main
(call-with-input-file "data/day11.txt"
(lambda (prt)
(define input (preprocess prt))
(answer 11 1 (day11a input))
(answer 11 2 (day11b input)))))
(module+ test
(require rackunit)
(call-with-input-file "data/day11.test.txt"
(lambda (prt)
(define input (preprocess prt))
(check-equal? (count-occupied input) 0)
(check-equal? (board-dim input) (cons 10 10))
(check-equal? (day11a input) 37)
(check-equal? (day11b input) 26))))