#lang curly-fn racket (require "scripts/aoc.rkt") ;; solution for day 24 ;; constraint: x+y+z = 0 ;; this could be formalized with a contract but part2 is already slow enough tbh (struct hex [x y z] #:transparent) (define (hex+ a b) (hex (+ (hex-x a) (hex-x b)) (+ (hex-y a) (hex-y b)) (+ (hex-z a) (hex-z b)))) (define *dirs* (hash 'e (hex 1 -1 0) 'ne (hex 1 0 -1) 'nw (hex 0 1 -1) 'w (hex -1 1 0) 'sw (hex -1 0 1) 'se (hex 0 -1 1))) (define (paths->tiles input) ;; white is #f ;; black is #t (define tiles (make-hash)) (for ([path (in-list input)]) (define posn (for/fold ([posn (hex 0 0 0)]) ([p (in-list path)]) (hex+ posn (hash-ref *dirs* p)))) (hash-update! tiles posn not #f)) tiles) (define (count-black tiles) (for/sum ([(_ v) (in-hash tiles)] #:when v) 1)) (define (part1 input) (count-black (paths->tiles input))) (define (part2 input) (define tiles (paths->tiles input)) (define neighbors-cache (make-hash)) (define (step tiles radius) (define new-tiles (make-hash)) (for* ([x (in-range (- radius) (add1 radius))] [y (in-range (- radius) (add1 radius))] [z (in-range (- radius) (add1 radius))] #:when (zero? (+ x y z))) (define thispos (hex x y z)) (define thistile (hash-ref tiles thispos #f)) (define neighbors (hash-ref! neighbors-cache thispos (thunk (for/list ([t (in-list (hash-values *dirs*))]) (hex+ thispos t))))) (define num-blacks (for/sum ([neigh (in-list neighbors)] #:when (hash-ref tiles neigh #f)) 1)) (hash-set! new-tiles thispos (match* (thistile num-blacks) [(#t (or 0 (not (or 1 2)))) #f] [(#t _) #t] [(#f 2) #t] [(#f _) #f]))) new-tiles) (define radius (apply max (map #{max (abs (hex-x %)) (abs (hex-y %)) (abs (hex-z %))} (hash-keys tiles)))) (begin0 (count-black (for/fold ([tiles tiles]) ([i (in-range 100)] [radius (in-range (add1 radius) +inf.0)]) (printf "\r\x1b[K~a/100..." i) (flush-output) (step tiles radius))) (printf "\r\1b[Kdone\n"))) ;; parse input file (define (parse fname) (for/list ([line (in-list (file->lines fname))]) (map string->symbol (regexp-match* #px"(e|se|sw|w|nw|ne)" line)))) (module+ test (require rackunit) ;; tests here (displayln "no tests :(")) (module+ main (define input (parse "inputs/24")) (answer 24 1 (time (part1 input))) (answer 24 2 (time (part2 input))) (displayln "meow"))