20 files changed, 134 insertions(+), 116 deletions(-)
M .gitignore
A advent.asd
D day2-input.txt
D day2.lisp
D day5-input.txt
D day5-input2.txt
D day7.lisp
R day1.lisp => days/day1.lisp
R day3.lisp => days/day3.lisp
R day4.lisp => days/day4.lisp
R day6.lisp => days/day6.lisp
A days/day7.lisp
R day1-input.txt => inputs/day1-input.txt
R day3-input.txt => inputs/day3-input.txt
R day3-input2.txt => inputs/day3-input2.txt
R day6-input.txt => inputs/day6-input.txt
R day7-input.txt => inputs/day7-input.txt
A inputs/day7-input2.txt
M intcode.lisp
A package.lisp
M .gitignore => .gitignore +1 -1
@@ 1,2 1,2 @@
*.fasl
-/day7-output.txt
+/scratch.lisp
A advent.asd => advent.asd +15 -0
@@ 0,0 1,15 @@
+
+(asdf:defsystem :advent
+ :description "Advent of Code"
+ :author "Theodor Thornhill <theothornhill@pm.me>"
+ :license "MIT"
+ :version "0.0.1"
+ :depends-on (:cl-ppcre :bordeaux-threads)
+ :components ((:file "package")
+ (:file "intcode")
+ (:module "days"
+ :components ((:file "day1")
+ (:file "day3")
+ (:file "day4")
+ (:file "day6")
+ (:file "day7")))))
D day2-input.txt => day2-input.txt +0 -1
@@ 1,1 0,0 @@
-1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,10,1,19,1,5,19,23,1,23,5,27,2,27,10,31,1,5,31,35,2,35,6,39,1,6,39,43,2,13,43,47,2,9,47,51,1,6,51,55,1,55,9,59,2,6,59,63,1,5,63,67,2,67,13,71,1,9,71,75,1,75,9,79,2,79,10,83,1,6,83,87,1,5,87,91,1,6,91,95,1,95,13,99,1,10,99,103,2,6,103,107,1,107,5,111,1,111,13,115,1,115,13,119,1,13,119,123,2,123,13,127,1,127,6,131,1,131,9,135,1,5,135,139,2,139,6,143,2,6,143,147,1,5,147,151,1,151,2,155,1,9,155,0,99,2,14,0,0
D day2.lisp => day2.lisp +0 -17
@@ 1,17 0,0 @@
-;; Day 2:
-
-(in-package :intcode)
-
-(defun run (filename noun verb)
- (with-intcode (memory)
- (init-intcode filename)
- (setf (aref memory 1) noun)
- (setf (aref memory 2) verb)
- (run-intcode)))
-
-(defun find-result (filename target)
- (with-intcode (memory memory-size)
- (loop named r for noun below 100 do
- (loop for verb below 100 do
- (if (= (run filename noun verb) target)
- (return-from r (+ (* 100 noun) verb)))))))
D day5-input.txt => day5-input.txt +0 -1
@@ 1,1 0,0 @@
-3,225,1,225,6,6,1100,1,238,225,104,0,1002,43,69,224,101,-483,224,224,4,224,1002,223,8,223,1001,224,5,224,1,224,223,223,1101,67,60,225,1102,5,59,225,1101,7,16,225,1102,49,72,225,101,93,39,224,101,-98,224,224,4,224,102,8,223,223,1001,224,6,224,1,224,223,223,1102,35,82,225,2,166,36,224,101,-4260,224,224,4,224,102,8,223,223,101,5,224,224,1,223,224,223,102,66,48,224,1001,224,-4752,224,4,224,102,8,223,223,1001,224,2,224,1,223,224,223,1001,73,20,224,1001,224,-55,224,4,224,102,8,223,223,101,7,224,224,1,223,224,223,1102,18,41,224,1001,224,-738,224,4,224,102,8,223,223,101,6,224,224,1,224,223,223,1101,68,71,225,1102,5,66,225,1101,27,5,225,1101,54,63,224,1001,224,-117,224,4,224,102,8,223,223,1001,224,2,224,1,223,224,223,1,170,174,224,101,-71,224,224,4,224,1002,223,8,223,1001,224,4,224,1,223,224,223,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,1007,226,226,224,1002,223,2,223,1006,224,329,1001,223,1,223,1007,226,677,224,102,2,223,223,1006,224,344,1001,223,1,223,108,677,677,224,102,2,223,223,1005,224,359,1001,223,1,223,1007,677,677,224,1002,223,2,223,1006,224,374,101,1,223,223,8,677,226,224,1002,223,2,223,1006,224,389,101,1,223,223,7,226,226,224,1002,223,2,223,1005,224,404,101,1,223,223,7,677,226,224,102,2,223,223,1005,224,419,1001,223,1,223,8,226,677,224,1002,223,2,223,1005,224,434,101,1,223,223,1008,226,677,224,102,2,223,223,1006,224,449,1001,223,1,223,7,226,677,224,1002,223,2,223,1006,224,464,1001,223,1,223,108,677,226,224,102,2,223,223,1005,224,479,101,1,223,223,108,226,226,224,1002,223,2,223,1006,224,494,101,1,223,223,8,226,226,224,1002,223,2,223,1005,224,509,1001,223,1,223,1107,677,226,224,102,2,223,223,1005,224,524,1001,223,1,223,1107,226,226,224,102,2,223,223,1005,224,539,1001,223,1,223,1108,677,677,224,1002,223,2,223,1006,224,554,101,1,223,223,107,226,677,224,102,2,223,223,1005,224,569,1001,223,1,223,1108,226,677,224,1002,223,2,223,1005,224,584,1001,223,1,223,1107,226,677,224,1002,223,2,223,1005,224,599,1001,223,1,223,1008,226,226,224,1002,223,2,223,1005,224,614,101,1,223,223,107,226,226,224,102,2,223,223,1006,224,629,1001,223,1,223,1008,677,677,224,1002,223,2,223,1006,224,644,101,1,223,223,107,677,677,224,1002,223,2,223,1005,224,659,101,1,223,223,1108,677,226,224,1002,223,2,223,1006,224,674,1001,223,1,223,4,223,99,226
D day5-input2.txt => day5-input2.txt +0 -1
@@ 1,1 0,0 @@
-3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31, 1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104, 999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99
D day7.lisp => day7.lisp +0 -56
@@ 1,56 0,0 @@
-
-(in-package :intcode)
-
-(defparameter *a* (make-instance 'intcode))
-(defparameter *b* (make-instance 'intcode))
-(defparameter *c* (make-instance 'intcode))
-(defparameter *d* (make-instance 'intcode))
-(defparameter *e* (make-instance 'intcode))
-
-(defun run-day7-part-one (a b c d e &rest args)
- (let ((computers (list a b c d e)))
- (map nil (lambda (computer arg)
- (init-intcode "./day7-input.txt" computer arg))
- computers args)
- (run-with-input a a 0)
- (run-with-input b a)
- (run-with-input c b)
- (run-with-input d c)
- (run-with-input e d)))
-
-
-(defun all-permutations (list)
- (cond ((null list) nil)
- ((null (cdr list)) (list list))
- (t (loop for element in list
- append (mapcar (lambda (l) (cons element l))
- (all-permutations (remove element list)))))))
-
-(defun run-with-input (a b &optional (hardcode nil))
- (let ((result 0))
- (with-intcode a
- (with-instruction-pointer
- (let ((action (next-instruction)))
- (funcall action (setting a)) ;; do first read instruction
- (do ((action (next-instruction) (next-instruction)))
- ((eql action 'halt)
- (setf result (get-mem 0 (1- instruction-pointer))))
- (cond ((eql action 'input)
- (cond ((out-buffer b)
- (input (pop (out-buffer b))))
- (hardcode
- (input hardcode)
- (setf hardcode nil))
- (t
- (return))))
- ((eql action 'output)
- (output nil))
- (t (funcall action)))))))))
-
-(defun day7-part-one ()
- (let (result)
- (mapcar (lambda (x) (push (apply #'run-day7-part-one
- *a* *b* *c* *d* *e* x)
- result))
- (all-permutations '(0 1 2 3 4)))
- (car (sort result #'>))))
R day1.lisp => days/day1.lisp +1 -1
@@ 18,4 18,4 @@
(let ((fuels (read-fuel-file filename)))
(reduce #'+ (mapcar #'add-fuels fuels))))
-(fuel-required "./day1-input.txt")
+(fuel-required "./inputs/day1-input.txt")
R day3.lisp => days/day3.lisp +1 -1
@@ 102,5 102,5 @@ Then record number of steps to hit"
(mapcar (lambda (x) (+ (abs (car x)) (abs (cadr x)))) result)))
(defun day3 ()
- (values (car (run-paths "./day3-input.txt"))
+ (values (car (run-paths "./inputs/day3-input.txt"))
(car (sort (get-intersections) #'<))))
R day4.lisp => days/day4.lisp +0 -0
R day6.lisp => days/day6.lisp +1 -1
@@ 65,6 65,6 @@
(gethash 'san *objects*) -1))))
(defun day6 ()
- (set-all-objects "./day6-input.txt")
+ (set-all-objects "./inputs/day6-input.txt")
(values (part-one)
(part-two)))
A days/day7.lisp => days/day7.lisp +56 -0
@@ 0,0 1,56 @@
+
+(in-package :intcode)
+
+(defparameter *a* (make-instance 'intcode))
+(defparameter *b* (make-instance 'intcode))
+(defparameter *c* (make-instance 'intcode))
+(defparameter *d* (make-instance 'intcode))
+(defparameter *e* (make-instance 'intcode))
+
+(defparameter *computers* (list *a* *b* *c* *d* *e*))
+
+(defun run-threaded (a b)
+ (bt:make-thread (lambda ()
+ (run-with-input a b))
+ :name (format nil "~a" a)))
+
+(defun add-settings (args)
+ ;; Set the first args on *e* since it feeds *a* anyways. Ugly...
+ (setf (out *e*) (list 0 (first args)))
+ (setf (out *a*) (list (second args)))
+ (setf (out *b*) (list (third args)))
+ (setf (out *c*) (list (fourth args)))
+ (setf (out *d*) (list (fifth args))))
+
+(defun run-day7 (&rest args)
+ (map nil (lambda (computer)
+ (init-intcode "./inputs/day7-input.txt" computer))
+ *computers*)
+ (add-settings args)
+ (let ((threads
+ (list (run-threaded *a* *e*)
+ (run-threaded *b* *a*)
+ (run-threaded *c* *b*)
+ (run-threaded *d* *c*)
+ (run-threaded *e* *d*))))
+ (mapcar #'bt:join-thread threads)
+ (car (out *e*))))
+
+(defun all-permutations (list)
+ ;; Stolen from Rainer Joswig stackoverflow
+ (cond ((null list) nil)
+ ((null (cdr list)) (list list))
+ (t (loop for element in list
+ append (mapcar (lambda (l) (cons element l))
+ (all-permutations (remove element list)))))))
+
+(defun run-with-permutations (&rest args)
+ (let (result)
+ (mapcar (lambda (x) (push (apply #'run-day7 x) result))
+ (all-permutations args))
+ (car (sort result #'>))))
+
+(defun day7 ()
+ (format t "Running day 7... ")
+ (values (run-with-permutations 0 1 2 3 4)
+ (run-with-permutations 5 6 7 8 9)))
R day1-input.txt => inputs/day1-input.txt +0 -0
R day3-input.txt => inputs/day3-input.txt +0 -0
R day3-input2.txt => inputs/day3-input2.txt +0 -0
R day6-input.txt => inputs/day6-input.txt +0 -0
R day7-input.txt => inputs/day7-input.txt +0 -1
@@ 1,2 1,1 @@
3,8,1001,8,10,8,105,1,0,0,21,46,67,76,101,118,199,280,361,442,99999,3,9,1002,9,4,9,1001,9,2,9,102,3,9,9,101,3,9,9,102,2,9,9,4,9,99,3,9,1001,9,3,9,102,2,9,9,1001,9,2,9,1002,9,3,9,4,9,99,3,9,101,3,9,9,4,9,99,3,9,1001,9,2,9,1002,9,5,9,101,5,9,9,1002,9,4,9,101,5,9,9,4,9,99,3,9,102,2,9,9,1001,9,5,9,102,2,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,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,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,99,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,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,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,99,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,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,1,9,4,9,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,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,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,2,9,4,9,99,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,99
-
A inputs/day7-input2.txt => inputs/day7-input2.txt +1 -0
@@ 0,0 1,1 @@
+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
M intcode.lisp => intcode.lisp +52 -35
@@ 1,11 1,5 @@
;;; IntCode computer
-(ql:quickload :cl-ppcre)
-(defpackage :intcode
- (:use :cl)
- (:import-from :cl-ppcre
- :split))
-
(in-package :intcode)
(defmacro with-gensyms (syms &body body)
@@ 16,13 10,14 @@
((memory
:initarg :memory
:accessor memory)
- (setting
- :initarg :setting
- :accessor setting)
- (out-buffer
- :initarg :out-buffer
- :initform (list)
- :accessor out-buffer)
+ (in
+ :initarg :in
+ :initform nil
+ :accessor in)
+ (out
+ :initarg :out
+ :initform nil
+ :accessor out)
(instruction-pointer
:initarg :instruction-pointer
:initform 0
@@ 39,10 34,11 @@
(defun parse-instruction (instruction)
(let ((i (format nil "~5,'0d" instruction)))
- ;; KLUDGE: This thing does too many things.
- ;; Handle case for halt value better, and maybe split the mv-bind?
+ ;; Force instruction format to be of length 5.
+ ;; In example, instruction 99 will be 00099, so we get the modes in
+ ;; front. We can map these to a list so we can get them later.
(values (if (string= (subseq i 3) "99")
- 99
+ 99 ;; If the last two digits are 99, return the integer
(parse-integer (subseq i 4)))
(reverse (mapcar #'parse-integer
(split "" (subseq i 0 3)))))))
@@ 58,6 54,9 @@
(defmacro with-modes (&body body)
"Anaphoric MODES variables"
`(let* ((modes (nth-value
+ ;; Use nth-value since we don't care about the first value
+ ;; here. We want the modes, not the instruction
+ ;; see `parse-instruction'
1 (parse-instruction
(get-mem 1 (instruction-pointer *intcode*)))))
(first-param-mode (car modes))
@@ 145,16 144,12 @@
(defun input (&optional in)
(with-io
- ;; (setf (set-mem x) (if in in (parse-integer (read-line))))
- (setf (set-mem x) in)
- ))
+ (setf (set-mem x) in)))
(defun output (&optional (stream t))
(with-io
- (with-internals (out-buffer)
- (if (out-buffer *intcode*)
- (push (get-mem 0 x) (cdr (last (out-buffer *intcode*))))
- (push (get-mem 0 x) (out-buffer *intcode*)))
+ (with-internals (out)
+ (push (get-mem 0 x) (out *intcode*))
(format stream "~a" (get-mem 0 x)))))
(defun jump-if-true ()
@@ 179,25 174,47 @@
(defun halt () :halt)
-(defun init-intcode (filename intcode &optional (start nil))
+(defun init-intcode (filename intcode)
(with-intcode intcode
(let* ((op-codes (read-op-codes filename))
(mem-size (length op-codes)))
- (with-internals (memory halted setting out-buffer instruction-pointer)
+ (with-internals (memory in out instruction-pointer)
(setf instruction-pointer 0)
- (setf setting start)
- (setf out-buffer nil)
+ (setf in nil)
+ (setf out nil)
(setf memory (make-array mem-size :initial-contents op-codes))
:initialized))))
-(defun run (intcode)
- "RUN dynamically binds an instance of INTCODE. "
- (with-intcode intcode
- (with-internals (memory instruction-pointer)
- (do* ((action (next-instruction) (next-instruction)))
- ((eql action 'halt) (aref memory 0))
+;; (defun run (intcode)
+;; "RUN dynamically binds an instance of INTCODE. "
+;; (with-intcode intcode
+;; (with-internals (memory instruction-pointer)
+;; (do* ((action (next-instruction) (next-instruction)))
+;; ((eql action 'halt) (aref memory 0))
+;; (cond ((eql action 'input)
+;; (funcall action))
+;; ((eql action 'output)
+;; (funcall action nil))
+;; (t (funcall action)))))))
+
+(defun run-with-input (a b)
+ ;; We don't return anything here yet. We can always get the value from
+ ;; the correct computer. I'm guessing this is subject to change later
+ ;; anyways.
+ (with-intcode a
+ (with-instruction-pointer
+ (do ((action (next-instruction) (next-instruction)))
+ ((eql action 'halt))
(cond ((eql action 'input)
- (funcall action))
+ ;; KLUDGE: This thing is super ugly with its spinlock waiting...
+ (loop
+ when (out b)
+ do (let ((in (car (last (out b)))))
+ ;; Remove last element and use it for input.
+ ;; Noob implicit FIFO queue
+ (setf (out b) (butlast (out b)))
+ (input in)
+ (return))))
((eql action 'output)
- (funcall action nil))
+ (output nil))
(t (funcall action)))))))
A package.lisp => package.lisp +6 -0
@@ 0,0 1,6 @@
+
+(defpackage :intcode
+ (:use :cl)
+ (:local-nicknames (:bordeaux-threads :bt))
+ (:import-from :cl-ppcre
+ :split))