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.

110 lines
3.1 KiB

#lang racket
(require "lib/common.rkt")
(struct cposn (x y z) #:transparent)
(define (parse prt)
(define (line->directions chrs)
(match chrs
['() '()]
[(list* #\s #\e _) (cons 'southeast (line->directions (drop chrs 2)))]
[(list* #\s #\w _) (cons 'southwest (line->directions (drop chrs 2)))]
[(list* #\n #\e _) (cons 'northeast (line->directions (drop chrs 2)))]
[(list* #\n #\w _) (cons 'northwest (line->directions (drop chrs 2)))]
[(list* #\e _) (cons 'east (line->directions (rest chrs)))]
[(list* #\w _) (cons 'west (line->directions (rest chrs)))]))
(map (compose1 line->directions string->list) (port->lines prt)))
(define (direction->cposn dir)
(match dir
['east (cposn 1 -1 0)]
['west (cposn -1 1 0)]
['southeast (cposn 0 -1 1)]
['southwest (cposn -1 0 1)]
['northeast (cposn 1 0 -1)]
['northwest (cposn 0 1 -1)]))
(define directions
(map direction->cposn '(east west southeast southwest northeast northwest)))
(define (cposn+ p1 p2)
(match-define (cposn x1 y1 z1) p1)
(match-define (cposn x2 y2 z2) p2)
(cposn (+ x1 x2) (+ y1 y2) (+ z1 z2)))
(define (generate-tiles input)
(define traversals (map (λ (l) (map direction->cposn l)) input))
(define tiles (make-hash))
(define (flip! posn)
(hash-update! tiles posn not #f))
(define (follow-and-flip! path)
(for/fold ([p (cposn 0 0 0)]
#:result (flip! p))
([d (in-list path)])
(cposn+ p d)))
(for* ([trav (in-list traversals)])
(follow-and-flip! trav))
(define (day24a input)
(for/sum ([(_ v) (in-hash (generate-tiles input))]
#:when v)
(define (tile-black? tiles p)
(hash-ref tiles p #f))
(define (get-neighbors p)
(for/list ([d (in-list directions)])
(cposn+ d p)))
(define (count-neighbors tiles p)
(for/sum ([d (in-list (get-neighbors p))]
#:when (tile-black? tiles d))
(define (tick-tiles tiles radius)
(define work (hash-copy tiles))
(define (flippe-floppe! posn)
(hash-update! work posn not #f))
(define (check-and-flip! p)
(define n (count-neighbors tiles p))
(when (or (and (tile-black? tiles p)
(or (zero? n) (> n 2)))
(and (not (tile-black? tiles p))
(= n 2)))
(flippe-floppe! p)))
(for* ([x (in-range (- radius) (add1 radius))]
[y (in-range (- radius) (add1 radius))]
[z (in-range (- radius) (add1 radius))]
#:when (zero? (+ x y z)))
(check-and-flip! (cposn x y z)))
(define (day24b input)
(define tiles (generate-tiles input))
(define radius
(for/max ([(p _) (in-hash tiles)])
(max (abs (cposn-x p))
(abs (cposn-y p))
(abs (cposn-z p)))))
(define result
(for/fold ([t tiles])
([i (in-range 100)]
[r (in-range (add1 radius) +inf.0)])
(tick-tiles t r)))
(for/sum ([(_ v) (in-hash result)]
#:when v)
(module+ main
(call-with-input-file "data/day24.txt"
(λ (prt)
(define input (parse prt))
(answer 24 1 (day24a input))
(answer 24 2 (day24b input)))))