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.

90 lines
2.7 KiB

#lang racket
(require "lib/common.rkt")
(struct 4posn (x y z w) #:transparent)
(define (board-dim board)
(define x (map 4posn-x (set->list board)))
(define y (map 4posn-y (set->list board)))
(define z (map 4posn-z (set->list board)))
(define w (map 4posn-w (set->list board)))
(list (cons (apply min x) (apply max x))
(cons (apply min y) (apply max y))
(cons (apply min z) (apply max z))
(cons (apply min w) (apply max w))))
(define (board-set! board x y z w val)
(if val
(set-add! board (4posn x y z w))
(set-remove! board (4posn x y z w))))
(define (board-ref board x y z w)
(set-member? board (4posn x y z w)))
(define (board-copy board)
(set-copy board))
(define (active? board x y z w)
(board-ref board x y z w))
(define (inactive? board x y z w)
(not (active? board x y z w)))
(define (in-adj-range pair)
(in-range (- (car pair) 1) (+ (cdr pair) 2)))
(define (parse prt)
(define strt
(list->vector (map (compose1 list->vector string->list)
(port->lines prt))))
(define xlen (vector-length (vector-ref strt 0)))
(define ylen (vector-length strt))
(for*/mutable-set ([i (in-range xlen)]
[j (in-range ylen)]
#:when (char=? (vector-ref (vector-ref strt j) i) #\#))
(4posn i j 0 0)))
(define (count-neighbors board x y z w)
(for*/sum ([dx (in-adj-range (cons x x))]
[dy (in-adj-range (cons y y))]
[dz (in-adj-range (cons z z))]
[dw (in-adj-range (cons w w))]
#:unless (and (= dx x) (= dy y)
(= dz z) (= dw w)))
(if (active? board dx dy dz dw) 1 0)))
(define (count-occupied board)
(set-count board))
(define (tick-state board part1?)
(match-define (list m n o p) (board-dim board))
(define res (board-copy board))
(for* ([i (in-adj-range m)]
[j (in-adj-range n)]
[k (in-adj-range o)]
[l (if part1? '(0) (in-adj-range p))])
(define neighbors (count-neighbors board i j k l))
(cond [(and (active? board i j k l)
(not (<= 2 neighbors 3)))
(board-set! res i j k l #f)]
[(and (inactive? board i j k l)
(= 3 neighbors))
(board-set! res i j k l #t)]))
res)
(define (day17a board)
(for/fold ([brd board]
#:result (count-occupied brd))
([_ (in-range 6)])
(tick-state brd #t)))
(define (day17b board)
(for/fold ([brd board]
#:result (count-occupied brd))
([_ (in-range 6)])
(tick-state brd #f)))
(module+ main
(call-with-input-file "data/day17.txt"
(λ (prt)
(define input (parse prt))
(answer 17 1 (day17a input))
(answer 17 2 (day17b input)))))