(asdf:load-system :adventofcode2020) (in-package #:adventofcode2020) (named-readtables:in-readtable fn-reader) (defun make-program (insts) (let ((len (length insts)) (parse-inst (lambda (inst) (cl-ppcre:register-groups-bind (code (#'parse-integer imm)) ("([a-z]{3}) ([-+][0-9]+)" inst) (list code imm))))) (list :ptr 0 :acc 0 :mem (make-array len :initial-contents (mapcar parse-inst insts)) :vis (make-array len :element-type 'bit)))) (defun step-program (program) (let ((ptr (getf program :ptr)) (mem (getf program :mem)) (acc (getf program :acc))) (if (= ptr (length mem)) (setf (getf program :stop) 1) (if (= 1 (bit (getf program :vis) ptr)) (setf (getf program :stop) 2) (destructuring-bind (code imm) (aref mem ptr) (cond ((string= code "nop") (setf (getf program :ptr) (1+ ptr))) ((string= code "acc") (progn (setf (getf program :ptr) (1+ ptr)) (setf (getf program :acc) (+ acc imm)))) ((string= code "jmp") (setf (getf program :ptr) (+ ptr imm)))) (setf (bit (getf program :vis) ptr) 1)))) program)) (defun run-until-stop (program) (if (getf program :stop) (values (getf program :acc) (getf program :stop)) (run-until-stop (step-program program)))) (defun run-with-fix (program i) (let ((fixing (aref (getf program :mem) i)) (fix-code (lambda (inst) (destructuring-bind (code imm) inst (cond ((string= code "nop") (list "jmp" imm)) ((string= code "jmp") (list "nop" imm))))))) (setf (aref (getf program :mem) i) (funcall fix-code fixing)) (multiple-value-bind (acc stop) (run-until-stop program) (setf (aref (getf program :mem) i) fixing) (setf (getf program :stop) nil) (setf (getf program :ptr) 0) (setf (getf program :acc) 0) (setf (getf program :vis) (make-array (length (getf program :mem)) :element-type 'bit)) (if (= stop 1) acc most-negative-fixnum)))) (defun find-fixed-result (program) (loop for i from 0 below (length (getf program :mem)) unless (string= "acc" (first (aref (getf program :mem) i))) maximizing (run-with-fix program i))) (day 08 input (let ((program (make-program (list-from input)))) (part1 (run-until-stop program)) (part2 (find-fixed-result program)))) (def-suite day08) (in-suite day08) (defvar *simple-instructions* '("nop +0" "acc +1" "jmp +4" "acc +3" "jmp -3" "acc -99" "acc +1" "jmp -4" "acc +6")) (test run-until-stop (is (equal 5 (run-until-stop (make-program *simple-instructions*))))) (test run-with-fix (is (equal 8 (run-with-fix (make-program *simple-instructions*) 7)))) (test find-fixed-result (is (equal 8 (find-fixed-result (make-program *simple-instructions*))))) (run! 'day08)