diff --git a/17.rkt b/17.rkt index bdb9499..d2f2a19 100644 --- a/17.rkt +++ b/17.rkt @@ -5,85 +5,68 @@ ;; solution for day 17 (struct pt [x y z w] #:transparent) +(define pt-getters (list pt-x pt-y pt-z pt-w)) -(define (part1 input) - (define world (hash-copy input)) - (define (simulate world) - (define new-world (make-hash)) - (define min-x (apply min (map pt-x (hash-keys world)))) - (define max-x (apply max (map pt-x (hash-keys world)))) - (define min-y (apply min (map pt-y (hash-keys world)))) - (define max-y (apply max (map pt-y (hash-keys world)))) - (define min-z (apply min (map pt-z (hash-keys world)))) - (define max-z (apply max (map pt-z (hash-keys world)))) - (for* ([x (in-range (- min-x 1) (+ max-x 2))] - [y (in-range (- min-y 1) (+ max-y 2))] - [z (in-range (- min-z 1) (+ max-z 2))]) - (define ct (for*/sum ([dx (in-range -1 2)] - [dy (in-range -1 2)] - [dz (in-range -1 2)] - #:unless (and (zero? dx) (zero? dy) (zero? dz)) - #:when (hash-ref world (pt (+ x dx) (+ y dy) (+ z dz) 0) #f)) - 1)) - (define this (pt x y z 0)) - (cond - [(hash-ref world this #f) - (when (or (= 2 ct) (= 3 ct)) - (hash-set! new-world this #t))] - [else - (when (= 3 ct) - (hash-set! new-world this #t))])) - new-world) +(define (pt+ . args) + (for/fold ([ans (pt 0 0 0 0)]) ([x (in-list args)]) + (apply pt (map #{+ (% ans) (% x)} pt-getters)))) - (for ([i (in-range 6)]) - (set! world (simulate world))) - (length (filter identity (hash-values world)))) +(define (in-pts lower upper use-w?) + (define (in-range+ getter) + (in-range (sub1 (getter lower)) (+ 2 (getter upper)))) + (for*/stream ([x (in-range+ pt-x)] + [y (in-range+ pt-y)] + [z (in-range+ pt-z)] + [w (if use-w? (in-range+ pt-w) (in-range 1))]) + (pt x y z w))) -(define (part2 input) - (define world (hash-copy input)) - (define (simulate world) - (define new-world (make-hash)) - (define min-x (apply min (map pt-x (hash-keys world)))) - (define max-x (apply max (map pt-x (hash-keys world)))) - (define min-y (apply min (map pt-y (hash-keys world)))) - (define max-y (apply max (map pt-y (hash-keys world)))) - (define min-z (apply min (map pt-z (hash-keys world)))) - (define max-z (apply max (map pt-z (hash-keys world)))) - (define min-w (apply min (map pt-w (hash-keys world)))) - (define max-w (apply max (map pt-w (hash-keys world)))) - (for* ([x (in-range (- min-x 1) (+ max-x 2))] - [y (in-range (- min-y 1) (+ max-y 2))] - [z (in-range (- min-z 1) (+ max-z 2))] - [w (in-range (- min-w 1) (+ max-w 2))]) - (define ct (for*/sum ([dx (in-range -1 2)] - [dy (in-range -1 2)] - [dz (in-range -1 2)] - [dw (in-range -1 2)] - #:unless (and (zero? dx) (zero? dy) (zero? dz) (zero? dw)) - #:when (hash-ref world (pt (+ x dx) (+ y dy) (+ z dz) (+ w dw)) #f)) - 1)) - (define this (pt x y z w)) - (cond - [(hash-ref world this #f) - (when (or (= 2 ct) (= 3 ct)) - (hash-set! new-world this #t))] - [else - (when (= 3 ct) - (hash-set! new-world this #t))])) - new-world) +(define nearby/4d + (for*/list ([x (in-range -1 2)] + [y (in-range -1 2)] + [z (in-range -1 2)] + [w (in-range -1 2)] + #:unless (and (zero? x) (zero? y) (zero? z) (zero? w))) + (pt x y z w))) - (for ([i (in-range 6)]) - (set! world (simulate world))) - (length (filter identity (hash-values world)))) +(define nearby/3d (filter #{zero? (pt-w %)} nearby/4d)) + +(define (calc-bounds world) + (define (helper getter reducer) + (apply reducer (set-map world getter))) + (define (helper2 reducer) + (apply pt (map #{helper % reducer} pt-getters))) + (values (helper2 min) (helper2 max))) + +(define (simulate world use-w?) + (define new-world (mutable-set)) + (define-values [lower upper] (calc-bounds world)) + (define nearby (if use-w? nearby/4d nearby/3d)) + + (for ([pt (in-pts lower upper use-w?)]) + (define ct + (for*/sum ([nb (in-list nearby)]) + (if (set-member? world (pt+ pt nb)) 1 0))) + (when (if (set-member? world pt) (<= 2 ct 3) (= 3 ct)) + (set-add! new-world pt))) + + new-world) + +(define (simulate/times world times use-w?) + (set-count + (for/fold ([world world]) ([_ (in-range times)]) + (simulate world use-w?)))) + +(define part1 #{simulate/times % 6 #f}) +(define part2 #{simulate/times % 6 #t}) ;; parse input file (define (parse fname) (define input (file->lines fname)) - (define world (make-hash)) + (define world (mutable-set)) (for ([line (in-list input)] [y (in-naturals)]) (for ([char (in-string line)] [x (in-naturals)]) (when (char=? #\# char) - (hash-set! world (pt x y 0 0) #t)))) + (set-add! world (pt x y 0 0))))) world) (module+ test