1
0
Fork 0

Day 9; Cleanup of IntCode interpreter and solutions from past days.

This commit is contained in:
Jonathan Chan 2019-12-08 23:29:20 -08:00
parent 59b628be64
commit c0670a74b1
11 changed files with 237 additions and 166 deletions

1
input/09.txt Normal file
View File

@ -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

37
letters.rkt Normal file
View File

@ -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
View File

@ -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)))

View File

@ -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

View File

@ -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)]

View File

@ -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)

View File

@ -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)))

View File

@ -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])

View File

@ -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)

15
src/09.rkt Normal file
View File

@ -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))

91
src/IntCode.rkt Normal file
View File

@ -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))