aboutsummaryrefslogtreecommitdiff
path: root/2019/interpreter.lisp
blob: 30bee822bf289a10ff1210b570d6c4fa501c18b8 (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
48
49
50
51
52
53
54
55
56
(defpackage #:intcode
  (:use :cl)
  (:export :run :parse))

(in-package #:intcode)

;;; Interpreter

(defun run (ram)
  (let ((ip 0))
    (loop
     (let ((opcode (aref ram ip))
           (arg-1 (try-aref ram (+ ip 1)))
           (arg-2 (try-aref ram (+ ip 2)))
           (arg-3 (try-aref ram (+ ip 3))))
       (case opcode
         (1
          (setf (aref ram arg-3)
                (+ (aref ram arg-1)
                   (aref ram arg-2))))
         (2
          (setf (aref ram arg-3)
                (* (aref ram arg-1)
                   (aref ram arg-2))))
         (99
          (return-from run))
         (otherwise
          (error (format nil "Invalid opcode ‘~d’" opcode)))))
     (incf ip 4))))

;;; Input Parsing

(defun parse (filename)
  (with-open-file (stream filename)
    (let ((contents (make-string (file-length stream))))
      (read-sequence contents stream)
      (extract-numbers-from-string contents))))

(defun extract-numbers-from-string (string)
  (loop for comma-pos = (position-if #'commap string)
        collect (parse-integer (subseq string 0 comma-pos)) into numbers
        unless comma-pos
          return (coerce numbers 'vector)
        do (setq string (subseq string (1+ comma-pos)))))

;;; Helper Functions

(defun commap (char)
  (char= char #\,))

(defun try-aref (array &rest subscripts)
  (loop for i in subscripts
        for j in (array-dimensions array)
        unless (< -1 i j)
          return nil
        finally (return (apply #'aref array subscripts))))