aboutsummaryrefslogtreecommitdiff
path: root/2024/17/machine.lisp
blob: 31ae24fa460ebdb3f8b06558c0b79b418f5feebc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
(defpackage #:machine
  (:use :cl)
  (:export :run))

(in-package #:machine)

;;; Interpreter

(defconstant +op-adv+ 0)
(defconstant +op-bxl+ 1)
(defconstant +op-bst+ 2)
(defconstant +op-jnz+ 3)
(defconstant +op-bxc+ 4)
(defconstant +op-out+ 5)
(defconstant +op-bdv+ 6)
(defconstant +op-cdv+ 7)

(defun run (program A B C)
  (let ((ip 0)
        output)
    (flet ((fetch-oprand (oprand)
             (case oprand
               (4 A) (5 B) (6 C)
               (otherwise oprand)))
           (xdv (oprand)
             (floor A (ash 2 (1- oprand)))))
      (loop while (< ip (length program)) do
        (let* ((opcode (aref program ip))
               (oprand-lit (aref program (1+ ip)))
               (oprand (fetch-oprand oprand-lit)))
          (ecase opcode
            (#.+op-bxl+
             (setq B (logxor B oprand-lit)))
            (#.+op-bst+
             (setq B (logand oprand #b111)))
            (#.+op-jnz+
             (unless (zerop A)
               (setq ip (- oprand-lit 2))))
            (#.+op-bxc+
             (setq B (logxor B C)))
            (#.+op-out+
             (push (logand oprand #b111) output))
            (#.+op-adv+ (setq A (xdv oprand)))
            (#.+op-bdv+ (setq B (xdv oprand)))
            (#.+op-cdv+ (setq C (xdv oprand))))
          (incf ip 2))))
    (nreverse output)))