~theothornhill/advent

27221a0f1750ae1695f3bc928fa71ee146b15ea1 — Theodor Thornhill 4 years ago 208fb80
Big refactor
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))