about summary refs log tree commit diff
path: root/day16.rkt
blob: 5d96756f3e9370cb296785ea4f01f11085a6f438 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#lang racket

;; https://www.reddit.com/r/adventofcode/comments/zn6k1l/2022_day_16_solutions/j0g5nlk/

(define flow-rates (make-hash))
(define tunnels (make-hash))

(for ([line (file->lines "day16")])
  (let* ([valves (regexp-match* #rx"[A-Z][A-Z]" line)]
         [valve (first valves)]
         [flow-rate (string->number (first (regexp-match #rx"[0-9]+" line)))])
    (hash-set! flow-rates valve flow-rate)
    (hash-set! tunnels valve (rest valves))))

(define key-rooms (for/set ([(room flow-rate) flow-rates]
                            #:when (or (equal? room "AA") (positive? flow-rate)))
                    room))

(set-count key-rooms)

(define distance (make-hash))
(for ([start-room (hash-keys tunnels)])
  (let ([cur (mutable-set start-room)]
        [next (mutable-set)]
        [dist 0])
    (hash-set! distance (list start-room start-room) 0)
    (let loop ()
      (set! dist (+ 1 dist))
      (for ([pos cur])
        (for ([newpos (hash-ref tunnels pos)])
          (unless (hash-has-key? distance (list start-room newpos))
            (hash-set! distance (list start-room newpos) dist)
            (set-add! next newpos))))
      (set! cur next)
      (set! next (mutable-set))
      (unless (set-empty? cur)
        (loop)))))

;distance

(define (part1 cur time seen targets)
  (let* ([seen (set-add seen cur)]
         [targets (set-subtract targets seen)])
    (for/fold ([best-flow 0])
              ([target targets])
      (let ([time-left (- time (hash-ref distance (list cur target)) 1)])
        (if (positive? time-left)
          (let ([flow (+ (* (hash-ref flow-rates target) time-left)
                         (part1 target time-left seen targets))])
            (max best-flow flow))
          best-flow)))))

(part1 "AA" 30 (set) key-rooms)
;; 1720


(define endpoints (make-hash))

(define (find-and-record cur curflow time seen)
  (let* ([seen (set-add seen cur)]
         [targets (set-subtract key-rooms seen)]
         [torecord (set-remove seen "AA")])
    (hash-update! endpoints torecord (lambda (v) (max v curflow)) 0)
    (for/fold ([best-flow 0])
              ([target targets])
      (let ([time-left (- time (hash-ref distance (list cur target)) 1)])
        (if (positive? time-left)
          (let* ([flow (* (hash-ref flow-rates target) time-left)]
                 [flow (+ flow (find-and-record
                                target
                                (+ curflow flow) time-left seen))])
            (max best-flow flow))
          best-flow)))))

(void (find-and-record "AA" 0 26 (set)))

(define (fill-in-endpoints cur)
  (unless (hash-has-key? endpoints cur)
    (hash-set! endpoints cur (for/fold ([best-flow 0])
                                       ([e cur])
                               (max best-flow (fill-in-endpoints
                                               (set-remove cur e))))))
  (hash-ref endpoints cur))

(void (fill-in-endpoints (set-remove key-rooms "AA")))

(for/fold ([best-flow 0])
          ([human (hash-keys endpoints)])
  (let ([elephant (set-subtract key-rooms (set "AA") human)])
    (max best-flow (+ (hash-ref endpoints human)
                      (hash-ref endpoints elephant)))))
;; 2582