Refactored IntCode to internally use a hashmap instead of a vector.
This commit is contained in:
parent
9a4afc2dd3
commit
10c0b5bf28
32
lib.rkt
32
lib.rkt
|
@ -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)))
|
|
@ -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)))
|
Loading…
Reference in New Issue