baf889db8d40

2019/07
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Sat, 07 Dec 2019 16:58:32 -0500
parents bf4373f04499
children 9ceb59a426ad
branches/tags (none)
files .lispwords advent.asd data/2019/07.txt package.lisp src/2019/days/day-07.lisp src/2019/intcode.lisp src/utils.lisp

Changes

--- a/.lispwords	Sat Dec 07 00:59:04 2019 -0500
+++ b/.lispwords	Sat Dec 07 16:58:32 2019 -0500
@@ -2,3 +2,4 @@
 (3 define-problem)
 (1 opcase)
 (1 finding-first)
+(1 rebind)
--- a/advent.asd	Sat Dec 07 00:59:04 2019 -0500
+++ b/advent.asd	Sat Dec 07 16:58:32 2019 -0500
@@ -31,6 +31,7 @@
                :pileup
                :split-sequence
                :str
+               :jpl-queues
 
                )
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/2019/07.txt	Sat Dec 07 16:58:32 2019 -0500
@@ -0,0 +1,1 @@
+3,8,1001,8,10,8,105,1,0,0,21,34,51,64,81,102,183,264,345,426,99999,3,9,102,2,9,9,1001,9,4,9,4,9,99,3,9,101,4,9,9,102,5,9,9,1001,9,2,9,4,9,99,3,9,101,3,9,9,1002,9,5,9,4,9,99,3,9,102,3,9,9,101,3,9,9,1002,9,4,9,4,9,99,3,9,1002,9,3,9,1001,9,5,9,1002,9,5,9,101,3,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,99,3,9,101,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,99,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,1,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,99
--- a/package.lisp	Sat Dec 07 00:59:04 2019 -0500
+++ b/package.lisp	Sat Dec 07 16:58:32 2019 -0500
@@ -36,6 +36,8 @@
     :first-character
     :let-result
     :let-complex
+    :queue-thunk
+    :rebind
 
     :ring
     :ring-prev
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/2019/days/day-07.lisp	Sat Dec 07 16:58:32 2019 -0500
@@ -0,0 +1,67 @@
+(defpackage :advent/2019/07 #.cl-user::*advent-use*
+  (:shadow :queue))
+(in-package :advent/2019/07)
+
+(defun queue (&key initial-contents)
+  (let-result (queue (make-instance 'jpl-queues:synchronized-queue
+                       :queue (make-instance 'jpl-queues:unbounded-fifo-queue)))
+    (dolist (el initial-contents)
+      (jpl-queues:enqueue el queue))))
+
+(defun make-amplifier (program input-queue output-queue)
+  (advent/intcode:init program
+                       :input (rcurry #'jpl-queues:dequeue input-queue)
+                       :output (rcurry #'jpl-queues:enqueue output-queue)))
+
+(defun make-amplifiers (program phases)
+  (iterate
+    (with top-queue = (queue :initial-contents (list (first phases) 0)))
+    (for (nil next-phase) :on phases)
+    (for output-queue = (if next-phase
+                          (queue :initial-contents (list next-phase))
+                          top-queue))
+    (for input-queue :previous output-queue :initially top-queue)
+    (collect (make-amplifier program input-queue output-queue) :into amps)
+    (returning amps top-queue)))
+
+(defun run-amplifiers (program phases)
+  (multiple-value-bind (amplifiers queue) (make-amplifiers program phases)
+    (-<> amplifiers
+      (mapcar (lambda (amp)
+                (bt:make-thread (curry #'advent/intcode:run-machine amp)
+                                :name "Amplifier Thread"))
+              <>)
+      (map nil #'bt:join-thread <>))
+    (jpl-queues:dequeue queue)))
+
+(defun maximum-permutation (function sequence)
+  (iterate (alexandria:map-permutations
+             (lambda (el)
+               (maximizing (funcall function el)))
+             sequence)
+           (finish)))
+
+(define-problem (2019 7) (data read-numbers) (46248 54163586)
+  (values
+    (maximum-permutation (curry #'run-amplifiers data) '(0 1 2 3 4))
+    (maximum-permutation (curry #'run-amplifiers data) '(5 6 7 8 9))))
+
+
+#; Scratch --------------------------------------------------------------------
+
+(run '(3 15 3 16 1002 16 10 16 1 16 15 15 4 15 99 0 0))
+
+(run '(3 23 3 24 1002 24 10 24 1002 23 -1 23 101 5 23 23 1 24 23 23 4 23 99 0 0))
+
+(run '(3 26 1001 26 -4 26 3 27 1002 27 2 27 1 27 26 27 4 27 1001 28 -1 28 1005 28 6 99 0 0 5))
+
+(run '(3 52 1001 52 -5 52 3 53 1 52 56 54 1007 54 5 55 1005 55 26 1001 54 -5 54
+       1105 1 12 1 53 54 53 1008 54 0 55 1001 55 1 55 2 53 55 53 4 53 1001 56
+       -1 56 1005 56 6 99 0 0 0 0 10))
+
+(defun kill-amplifiers ()
+  (-<> (bt:all-threads)
+    (remove "Amplifier Thread" <> :test-not #'string= :key #'bt:thread-name)
+    (map nil #'bt:destroy-thread <>)))
+
+(kill-amplifiers)
--- a/src/2019/intcode.lisp	Sat Dec 07 00:59:04 2019 -0500
+++ b/src/2019/intcode.lisp	Sat Dec 07 16:58:32 2019 -0500
@@ -1,27 +1,28 @@
 (defpackage :advent/intcode
   #.cl-user::*advent-use*
   (:shadow :step :trace)
-  (:export :init :step :run))
+  (:export :init :step :run :run-machine))
 
 (in-package :advent/intcode)
 
+(defparameter *trace-lock* (bt:make-lock "intcode trace lock"))
 
 ;;;; Data Structures ----------------------------------------------------------
 (defclass* machine ()
-  ((pc :type '(integer 0) :initform 0)
-   (memory :type 'vector)
-   (input :type 'function)
-   (output :type 'function)))
+  ((pc :type (integer 0) :initform 0)
+   (memory :type (vector integer))
+   (input :type function)
+   (output :type function)))
 
 (define-with-macro machine pc memory input output)
 
 
 (defclass* operation ()
   ((opcode :type (integer 0))
-   (name :type 'symbol)
-   (size :type '(integer 1))
-   (parameters :type 'list)
-   (perform :type 'function)))
+   (name :type symbol)
+   (size :type (integer 1))
+   (parameters :type list)
+   (perform :type function)))
 
 (defun perform-operation (opcode parameter-modes machine)
   (funcall (perform (gethash opcode *operations*))
@@ -54,24 +55,26 @@
       `(progn
          (defun ,function-name (,pmodes ,machine)
            (declare (ignorable ,pmodes))
-           (flet ((pop-mode ()
-                    (multiple-value-bind (,pms ,pm) (truncate ,pmodes 10)
-                      (setf ,pmodes ,pms)
-                      ,pm)))
-             (with-machine (,machine)
-               (let (,@(iterate
-                         (for (param kind) :in parameters)
-                         (for offset :from 0)
-                         (collect
-                           (ecase kind
-                             (in `(,param (retrieve ,machine
-                                                    (pop-mode)
-                                                    (aref memory (+ pc ,offset)))))
-                             (out `(,param (progn
-                                             (pop-mode)
-                                             (aref memory (+ pc ,offset)))))))))
-                 (incf pc ,(length parameters))
-                 ,@body))))
+           (,@(if parameters
+                `(flet ((pop-mode ()
+                          (multiple-value-bind (,pms ,pm) (truncate ,pmodes 10)
+                            (setf ,pmodes ,pms)
+                            ,pm))))
+                `(progn))
+            (with-machine (,machine)
+              (let (,@(iterate
+                        (for (param kind) :in parameters)
+                        (for offset :from 0)
+                        (collect
+                          (ecase kind
+                            (in `(,param (retrieve ,machine
+                                                   (pop-mode)
+                                                   (aref memory (+ pc ,offset)))))
+                            (out `(,param (progn
+                                            (pop-mode)
+                                            (aref memory (+ pc ,offset)))))))))
+                (incf pc ,(length parameters))
+                ,@body))))
          (setf (gethash ,opcode *operations*)
                (make-instance 'operation
                  :opcode ,opcode
@@ -172,17 +175,21 @@
 (defun step (machine &key trace)
   (with-machine (machine)
     (when trace
-      (disassemble-program (memory machine) :start pc :limit 1))
+      (bt:with-lock-held (*trace-lock*)
+        (when (numberp trace)
+          (format t "~D: " trace))
+        (disassemble-program (memory machine) :start pc :limit 1)))
     (multiple-value-bind (opcode parameter-modes) (parse-op (aref memory pc))
       (incf pc)
       (perform-operation opcode parameter-modes machine))))
 
-(defun run (program &key input output trace)
+(defun run-machine (machine &key trace)
   (iterate
-    (with machine = (init program :input input :output output))
     (case (step machine :trace trace)
       (:halt (return (aref (memory machine) 0))))))
 
+(defun run (program &key input output trace)
+  (run-machine (init program :input input :output output) :trace trace))
 
 ;; #; Scratch --------------------------------------------------------------------
 
--- a/src/utils.lisp	Sat Dec 07 00:59:04 2019 -0500
+++ b/src/utils.lisp	Sat Dec 07 16:58:32 2019 -0500
@@ -474,6 +474,17 @@
      ,@body))
 
 
+(defun queue-thunk (&rest elements)
+  (lambda () (pop elements)))
+
+
+(defmacro rebind ((&rest vars) &body body)
+  `(let (,@(iterate
+             (for var :in vars)
+             (collect `(,var ,var))))
+     ,@body))
+
+
 ;;;; A* Search ----------------------------------------------------------------
 (defstruct path
   state