src/2017/days/day-18.lisp @ e41337e3b59b

Accessors
author Steve Losh <steve@stevelosh.com>
date Wed, 15 Dec 2021 23:10:57 -0500
parents 182bdd87fd9e
children (none)
(advent:defpackage* :advent/2017/18)
(in-package :advent/2017/18)

(defclass* machine ()
  ((id :type integer)
   (program :type vector)
   (pc :initform 0)
   (registers :initform (make-hash-table))
   (queue :initform (make-queue))
   (blocked :initform nil)))

(defun reg (machine register)
  (gethash register (registers machine) 0))

(defun (setf reg) (new-value machine register)
  (setf (gethash register (registers machine) 0)
        new-value))

(defun val (machine register-or-constant)
  (etypecase register-or-constant
    (symbol (reg machine register-or-constant))
    (number register-or-constant)))

(defmacro opcase (op &body clauses)
  (once-only (op)
    `(case (first ,op)
       ,@(iterate
          (for ((opcode . args) . body) :in clauses)
          (collect `(,opcode (destructuring-bind ,args (rest ,op)
                               ,@body)))))))

(defun handle-common-ops (machine op)
  (macrolet ((r (x) `(reg machine ,x))
             (v (x) `(val machine ,x)))
    (opcase op
      ((set x y) (setf (r x) (v y)))
      ((add x y) (setf (r x) (+ (v x) (v y))))
      ((mul x y) (setf (r x) (* (v x) (v y))))
      ((mod x y) (setf (r x) (mod (v x) (v y))))
      ((jgz x y) (when (plusp (v x))
                   (incf (pc machine)
                         (1- (v y))))))))

(defun part1 (program)
  (iterate
    (with machine = (make-instance 'machine :program program))
    (with hz = nil)
    (with bound = (length program))
    (while (in-range-p 0 (pc machine) bound))
    (for op = (aref (program machine) (pc machine)))
    (incf (pc machine))
    (handle-common-ops machine op)
    (opcase op
      ((snd x) (setf hz (val machine x)))
      ((rcv x) (unless (zerop (val machine x))
                 (return hz))))))

(defun part2 (program)
  (iterate
    (with a = (make-instance 'machine :program program :id 0))
    (with b = (make-instance 'machine :program program :id 1))
    (with bound = (length program))
    (initially (setf (reg a 'p) 0
                     (reg b 'p) 1))
    (while (in-range-p 0 (pc a) bound))
    (for op = (aref (program a) (pc a)))
    (incf (pc a))
    (handle-common-ops a op)
    (opcase op
      ((snd x) (progn
                 (counting (= 1 (id a)))
                 (enqueue (val a x) (queue b))))
      ((rcv x) (cond ((not (queue-empty-p (queue a)))
                      (setf (reg a x) (dequeue (queue a))
                            (blocked b) nil))
                     ((blocked b) (pr 'deadlock) (finish))
                     (t (progn (decf (pc a))
                               (setf (blocked a) t)
                               (rotatef a b))))))))

;; TODO finish this
;; (define-problem (2017 18) (data read-lines) (1187 5969)
;;   (setf data (map 'vector #'read-all-from-string data))
;;   (values (part1 data)
;;           (part2 data)))


#; Scratch --------------------------------------------------------------------

(run '("set a 1"
       "add a 2"
       "mul a a"
       "mod a 5"
       "snd a"
       "set a 0"
       "rcv a"
       "jgz a -1"
       "set a 1"
       "jgz a -2"))

(run '("snd 1"
       "snd 2"
       "snd p"
       "rcv a"
       "rcv b"
       "rcv c"
       "rcv d"))