From aecfdf1296b9b15a64233ec0955f3df59945f604 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Thu, 5 Dec 2019 09:14:35 -0800 Subject: [PATCH] refac --- 2019/05.rkt | 123 ++++++++++++++++++++++------------------------------ 1 file changed, 52 insertions(+), 71 deletions(-) diff --git a/2019/05.rkt b/2019/05.rkt index 80828dc..0ff9fcd 100644 --- a/2019/05.rkt +++ b/2019/05.rkt @@ -1,87 +1,68 @@ #lang br (require racket/file rackunit) -(define (parse-ptr ptr proc) - (match (for/list ([c (in-string (~r ptr #:min-width 5 #:pad-string "0"))]) - (string->number (string c))) - [(list d4 d3 d2 d1 d0) (cons (+ (* 10 d1) d0) - (for/list ([val (list d2 d3 d4)]) - (if (zero? val) proc values)))])) - (define (string->regs str) (list->vector (map string->number (string-split (string-replace str "," " "))))) +(define ((binarize proc) x y) (if (proc x y) 1 0)) + (define (run str starting-input) (define regs (string->regs str)) - (define (deref ptr) (vector-ref regs ptr)) - (let loop ([ptr 0]) - (match-define (list opcode mode1 mode2 mode3) (parse-ptr (vector-ref regs ptr) deref)) - (match opcode - ;; add & multiply - [(or 1 2) - (vector-set! regs (deref (+ ptr 3)) - ((match opcode [1 +][_ *]) - (mode1 (deref (+ ptr 1))) - (mode2 (deref (+ ptr 2))))) - (loop (+ ptr 4))] - ;; input - [3 (vector-set! regs (mode1 (+ ptr 1)) starting-input) - (loop (+ ptr 2))] - ;; output - [4 (println (vector-ref regs (mode1 (+ ptr 1)))) - (loop (+ ptr 2))] - ;; jump - [(or 5 6) - (if ((match opcode [5 not][_ values]) (zero? (mode1 (deref (+ ptr 1))))) - (loop (mode2 (deref (+ ptr 2)))) - (loop (+ ptr 3)))] - ;; compare - [(or 7 8) - (vector-set! regs (deref (+ ptr 3)) - (if ((match opcode [7 <][_ =]) (mode1 (deref (+ ptr 1))) (mode2 (deref (+ ptr 2)))) - 1 - 0)) - (loop (+ ptr 4))] - ;; terminate - [99 (void)] - [_ (error 'unknown-opcode)]))) + (define (reg-ref ptr) (vector-ref regs ptr)) + (define (reg-set! ptr val) (vector-set! regs (reg-ref ptr) val)) + (let/ec terminate + (let loop ([ptr 0]) + (match-define (list opcode mode1 mode2 mode3) + (match (for/list ([c (in-string (~r (reg-ref ptr) #:min-width 5 #:pad-string "0"))]) + (string->number (string c))) + [(list d4 d3 d2 d1 d0) (cons (+ (* 10 d1) d0) + (for/list ([mode (list d2 d3 d4)]) + (if (zero? mode) reg-ref values)))])) + (define next-ptr + (match opcode + [(or 1 2 7 8) ; 4-arity: add & multiply & compare + (reg-set! (+ ptr 3) ((match opcode + [1 +] + [2 *] + [7 (binarize <)] + [8 (binarize =)]) (mode1 (reg-ref (+ ptr 1))) + (mode2 (reg-ref (+ ptr 2))))) + (+ ptr 4)] + [(or 3 4) ; 2-arity: input & output + (match opcode + [3 (reg-set! (+ ptr 1) starting-input)] + [4 (println (reg-ref (mode1 (+ ptr 1))))]) + (+ ptr 2)] + [(or 5 6) ; 3-arity: jump + (if ((match opcode + [5 not] + [6 values]) (zero? (mode1 (reg-ref (+ ptr 1))))) + (mode2 (reg-ref (+ ptr 2))) + (+ ptr 3))] + [99 (terminate)] + [_ (error 'unknown-opcode)])) + (loop next-ptr)))) -(define-syntax-rule (last-output-line func) +(define-syntax-rule (last-output func) (last (map string->number (string-split (with-output-to-string (λ () func)))))) -(check-eq? (last-output-line (run "3,0,4,0,99" 42)) 42) +(check-eq? (last-output (run "3,0,4,0,99" 42)) 42) ;; 1 -(check-eq? - (last-output-line (run (file->string "05.rktd") 1)) - 15386262) +(check-eq? (last-output (run (file->string "05.rktd") 1)) 15386262) -(check-eq? (last-output-line (run "3,9,8,9,10,9,4,9,99,-1,8" 8)) 1) -(check-eq? (last-output-line (run "3,9,7,9,10,9,4,9,99,-1,8" 8)) 0) -(check-eq? (last-output-line (run "3,3,1108,-1,8,3,4,3,99" 8)) 1) -(check-eq? (last-output-line (run "3,3,1107,-1,8,3,4,3,99" 8)) 0) -(check-eq? (last-output-line (run "3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9" 0)) 0) -(check-eq? (last-output-line (run "3,3,1105,-1,9,1101,0,0,12,4,12,99,1" 0)) 0) +(check-eq? (last-output (run "3,9,8,9,10,9,4,9,99,-1,8" 8)) 1) +(check-eq? (last-output (run "3,9,7,9,10,9,4,9,99,-1,8" 8)) 0) +(check-eq? (last-output (run "3,3,1108,-1,8,3,4,3,99" 8)) 1) +(check-eq? (last-output (run "3,3,1107,-1,8,3,4,3,99" 8)) 0) +(check-eq? (last-output (run "3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9" 0)) 0) +(check-eq? (last-output (run "3,3,1105,-1,9,1101,0,0,12,4,12,99,1" 0)) 0) -(check-eq? - (last-output-line - (run "3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31, -1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104, -999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99" 0)) - 999) -(check-eq? - (last-output-line - (run "3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31, -1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104, -999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99" 8)) - 1000) -(check-eq? - (last-output-line - (run "3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31, -1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104, -999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99" 10)) - 1001) +(let ([str "3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31, + 1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104, + 999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99"]) + (check-eq? (last-output (run str 0)) 999) + (check-eq? (last-output (run str 8)) 1000) + (check-eq? (last-output (run str 10)) 1001)) ;; 2 -(check-eq? - (last-output-line (run (file->string "05.rktd") 5)) - 10376124) \ No newline at end of file +(check-eq? (last-output (run (file->string "05.rktd") 5)) 10376124) \ No newline at end of file