Day 9; Cleanup of IntCode interpreter and solutions from past days.
This commit is contained in:
parent
e16d1abe4d
commit
28a510f3ec
|
@ -0,0 +1 @@
|
|||
1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1101,0,3,1000,109,988,209,12,9,1000,209,6,209,3,203,0,1008,1000,1,63,1005,63,65,1008,1000,2,63,1005,63,904,1008,1000,0,63,1005,63,58,4,25,104,0,99,4,0,104,0,99,4,17,104,0,99,0,0,1102,252,1,1023,1102,36,1,1008,1102,24,1,1017,1101,25,0,1013,1102,479,1,1026,1101,0,259,1022,1102,1,38,1001,1102,1,713,1024,1101,0,708,1025,1102,1,22,1006,1101,0,32,1010,1101,476,0,1027,1102,1,516,1029,1102,1,34,1009,1101,0,23,1016,1102,1,37,1011,1102,525,1,1028,1101,0,35,1004,1102,31,1,1002,1102,39,1,1019,1102,28,1,1015,1102,1,1,1021,1101,0,30,1007,1101,0,27,1014,1101,21,0,1018,1101,0,29,1005,1102,26,1,1000,1102,1,0,1020,1101,0,20,1012,1101,33,0,1003,109,13,21108,40,40,6,1005,1019,199,4,187,1106,0,203,1001,64,1,64,1002,64,2,64,109,15,1205,-7,221,4,209,1001,64,1,64,1105,1,221,1002,64,2,64,109,-25,1208,-3,26,63,1005,63,243,4,227,1001,64,1,64,1106,0,243,1002,64,2,64,109,25,2105,1,-5,1001,64,1,64,1106,0,261,4,249,1002,64,2,64,109,-4,21108,41,42,-8,1005,1016,281,1001,64,1,64,1106,0,283,4,267,1002,64,2,64,109,-6,1206,2,301,4,289,1001,64,1,64,1105,1,301,1002,64,2,64,109,-4,21102,42,1,2,1008,1016,42,63,1005,63,323,4,307,1106,0,327,1001,64,1,64,1002,64,2,64,109,-7,2108,35,1,63,1005,63,343,1105,1,349,4,333,1001,64,1,64,1002,64,2,64,109,-13,1208,7,35,63,1005,63,369,1001,64,1,64,1106,0,371,4,355,1002,64,2,64,109,24,21102,43,1,-1,1008,1017,42,63,1005,63,391,1105,1,397,4,377,1001,64,1,64,1002,64,2,64,109,-13,2101,0,-4,63,1008,63,38,63,1005,63,419,4,403,1105,1,423,1001,64,1,64,1002,64,2,64,109,21,1206,-5,435,1106,0,441,4,429,1001,64,1,64,1002,64,2,64,109,-22,21101,44,0,10,1008,1014,44,63,1005,63,463,4,447,1105,1,467,1001,64,1,64,1002,64,2,64,109,25,2106,0,-2,1106,0,485,4,473,1001,64,1,64,1002,64,2,64,109,-19,2107,37,-2,63,1005,63,501,1106,0,507,4,491,1001,64,1,64,1002,64,2,64,109,8,2106,0,10,4,513,1001,64,1,64,1105,1,525,1002,64,2,64,109,-6,21107,45,46,0,1005,1012,547,4,531,1001,64,1,64,1105,1,547,1002,64,2,64,109,-5,1202,-1,1,63,1008,63,21,63,1005,63,567,1105,1,573,4,553,1001,64,1,64,1002,64,2,64,109,2,1207,-3,21,63,1005,63,589,1105,1,595,4,579,1001,64,1,64,1002,64,2,64,109,1,1201,-8,0,63,1008,63,34,63,1005,63,619,1001,64,1,64,1106,0,621,4,601,1002,64,2,64,109,-6,2102,1,-1,63,1008,63,33,63,1005,63,643,4,627,1105,1,647,1001,64,1,64,1002,64,2,64,109,10,21101,46,0,3,1008,1017,43,63,1005,63,667,1106,0,673,4,653,1001,64,1,64,1002,64,2,64,109,-13,2102,1,8,63,1008,63,35,63,1005,63,697,1001,64,1,64,1106,0,699,4,679,1002,64,2,64,109,23,2105,1,0,4,705,1105,1,717,1001,64,1,64,1002,64,2,64,109,-1,1205,-3,729,1106,0,735,4,723,1001,64,1,64,1002,64,2,64,109,-15,2101,0,0,63,1008,63,38,63,1005,63,755,1106,0,761,4,741,1001,64,1,64,1002,64,2,64,109,-2,2107,28,-1,63,1005,63,779,4,767,1106,0,783,1001,64,1,64,1002,64,2,64,109,-2,2108,35,0,63,1005,63,801,4,789,1105,1,805,1001,64,1,64,1002,64,2,64,109,1,1201,-5,0,63,1008,63,26,63,1005,63,831,4,811,1001,64,1,64,1105,1,831,1002,64,2,64,109,-5,1207,5,30,63,1005,63,849,4,837,1106,0,853,1001,64,1,64,1002,64,2,64,109,2,1202,-2,1,63,1008,63,26,63,1005,63,879,4,859,1001,64,1,64,1105,1,879,1002,64,2,64,109,15,21107,47,46,0,1005,1017,899,1001,64,1,64,1105,1,901,4,885,4,64,99,21102,1,27,1,21101,915,0,0,1106,0,922,21201,1,66416,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21102,942,1,0,1105,1,922,21202,1,1,-1,21201,-2,-3,1,21102,1,957,0,1105,1,922,22201,1,-1,-2,1105,1,968,22102,1,-2,-2,109,-3,2105,1,0
|
|
@ -0,0 +1,37 @@
|
|||
#lang racket
|
||||
|
||||
(define space
|
||||
(string-append
|
||||
"░░░░░"
|
||||
"░░░░░"
|
||||
"░░░░░"
|
||||
"░░░░░"
|
||||
"░░░░░"
|
||||
"░░░░░"))
|
||||
|
||||
(define A
|
||||
(string-append
|
||||
"░░█░░"
|
||||
"░█░█░"
|
||||
"█░░░█"
|
||||
"█████"
|
||||
"█░░░█"
|
||||
"█░░░█"))
|
||||
|
||||
(define B
|
||||
(string-append
|
||||
"███░░"
|
||||
"█░░█░"
|
||||
"███░░"
|
||||
"█░░█░"
|
||||
"█░░█░"
|
||||
"███░░"))
|
||||
|
||||
(define C
|
||||
(string-append
|
||||
"░░██░"
|
||||
"░█░░█"
|
||||
"█░░░░"
|
||||
"█░░░░"
|
||||
"░█░░█"
|
||||
"░░██░"))
|
84
lib.rkt
84
lib.rkt
|
@ -8,12 +8,16 @@
|
|||
sum
|
||||
neq?
|
||||
nzero?
|
||||
number->digits-reverse
|
||||
number->digits
|
||||
rac
|
||||
list-ref*
|
||||
number->digits-reverse
|
||||
number->digits)
|
||||
chunks-of
|
||||
transpose
|
||||
vector-ref*
|
||||
vector-set!*)
|
||||
|
||||
;; IO helpers
|
||||
;; IO helpers ;;
|
||||
|
||||
;; problem-input : number? -> (listof string?)
|
||||
;; Return contents of input file input/xx.txt as lines of strings.
|
||||
|
@ -28,7 +32,7 @@
|
|||
(printf "Part 1: ~a\nPart 2: ~a\n" part1 part2))
|
||||
|
||||
|
||||
;; Common helpers
|
||||
;; Number helpers ;;
|
||||
|
||||
;; sum : (listof number) -> number
|
||||
(define (sum ns) (apply + ns))
|
||||
|
@ -41,6 +45,22 @@
|
|||
(define (nzero? n)
|
||||
(not (zero? n)))
|
||||
|
||||
;; number->digits-reverse : number -> (listof number)
|
||||
;; Return the digits of the given number in reverse order (i.e. RTL)
|
||||
(define (number->digits-reverse n)
|
||||
(if (< n 10)
|
||||
(list n)
|
||||
(cons (remainder n 10)
|
||||
(number->digits-reverse (quotient n 10)))))
|
||||
|
||||
;; number->digits : number -> (listof number)
|
||||
;; Return the digits of the given number (LTR)
|
||||
(define (number->digits n)
|
||||
(reverse (number->digits-reverse n)))
|
||||
|
||||
|
||||
;; List helpers ;;
|
||||
|
||||
;; rac : (listof any) -> any -> (listof any)
|
||||
;; Append element to the back of the list.
|
||||
(define (rac lst v)
|
||||
|
@ -54,15 +74,49 @@
|
|||
failure-result
|
||||
(list-ref lst pos)))
|
||||
|
||||
;; number->digits-reverse : number -> (listof number)
|
||||
;; Return the digits of the given number in reverse order (i.e. RTL)
|
||||
(define (number->digits-reverse n)
|
||||
(if (< n 10)
|
||||
(list n)
|
||||
(cons (remainder n 10)
|
||||
(number->digits-reverse (quotient n 10)))))
|
||||
;; chunks-of : (listof any) -> nonzero? -> (listof (listof any))
|
||||
;; Partitions a list into lists of the given size in order,
|
||||
;; with the final list possibly being smaller
|
||||
;; e.g. '(1 2 3 4 5) 2 => '((1 2) (3 4) (5))
|
||||
(define (chunks-of lst size)
|
||||
(if (< (length lst) size) lst
|
||||
(cons (take lst size)
|
||||
(chunks-of (drop lst size) size))))
|
||||
|
||||
;; number->digits : number -> (listof number)
|
||||
;; Return the digits of the given number (LTR)
|
||||
(define (number->digits n)
|
||||
(reverse (number->digits-reverse n)))
|
||||
;; transpose : (listof (listof any)) -> (listof (listof any))
|
||||
;; Turns a list of lists into a list of lists of
|
||||
;; the first elements of the lists, ..., the nth elements
|
||||
;; where n is the length of the shortest list.
|
||||
;; In short, it transposes a list of rows into a list of columns.
|
||||
;; e.g. '((1 2 3 4) '((1 5 8)
|
||||
;; (5 6 7) => (2 6 9)
|
||||
;; (8 9 10 11 12)) (3 7 10))
|
||||
(define (transpose layers)
|
||||
(if (ormap empty? layers) '()
|
||||
(let ([pixels (map car layers)]
|
||||
[layers (map cdr layers)])
|
||||
(cons pixels (transpose layers)))))
|
||||
|
||||
|
||||
;; Vector helpers ;;
|
||||
|
||||
;; vector-ref* : (vectorof any) -> number -> any -> any
|
||||
;; Same as list-ref, except a default value is provided
|
||||
;; if the index is beyond the length of the list.
|
||||
(define (vector-ref* vec pos failure-result)
|
||||
(if (>= pos (vector-length vec))
|
||||
failure-result
|
||||
(vector-ref vec pos)))
|
||||
|
||||
;; vector-set!* : (vectorof any) -> number -> any -> (vectorof any)
|
||||
;; Set the value at given index in the vector, then return the vector
|
||||
;; If the index is beyond the length of the vector,
|
||||
;; a vector that can accomodate that index is returned,
|
||||
;; with all the original elements and the element at the index set
|
||||
(define (vector-set!* vec pos v)
|
||||
(if (< pos (vector-length vec))
|
||||
(begin (vector-set! vec pos v) vec)
|
||||
(let ([new-vec (make-vector (add1 pos))])
|
||||
(vector-copy! new-vec 0 vec)
|
||||
(vector-set! new-vec pos v)
|
||||
new-vec)))
|
24
src/01.rkt
24
src/01.rkt
|
@ -2,30 +2,6 @@
|
|||
|
||||
(require "../lib.rkt")
|
||||
|
||||
#|
|
||||
DAY 1: The Tyranny of the Rocket Equation (excerpt)
|
||||
|
||||
PART 1:
|
||||
...
|
||||
Fuel required to launch a given module is based on its mass.
|
||||
Specifically, to find the fuel required for a module, take its mass,
|
||||
divide by three, round down, and subtract 2.
|
||||
...
|
||||
What is the sum of the fuel requirements for all of the modules
|
||||
on your spacecraft?
|
||||
|
||||
PART 2:
|
||||
...
|
||||
So, for each module mass, calculate its fuel and add it to the total.
|
||||
Then, treat the fuel amount you just calculated as the input mass
|
||||
and repeat the process, continuing until a fuel requirement is zero
|
||||
or negative.
|
||||
...
|
||||
What is the sum of the fuel requirements for all of the modules
|
||||
on your spacecraft when also taking into account the mass of the
|
||||
added fuel?
|
||||
|#
|
||||
|
||||
(define input (map string->number (problem-input 1)))
|
||||
|
||||
;; calc-fuel : number -> number
|
||||
|
|
36
src/02.rkt
36
src/02.rkt
|
@ -1,34 +1,29 @@
|
|||
#lang racket
|
||||
|
||||
(require "../lib.rkt")
|
||||
(require "../lib.rkt"
|
||||
"IntCode.rkt"
|
||||
racket/vector)
|
||||
|
||||
(define input
|
||||
(map string->number (string-split (car (problem-input 2)) ",")))
|
||||
(string->program (car (problem-input 2))))
|
||||
|
||||
(define (input-nv nv)
|
||||
(append (list (car input) (first nv) (second nv)) (cdddr input)))
|
||||
(let ([input (vector-copy input)])
|
||||
(vector-set! input 1 (first nv))
|
||||
(vector-set! input 2 (second nv))
|
||||
input))
|
||||
|
||||
(define (exec pointer program)
|
||||
(let* ([opcode (list-ref program pointer)]
|
||||
[val1 (list-ref program (list-ref program (+ pointer 1)))]
|
||||
[val2 (list-ref program (list-ref program (+ pointer 2)))]
|
||||
[val3 (list-ref program (+ pointer 3))]
|
||||
[next-program
|
||||
(cond [(= opcode 1)
|
||||
(list-set program val3 (+ val1 val2))]
|
||||
[(= opcode 2)
|
||||
(list-set program val3 (* val1 val2))]
|
||||
[else program])])
|
||||
(if (= opcode 99)
|
||||
next-program
|
||||
(exec (+ pointer 4) next-program))))
|
||||
(define (exec-pos0 program)
|
||||
(let-values ([(program _)
|
||||
(exec program)])
|
||||
(vector-ref program 0)))
|
||||
|
||||
(define part1
|
||||
(car (exec 0 (input-nv '(12 2)))))
|
||||
(exec-pos0 (input-nv '(12 2))))
|
||||
|
||||
(define part2
|
||||
(let* ([nounverbs (cartesian-product (range 100) (range 100))]
|
||||
[outputs (map (λ (nv) (car (exec 0 (input-nv nv)))) nounverbs)]
|
||||
[outputs (map (λ (nv) (exec-pos0 (input-nv nv))) nounverbs)]
|
||||
[nounverb (list-ref nounverbs (index-of outputs 19690720))]
|
||||
[noun (first nounverb)]
|
||||
[verb (second nounverb)])
|
||||
|
@ -41,7 +36,8 @@
|
|||
;;;; ALTERNATE SOLUTION
|
||||
|
||||
(define part2-input
|
||||
(append (list (car input) 'noun 'verb '(+ noun verb)) (cddddr input)))
|
||||
(let ([input (vector->list input)])
|
||||
(append (list (car input) 'noun 'verb '(+ noun verb)) (cddddr input))))
|
||||
|
||||
(define (exec-sym pointer program)
|
||||
(let* ([opcode (list-ref program pointer)]
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
(define-values (start end) (values 235741 706948))
|
||||
|
||||
(define (neq? b1 b2) (not (eq? b1 b2)))
|
||||
|
||||
(define (two-adjacent-digits? cs)
|
||||
(if (< (length cs) 2) #f
|
||||
(or (eq? (first cs)
|
||||
|
|
79
src/05.rkt
79
src/05.rkt
|
@ -1,86 +1,11 @@
|
|||
#lang racket
|
||||
|
||||
(require "../lib.rkt")
|
||||
|
||||
(provide string->program
|
||||
exec)
|
||||
|
||||
;; string->program : string -> (listof number)
|
||||
;; A program is a list of numbers,
|
||||
;; which are sequences of instructions and parameters.
|
||||
(define (string->program str)
|
||||
(map string->number (string-split str ",")))
|
||||
(require "../lib.rkt"
|
||||
"IntCode.rkt")
|
||||
|
||||
(define input
|
||||
(string->program (car (problem-input 5))))
|
||||
|
||||
;; leave-one : (listof any) -> (listof any)
|
||||
;; If the list has one or fewer elements, return the list;
|
||||
;; otherwise, return the rest of the list
|
||||
(define (leave-one lst)
|
||||
(if (<= (length lst) 1) lst (cdr lst)))
|
||||
|
||||
;; exec : program -> number -> (listof number) -> (listof number) -> program
|
||||
;; An encoded instruction is anywhere from 1 to 4 digits long.
|
||||
;; The last one or two digits represent the opcode, which can be:
|
||||
;; - 1/2: add/multiply parameters 1 and 2 and store in parameter 3
|
||||
;; - 3: take an input and store in parameter 1
|
||||
;; - 4: output parameter 1
|
||||
;; - 5/6: if parameter 1 is non-zero/zero, jump to parameter 2
|
||||
;; - 7/8: if parameter 1 is less-than/equal-to parameter 2,
|
||||
;; store 1 else store 0 in parameter 3
|
||||
;; - 99: halt
|
||||
;; The next few digits to the left of the opcode (if any) represent
|
||||
;; the mode of each parameter, with that of parameter i in the digit
|
||||
;; i digits to the left of the opcode.
|
||||
;; If the mode is 0, the value at pointer is an address.
|
||||
;; If the mode is 1, the value at pointer is immediate.
|
||||
;; Note that leading zeroes in the encoded instruction are omitted.
|
||||
(define (exec program #:ptr [pointer 0] #:in [input '()] #:out [output '()])
|
||||
(let* ([instruction (list-ref program pointer)]
|
||||
[opcode (remainder instruction 100)]
|
||||
[mode1 (remainder (quotient instruction 100) 10)]
|
||||
[mode2 (remainder (quotient instruction 1000) 10)]
|
||||
[mode3 (remainder (quotient instruction 10000) 10)]
|
||||
;; l* : call to get write location from program
|
||||
[l1 (λ () (if (zero? mode1) (list-ref program (+ pointer 1)) (+ pointer 1)))]
|
||||
[l2 (λ () (if (zero? mode2) (list-ref program (+ pointer 2)) (+ pointer 2)))]
|
||||
[l3 (λ () (if (zero? mode3) (list-ref program (+ pointer 3)) (+ pointer 3)))]
|
||||
;; v* : call to read values from program
|
||||
[v1 (λ () (list-ref program (l1)))]
|
||||
[v2 (λ () (list-ref program (l2)))]
|
||||
[v3 (λ () (list-ref program (l3)))]
|
||||
[next-pointer
|
||||
(match opcode
|
||||
[(or 1 2 7 8) (+ pointer 4)]
|
||||
[(or 3 4) (+ pointer 2)]
|
||||
[(or 5 6) (+ pointer 3)]
|
||||
[99 (+ pointer 1)])])
|
||||
(match opcode
|
||||
[(or 1 2)
|
||||
(let* ([arith (match opcode [1 +] [2 *])]
|
||||
[value (arith (v1) (v2))]
|
||||
[program (list-set program (l3) value)])
|
||||
(exec program #:ptr next-pointer #:in input #:out output))]
|
||||
[3
|
||||
(let* ([value (car input)]
|
||||
[input (cdr input)]
|
||||
[program (list-set program (l1) value)])
|
||||
(exec program #:ptr next-pointer #:in input #:out output))]
|
||||
[4
|
||||
(let* ([output (append output `(,(v1)))])
|
||||
(exec program #:ptr next-pointer #:in input #:out output))]
|
||||
[(or 5 6)
|
||||
(let* ([jump-if (match opcode [5 nzero?] [6 zero?])]
|
||||
[next-pointer (if (jump-if (v1)) (v2) next-pointer)])
|
||||
(exec program #:ptr next-pointer #:in input #:out output))]
|
||||
[(or 7 8)
|
||||
(let* ([lt-eq (match opcode [7 <] [8 =])]
|
||||
[value (if (lt-eq (v1) (v2)) 1 0)]
|
||||
[program (list-set program (l3) value)])
|
||||
(exec program #:ptr next-pointer #:in input #:out output))]
|
||||
[99 (values program output)])))
|
||||
|
||||
(define part1
|
||||
(let-values ([(_ out) (exec input #:in '(1))])
|
||||
(last out)))
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
(require data/queue
|
||||
"../lib.rkt"
|
||||
"05.rkt")
|
||||
"IntCode.rkt")
|
||||
|
||||
(define input
|
||||
(string->program (car (problem-input 7))))
|
||||
|
@ -69,7 +69,8 @@
|
|||
(state program next-pointer (cdr input)))])))
|
||||
|
||||
(define (amplify-loop phase)
|
||||
(let* ([amps (map (compose (curry state input 0) list) phase)]
|
||||
(let* ([input (vector->list input)]
|
||||
[amps (map (compose (curry state input 0) list) phase)]
|
||||
[Q (make-queue)])
|
||||
(map (curry enqueue! Q) amps)
|
||||
(let loop ([signal 0])
|
||||
|
|
29
src/08.rkt
29
src/08.rkt
|
@ -8,33 +8,10 @@
|
|||
(define width 25)
|
||||
(define height 6)
|
||||
|
||||
;; partition-into : (listof any) -> nonzero? -> (listof (listof any))
|
||||
;; Partitions a list into lists of the given size in order,
|
||||
;; with the final list possibly being smaller
|
||||
;; e.g. '(1 2 3 4 5) 2 => '((1 2) (3 4) (5))
|
||||
(define (partition-into lst size)
|
||||
(if (< (length lst) size) lst
|
||||
(cons (take lst size)
|
||||
(partition-into (drop lst size) size))))
|
||||
|
||||
;; pivot : (listof (listof any)) -> (listof (listof any))
|
||||
;; Turns a list of lists into a list of lists of
|
||||
;; the first elements of the lists, ..., the nth elements
|
||||
;; where n is the length of the shortest list.
|
||||
;; In short, it pivots a list of rows into a list of columns.
|
||||
;; e.g. '((1 2 3 4) '((1 5 8)
|
||||
;; (5 6 7) => (2 6 9)
|
||||
;; (8 9 10 11 12)) (3 7 10))
|
||||
(define (pivot layers)
|
||||
(if (ormap empty? layers) '()
|
||||
(let ([pixels (map car layers)]
|
||||
[layers (map cdr layers)])
|
||||
(cons pixels (pivot layers)))))
|
||||
|
||||
(define layers
|
||||
(let* ([area (* width height)]
|
||||
[chars (string->list input)])
|
||||
(partition-into chars area)))
|
||||
(chunks-of chars area)))
|
||||
|
||||
(define part1
|
||||
(let* ([zeroes (map (curry count (curry eq? #\0)) layers)]
|
||||
|
@ -45,9 +22,9 @@
|
|||
(* ones twos)))
|
||||
|
||||
(define part2
|
||||
(let* ([image (map (curry findf (curry neq? #\2)) (pivot layers))]
|
||||
(let* ([image (map (curry findf (curry neq? #\2)) (transpose layers))]
|
||||
[image* (map (λ (pixel) (if (eq? pixel #\1) #\█ #\ )) image)]
|
||||
[msg (map list->string (partition-into image* width))])
|
||||
[msg (map list->string (chunks-of image* width))])
|
||||
(for-each displayln msg)))
|
||||
|
||||
(show-solution part1 #f)
|
|
@ -0,0 +1,15 @@
|
|||
#lang racket
|
||||
|
||||
(require "../lib.rkt"
|
||||
"IntCode.rkt")
|
||||
|
||||
(define input
|
||||
(string->program (car (problem-input 9))))
|
||||
|
||||
(define-values (_ part1)
|
||||
(exec input #:in '(1)))
|
||||
|
||||
(define-values (__ part2)
|
||||
(exec input #:in '(2)))
|
||||
|
||||
(show-solution (car part1) (car part2))
|
|
@ -0,0 +1,91 @@
|
|||
#lang racket
|
||||
|
||||
(require racket/vector
|
||||
"../lib.rkt")
|
||||
|
||||
(provide string->program
|
||||
exec)
|
||||
|
||||
(define (vector-ref** vec pos)
|
||||
(vector-ref* vec pos 0))
|
||||
|
||||
;; string->program : string -> (listof number)
|
||||
;; A program is a list of numbers,
|
||||
;; which are sequences of instructions and parameters.
|
||||
(define (string->program str)
|
||||
(list->vector (map string->number (string-split str ","))))
|
||||
|
||||
;; exec* : program -> number -> number -> (listof number) -> (listof number) -> program
|
||||
;; An encoded instruction is anywhere from 1 to 4 digits long.
|
||||
;; The last one or two digits represent the opcode, which can be:
|
||||
;; - 1/2: add/multiply parameters 1 and 2 and store in parameter 3
|
||||
;; - 3: take an input and store in parameter 1
|
||||
;; - 4: output parameter 1
|
||||
;; - 5/6: if parameter 1 is non-zero/zero, jump to parameter 2
|
||||
;; - 7/8: if parameter 1 is less-than/equal-to parameter 2,
|
||||
;; store 1 else store 0 in parameter 3
|
||||
;; - 9: add parameter 1 to relative base
|
||||
;; - 99: halt
|
||||
;; The next few digits to the left of the opcode (if any) represent
|
||||
;; the mode of each parameter, with that of parameter i in the digit
|
||||
;; i digits to the left of the opcode.
|
||||
;; If the mode is 0, the value at pointer is an address.
|
||||
;; If the mode is 1, the value at pointer is immediate.
|
||||
;; If the mode is 2, the value at pointer is an address to be offset by base.
|
||||
;; Note that leading zeroes in the encoded instruction are omitted.
|
||||
(define (exec* program #:ptr [pointer 0] #:base [base 0] #:in [input '()] #:out [output '()])
|
||||
(define instruction (vector-ref** program pointer))
|
||||
(define opcode (remainder instruction 100))
|
||||
(define next-pointer
|
||||
(match opcode
|
||||
[(or 1 2 7 8) (+ pointer 4)]
|
||||
[(or 3 4 9) (+ pointer 2)]
|
||||
[(or 5 6) (+ pointer 3)]
|
||||
[99 (+ pointer 1)]))
|
||||
(define (get-location index mode)
|
||||
(match mode
|
||||
[0 (vector-ref** program (+ pointer index))]
|
||||
[1 (+ pointer index)]
|
||||
[2 (+ (vector-ref** program (+ pointer index)) base)]))
|
||||
(let* ([mode1 (remainder (quotient instruction 100) 10)]
|
||||
[mode2 (remainder (quotient instruction 1000) 10)]
|
||||
[mode3 (remainder (quotient instruction 10000) 10)]
|
||||
;; l* : call to get write location from program
|
||||
[l1 (λ () (get-location 1 mode1))]
|
||||
[l2 (λ () (get-location 2 mode2))]
|
||||
[l3 (λ () (get-location 3 mode3))]
|
||||
;; v* : call to read values from program
|
||||
[v1 (λ () (vector-ref** program (l1)))]
|
||||
[v2 (λ () (vector-ref** program (l2)))]
|
||||
[v3 (λ () (vector-ref** program (l3)))])
|
||||
(match opcode
|
||||
[(or 1 2)
|
||||
(let* ([arith (match opcode [1 +] [2 *])]
|
||||
[value (arith (v1) (v2))]
|
||||
[program (vector-set!* program (l3) value)])
|
||||
(exec* program #:ptr next-pointer #:base base #:in input #:out output))]
|
||||
[3
|
||||
(let* ([value (car input)]
|
||||
[input (cdr input)]
|
||||
[program (vector-set!* program (l1) value)])
|
||||
(exec* program #:ptr next-pointer #:base base #:in input #:out output))]
|
||||
[4
|
||||
(let* ([output (append output `(,(v1)))])
|
||||
(exec* program #:ptr next-pointer #:base base #:in input #:out output))]
|
||||
[(or 5 6)
|
||||
(let* ([jump-if (match opcode [5 nzero?] [6 zero?])]
|
||||
[next-pointer (if (jump-if (v1)) (v2) next-pointer)])
|
||||
(exec* program #:ptr next-pointer #:base base #:in input #:out output))]
|
||||
[(or 7 8)
|
||||
(let* ([lt-eq (match opcode [7 <] [8 =])]
|
||||
[value (if (lt-eq (v1) (v2)) 1 0)]
|
||||
[program (vector-set!* program (l3) value)])
|
||||
(exec* program #:ptr next-pointer #:base base #:in input #:out output))]
|
||||
[9
|
||||
(let ([base (+ base (v1))])
|
||||
(exec* program #:ptr next-pointer #:base base #:in input #:out output))]
|
||||
[99 (values program output)])))
|
||||
|
||||
;; Just so we always run the program on a fresh copy
|
||||
(define (exec program #:ptr [pointer 0] #:base [base 0] #:in [input '()] #:out [output '()])
|
||||
(exec* (vector-copy program) #:ptr pointer #:base base #:in input #:out output))
|
Loading…
Reference in New Issue