Skip to content

Latest commit

 

History

History
219 lines (209 loc) · 8.13 KB

2022.16.org

File metadata and controls

219 lines (209 loc) · 8.13 KB

Day 16

Executing this code

If you have a lisp installation, emacs, org-mode, and org-babel support for lisp installed you can run this by:

  1. Starting slime (M-x slime)
  2. Typing C-c C-c in the block initialize.
  3. In the repl type (in-package :aoc-2022-16)
  4. Typing C-c C-c in the block answers

Initial stuffs

Packages to load

(unless (find-package :priority-queue)
  (ql:quickload "priority-queue"))
(unless (find-package :cl-ppcre)
  (ql:quickload "cl-ppcre"))
(unless (find-package :parseq)
  (ql:quickload "parseq"))
(unless (find-package :lparallel)
  (ql:quickload "lparallel"))
(unless (find-package :fiveam)
  (ql:quickload "fiveam"))
(unless (find-package :series)
  (ql:quickload "series"))
(unless (find-package :cl-permutation)
  (ql:quickload "cl-permutation"))
(unless (find-package :bordeaux-threads)
  (ql:quickload "bordeaux-threads"))

Create package for this day

<<packages>>
(defpackage :aoc-2022-16
  (:use :common-lisp
        :priority-queue
        :parseq
        :fiveam)
  (:export :problem-a
           :problem-b))
(in-package :aoc-2022-16)

Input

"Valve NA has flow rate=0; tunnels lead to valves MU, PH"
(defun parse-line (line)
  (cl-ppcre:register-groups-bind
      (valve (#'parse-integer rate) valves)
      ("Valve ([A-Z]+) has flow rate=(\\d+); tunnels? leads? to valves? (.+)" line)
    (let ((valves (cl-ppcre:all-matches-as-strings "[A-Z][A-Z]" valves)))
      (list valve rate valves))))

(defun process-stream (in)
  (loop for line = (read-line in nil)
        while line
        collect (parse-line line)))
(defun read-input (file)
  (with-open-file (in file)
    (process-stream in)))
(defparameter *input*
  (read-input "input/16.txt"))

Part 1

  (defun increase (open bit-map rates)
    (loop for valve being the hash-keys of bit-map using (hash-value bit)
          if (plusp (logand open bit))
            sum (gethash valve rates)))

  (defun maximize-pressure (paths rates bit-map &optional (initial-time 30) (initial-open 0))
    (loop with fringe = (make-pqueue #'>)
          with table = (make-hash-table :test #'equalp)
            initially (pqueue-push (list "AA" initial-time 0 initial-open) 0 fringe)
          for (position time pressure open) = (pqueue-pop fringe)
          for state = (list position time open)
          for rate = (gethash position rates)
          for increase = (* (1- time) rate)
          for next-pressure = (+ pressure increase)
          when (zerop time)
            maximizing pressure
          if (and (< (gethash state table -1) pressure) (plusp time))
            do (setf (gethash state table) pressure)
               (loop for destination in (gethash position paths)
                     for next = (list destination (1- time) pressure open)
                     for next-rate = (gethash destination rates)
                     for estimate = (* (- time 2) next-rate)
                     do (pqueue-push
                         next
                         (+ estimate pressure)
                         fringe))
               (if (and (zerop (logand (gethash position bit-map) open))
                        (plusp rate))
                   (pqueue-push (list position (1- time) next-pressure (logior open (gethash position bit-map)))
                              next-pressure
                              fringe))
          until (pqueue-empty-p fringe)))
2
  (defun valves-to-paths (data)
    (loop with paths = (make-hash-table :test 'equalp)
          with rates = (make-hash-table :test 'equalp)
          with bit-map = (make-hash-table :test 'equalp)
          for i from 0
          for (valve rate valves) in data
          do (setf (gethash valve rates) rate)
             (setf (gethash valve paths) valves)
             (setf (gethash valve bit-map) (expt 2 i))
          finally (return (list paths rates bit-map))))

  (defun solve-a (data &optional (initial-time 30) (initial-open 0))
    (destructuring-bind (paths rates bit-map) (valves-to-paths data)
      (maximize-pressure paths rates bit-map initial-time initial-open)))

  (defun problem-a () (format t "Problem 16 A: ~a~%" (solve-a *input*)))

Part 2

(defun all-pressure (paths rates bit-map &optional (initial-time 30) (initial-open 0))
  (loop with fringe = (make-pqueue #'>)
        with table = (make-hash-table :test #'equalp)
          initially (pqueue-push (list "AA" initial-time 0 initial-open) 0 fringe)
        for (position time pressure open) = (pqueue-pop fringe)
        for state = (list position time open)
        for rate = (gethash position rates)
        for increase = (* (1- time) rate)
        for next-pressure = (+ pressure increase)
        with result = (make-hash-table)
        finally (return result)
        when (zerop time)
          do (setf (gethash open result) (max (gethash open result 0) pressure))
        if (and (< (gethash state table -1) pressure) (plusp time))
          do (setf (gethash state table) pressure)
             (loop for destination in (gethash position paths)
                   for next = (list destination (1- time) pressure open)
                   for next-rate = (gethash destination rates)
                   for estimate = (* (- time 2) next-rate)
                   do (pqueue-push
                       next
                       (+ estimate pressure)
                       fringe))
             (if (and (zerop (logand (gethash position bit-map) open))
                      (plusp rate))
                 (pqueue-push (list position (1- time) next-pressure (logior open (gethash position bit-map)))
                            next-pressure
                            fringe))
        until (pqueue-empty-p fringe)))

(defun solve-b (data)
  (destructuring-bind (paths rates bit-map) (valves-to-paths data)
    (let ((pairs (all-pressure paths rates bit-map 26)))
      (loop for o1 being the hash-key of pairs using (hash-value p1)
            maximizing (loop for o2 being the hash-key of pairs using (hash-value p2)
                             if (zerop (logand o1 o2))
                               maximizing (+ p1 p2))))))

(defun problem-b () (format t "Problem 16 B: ~a~%" (solve-b *input*)))

Putting it all together

<<read-input>>
<<input>>
<<initialize>>
<<structs>>
<<functions>>
<<input>>
<<problem-a>>
<<problem-b>>
(problem-a)
(problem-b)

Answer

Problem 16 A: 2183
Problem 16 B: 2911

Test Cases

(def-suite aoc.2022.16)
(in-suite aoc.2022.16)

(defparameter *sample-input*
  "Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
Valve BB has flow rate=13; tunnels lead to valves CC, AA
Valve CC has flow rate=2; tunnels lead to valves DD, BB
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
Valve EE has flow rate=3; tunnels lead to valves FF, DD
Valve FF has flow rate=0; tunnels lead to valves EE, GG
Valve GG has flow rate=0; tunnels lead to valves FF, HH
Valve HH has flow rate=22; tunnel leads to valve GG
Valve II has flow rate=0; tunnels lead to valves AA, JJ
Valve JJ has flow rate=21; tunnel leads to valve II")

(defparameter *sample*
  (with-input-from-string (in *sample-input*)
    (process-stream in)))

(run! 'aoc.2022.16)

Test Results

Running test suite AOC.2022.16
 Didn't run anything...huh?

Thoughts