1
0
Fork 0

Refactored IntCode to internally use a hashmap instead of a vector.

This commit is contained in:
Jonathan Chan 2019-12-17 11:26:03 -08:00
parent 9548612f61
commit 7873fda361
2 changed files with 49 additions and 32 deletions

32
lib.rkt
View File

@ -12,7 +12,7 @@
make-vector-grid make-vector-grid
vectors->lists vectors->lists
hash->vector hash->vectors
show-list-grid show-list-grid
show-vector-grid show-vector-grid
show-hash-grid show-hash-grid
@ -38,7 +38,9 @@
list->queue list->queue
vector-ref* vector-ref*
vector-set!*) vector-set!*
hash->vector
vector->hash)
;; Function helpers ;; ;; Function helpers ;;
@ -60,7 +62,7 @@
[path (string-append "../input/" filename ".txt")]) [path (string-append "../input/" filename ".txt")])
(read-lines path))) (read-lines path)))
;; show-solution : any/c -> any/c -> void ;; show-solution : a -> b -> void
;; Print part1 and part2 on separate lines. ;; Print part1 and part2 on separate lines.
(define (show-solution part1 part2) (define (show-solution part1 part2)
(printf "Part 1: ~a\nPart 2: ~a\n" part1 part2)) (printf "Part 1: ~a\nPart 2: ~a\n" part1 part2))
@ -80,10 +82,10 @@
(define (vectors->lists vector-grid) (define (vectors->lists vector-grid)
(map vector->list (vector->list vector-grid))) (map vector->list (vector->list vector-grid)))
;; hash->vector : hash-grid -> number -> vector-grid ;; hash->vectors : hash-grid -> number -> vector-grid
;; Where the position is not in the hash-grid, ;; Where the position is not in the hash-grid,
;; the vector-grid takes on the default value. ;; the vector-grid takes on the default value.
(define (hash->vector hash-grid [default 0]) (define (hash->vectors hash-grid [default 0])
(let* ([keys (hash-keys hash-grid)] (let* ([keys (hash-keys hash-grid)]
[xs (map car keys)] [xs (map car keys)]
[ys (map cdr keys)] [ys (map cdr keys)]
@ -113,7 +115,7 @@
;; show-hash-grid : (hashof (value => char)) -> hash-grid -> number -> void ;; show-hash-grid : (hashof (value => char)) -> hash-grid -> number -> void
(define (show-hash-grid char-hash hash-grid [default 0]) (define (show-hash-grid char-hash hash-grid [default 0])
(show-vector-grid char-hash (hash->vector hash-grid default))) (show-vector-grid char-hash (hash->vectors hash-grid default)))
;; Number helpers ;; ;; Number helpers ;;
@ -189,7 +191,7 @@
(cons (f v (first lst)) lst)) (cons (f v (first lst)) lst))
(list init) lst))) (list init) lst)))
;; list-ref* : (listof any) -> number -> any -> any ;; list-ref* : (listof a) -> number -> a -> a
;; Same as list-ref, except a default value is provided ;; Same as list-ref, except a default value is provided
;; if the index is beyond the length of the list. ;; if the index is beyond the length of the list.
(define (list-ref* lst pos failure-result) (define (list-ref* lst pos failure-result)
@ -224,7 +226,7 @@
[lists (map (λ (lst) (take lst min-len)) lists)]) [lists (map (λ (lst) (take lst min-len)) lists)])
(apply map list lists))) (apply map list lists)))
;; list->queue : (listof any) -> (queueof any) ;; list->queue : (listof a) -> (queueof a)
;; Creates a queue and adds elements of list in order ;; Creates a queue and adds elements of list in order
(define (list->queue lst) (define (list->queue lst)
(let ([Q (make-queue)]) (let ([Q (make-queue)])
@ -251,4 +253,16 @@
(let ([new-vec (make-vector (max (vector-length vec) (add1 pos)))]) (let ([new-vec (make-vector (max (vector-length vec) (add1 pos)))])
(vector-copy! new-vec 0 vec) (vector-copy! new-vec 0 vec)
(vector-set! new-vec pos v) (vector-set! new-vec pos v)
new-vec)) new-vec))
;; hash->vector : (hashof (number => a)) -> (vectorof a)
;; Convert an intmap into a mutable vector
(define (hash->vector hash [default 0])
(let ([length (add1 (apply max (hash-keys hash)))])
(build-vector length (λ (i) (hash-ref hash i default)))))
;; vector->hash : (vectorof a) -> (hashof (number => a))
;; Convert a vector into an immutable intmap
(define (vector->hash vec)
(let ([kvs (map cons (range (vector-length vec)) (vector->list vec))])
(make-immutable-hash kvs)))

View File

@ -3,17 +3,17 @@
(require racket/vector (require racket/vector
"../lib.rkt") "../lib.rkt")
(define (vector-ref vec pos) ;; string->program : string -> (vectorof number)
(vector-ref* vec pos 0))
;; string->program : string -> (listof number)
;; A program is a list of numbers, ;; A program is a list of numbers,
;; which are sequences of instructions and parameters. ;; which are sequences of instructions and parameters.
(define (string->program str) (define (string->program str)
(list->vector (map string->number (string-split str ",")))) (list->vector (map string->number (string-split str ","))))
(define (hash-ref* hash key)
(hash-ref hash key 0))
(define (program? p) (define (program? p)
(vectorof number?)) hash?)
;; state = ;; state =
;; | out number (() -> state) ;; | out number (() -> state)
@ -38,21 +38,21 @@
[in (resume) (resume input)] [in (resume) (resume input)]
[else (error "resume-with-input: Unexpected program state.")])) [else (error "resume-with-input: Unexpected program state.")]))
;; resume-with-io : state -> (listof number) -> (listof number) ;; resume-with-io : state -> (listof number) -> (listof number) -> (listof number)
;; Run the program, providing input as needed, and collecting output. ;; Run the program, providing input as needed, and collecting output.
(define (resume-with-io st inputs) (define (resume-with-io st inputs [outputs '()])
(type-case state st (type-case state st
[in (resume) [in (resume)
(resume-with-io (resume (car inputs)) (cdr inputs))] (resume-with-io (resume (car inputs)) (cdr inputs) outputs)]
[out (value resume) [out (value resume)
(cons value (resume-with-io (resume) inputs))] (resume-with-io (resume) inputs (cons value outputs))]
[halt (program) '()])) [halt (program) (reverse outputs)]))
;; halt-with-program : state -> program ;; halt-with-program : state -> (vectorof number)
;; Return program state of halted execution. ;; Return program state of halted execution.
(define (halt-with-program st) (define (halt-with-program st)
(type-case state st (type-case state st
[halt (program) program] [halt (program) (hash->vector program)]
[else (error "halt-with-program: Unexpected program state.")])) [else (error "halt-with-program: Unexpected program state.")]))
;; exec* : program -> number -> number -> state ;; exec* : program -> number -> number -> state
@ -74,7 +74,7 @@
;; If the mode is 2, the value at pointer is an address to be offset by base. ;; 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. ;; Note that leading zeroes in the encoded instruction are omitted.
(define (exec* program #:ptr [pointer 0] #:base [base 0]) (define (exec* program #:ptr [pointer 0] #:base [base 0])
(define instruction (vector-ref program pointer)) (define instruction (hash-ref* program pointer))
(define opcode (remainder instruction 100)) (define opcode (remainder instruction 100))
(define next-pointer (define next-pointer
(match opcode (match opcode
@ -84,9 +84,9 @@
[99 (+ pointer 1)])) [99 (+ pointer 1)]))
(define (get-location index mode) (define (get-location index mode)
(match mode (match mode
[0 (vector-ref program (+ pointer index))] [0 (hash-ref* program (+ pointer index))]
[1 (+ pointer index)] [1 (+ pointer index)]
[2 (+ (vector-ref program (+ pointer index)) base)])) [2 (+ (hash-ref* program (+ pointer index)) base)]))
(let* ([mode1 (remainder (quotient instruction 100) 10)] (let* ([mode1 (remainder (quotient instruction 100) 10)]
[mode2 (remainder (quotient instruction 1000) 10)] [mode2 (remainder (quotient instruction 1000) 10)]
[mode3 (remainder (quotient instruction 10000) 10)] [mode3 (remainder (quotient instruction 10000) 10)]
@ -95,19 +95,19 @@
[l2 (λ () (get-location 2 mode2))] [l2 (λ () (get-location 2 mode2))]
[l3 (λ () (get-location 3 mode3))] [l3 (λ () (get-location 3 mode3))]
;; v* : call to read values from program ;; v* : call to read values from program
[v1 (λ () (vector-ref program (l1)))] [v1 (λ () (hash-ref* program (l1)))]
[v2 (λ () (vector-ref program (l2)))] [v2 (λ () (hash-ref* program (l2)))]
[v3 (λ () (vector-ref program (l3)))]) [v3 (λ () (hash-ref* program (l3)))])
(match opcode (match opcode
[(or 1 2) [(or 1 2)
(let* ([arith (match opcode [1 +] [2 *])] (let* ([arith (match opcode [1 +] [2 *])]
[value (arith (v1) (v2))] [value (arith (v1) (v2))]
[program (vector-set!* program (l3) value)]) [program (hash-set program (l3) value)])
(exec* program #:ptr next-pointer #:base base))] (exec* program #:ptr next-pointer #:base base))]
[3 [3
(let* ([resume (let* ([resume
(λ (input) (λ (input)
(let ([program (vector-set!* program (l1) input)]) (let ([program (hash-set program (l1) input)])
(exec* program #:ptr next-pointer #:base base)))]) (exec* program #:ptr next-pointer #:base base)))])
(in resume))] (in resume))]
[4 [4
@ -122,7 +122,7 @@
[(or 7 8) [(or 7 8)
(let* ([lt-eq (match opcode [7 <] [8 =])] (let* ([lt-eq (match opcode [7 <] [8 =])]
[value (if (lt-eq (v1) (v2)) 1 0)] [value (if (lt-eq (v1) (v2)) 1 0)]
[program (vector-set!* program (l3) value)]) [program (hash-set program (l3) value)])
(exec* program #:ptr next-pointer #:base base))] (exec* program #:ptr next-pointer #:base base))]
[9 [9
(let ([base (+ base (v1))]) (let ([base (+ base (v1))])
@ -130,6 +130,9 @@
[99 [99
(halt program)]))) (halt program)])))
;; Just so we always run the program on a fresh copy ;; The external interface accepts a vector,
;; while the internals use an immutable hashmap
;; for functional purity and performance
(define (exec program #:ptr [pointer 0] #:base [base 0]) (define (exec program #:ptr [pointer 0] #:base [base 0])
(exec* (vector-copy program) #:ptr pointer #:base base)) (let* ([hash-program (vector->hash program)])
(exec* hash-program #:ptr pointer #:base base)))