You cannot 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.5 KiB
Racket
104 lines
3.5 KiB
Racket
2 years ago
|
#lang racket
|
||
|
|
||
|
(define input
|
||
|
(let* ([lines (file->lines "day14.txt")]
|
||
|
[template (first lines)]
|
||
|
[rule-strings (drop lines 2)]
|
||
|
[rules (map (λ (rs) (string-split rs " -> ")) rule-strings)])
|
||
|
(list template rules)))
|
||
|
|
||
|
(define template (first input))
|
||
|
(define rules (second input))
|
||
|
|
||
|
(define (find-pairs template)
|
||
|
(reverse
|
||
|
(foldl (λ (el acc) (cons (substring template el (+ 2 el)) acc))
|
||
|
'()
|
||
|
(range 0 (sub1 (string-length template))))))
|
||
|
|
||
|
(define (find-inserts pairs rules)
|
||
|
(map (λ (p) (second (assoc p rules))) pairs))
|
||
|
|
||
|
(define (insert-pairs template inserts)
|
||
|
(foldl (λ (idx acc)
|
||
|
(let* ([x (string (string-ref template idx))]
|
||
|
[insert (list-ref (append inserts (list "")) idx)])
|
||
|
(string-append acc x insert)))
|
||
|
"" (range 0 (string-length template))))
|
||
|
|
||
|
(define (step template rules)
|
||
|
(let* ([pairs (find-pairs template)]
|
||
|
[inserts (find-inserts pairs rules)]
|
||
|
[next (insert-pairs template inserts)])
|
||
|
next))
|
||
|
|
||
|
(define (element-counts str)
|
||
|
(let* ([lst (map string (string->list str))]
|
||
|
[ht (make-hash)])
|
||
|
(for-each (λ (x) (hash-set! ht x (+ 1 (hash-ref ht x 0)))) lst)
|
||
|
ht))
|
||
|
|
||
|
(define part1
|
||
|
(let* ([final (foldl (λ (i acc) (step acc rules)) template (range 0 10))]
|
||
|
[counts (element-counts final)]
|
||
|
[values (hash-values counts)]
|
||
|
[minimum (apply min values)]
|
||
|
[maximum (apply max values)]
|
||
|
[diff (- maximum minimum)])
|
||
|
diff))
|
||
|
|
||
|
part1
|
||
|
|
||
|
; PART 2
|
||
|
; uhoh. start over
|
||
|
|
||
|
(define (inc-hash ht key amount)
|
||
|
(hash-set! ht key (+ amount (hash-ref! ht key 0))))
|
||
|
|
||
|
(define (dec-hash ht key amount)
|
||
|
(hash-set! ht key (- (hash-ref! ht key 0) amount)))
|
||
|
|
||
|
(define (step2 ht)
|
||
|
(define pairs (filter (λ (p) (> (cdr p) 0)) (hash->list ht)))
|
||
|
(for-each (λ (pair-and-count)
|
||
|
(let* ([pair (car pair-and-count)]
|
||
|
[count (cdr pair-and-count)]
|
||
|
[ins (second (assoc pair rules))]
|
||
|
[new1 (string-append (substring pair 0 1) ins)]
|
||
|
[new2 (string-append ins (substring pair 1 2))])
|
||
|
(inc-hash ht new1 count)
|
||
|
(inc-hash ht new2 count)
|
||
|
(dec-hash ht pair count)))
|
||
|
pairs)
|
||
|
ht)
|
||
|
|
||
|
(define (pairs->element-counts ht)
|
||
|
(let* ([el-ht (make-hash)]
|
||
|
[pair-counts (hash->list ht)])
|
||
|
(for-each (λ (p) (let* ([pair (car p)]
|
||
|
[el1 (substring pair 0 1)]
|
||
|
[el2 (substring pair 1 2)]
|
||
|
[count (cdr p)])
|
||
|
(inc-hash el-ht el1 count)
|
||
|
(inc-hash el-ht el2 count)))
|
||
|
pair-counts)
|
||
|
el-ht))
|
||
|
|
||
|
(define part2
|
||
|
(let* ([ht (make-hash)]
|
||
|
[pairs (find-pairs template)]) ; find the initial pairs in the template
|
||
|
(for-each (λ (pair) (inc-hash ht pair 1)) pairs) ; add them to the hash table
|
||
|
(let* ([res (foldl (λ (el acc) (step2 acc)) ht (range 0 40))] ; step!
|
||
|
[el-counts (pairs->element-counts res)]
|
||
|
[first-char (substring template 0 1)]
|
||
|
[last-char (substring template (sub1 (string-length template)))])
|
||
|
(inc-hash el-counts first-char 1) ; add the first..
|
||
|
(inc-hash el-counts last-char 1) ; and last chars twice..
|
||
|
(let* ([lst (hash-map el-counts (λ (key val) (list key (/ val 2))))] ; then divide everything by 2
|
||
|
[values (map second lst)]
|
||
|
[minimum (apply min values)]
|
||
|
[maximum (apply max values)]
|
||
|
[diff (- maximum minimum)])
|
||
|
diff))))
|
||
|
|
||
|
part2
|