#lang br (require racket/file rackunit) (define (string->ints str) (map string->number (string-split str #px",\\s*"))) (define (string->regs str) (list->vector (string->ints str))) (define ((binarize proc) x y) (if (proc x y) 1 0)) (define (make-runner program [calling-thd (current-thread)]) (thread (λ () (define regs (string->regs program)) (define (maybe-enlarge-regs ptr) (unless (< ptr (vector-length regs)) (define newvec (make-vector (add1 ptr) 0)) (vector-copy! newvec 0 regs) (set! regs newvec)) regs) (define (reg-ref ptr) (vector-ref (maybe-enlarge-regs ptr) ptr)) (define (reg-set! ptr val) (vector-set! (maybe-enlarge-regs ptr) ptr val)) (define relative-base 0) (let/ec terminate (let loop ([ptr 0]) (define inst (for/list ([c (in-string (~r (reg-ref ptr) #:min-width 5 #:pad-string "0"))]) (string->number (string c)))) (define-values (opcode resolve) (match inst [(list d4 d3 d2 d1 d0) (values (+ (* 10 d1) d0) (λ (ptr offset) (define parameter-value (match offset [1 d2] [2 d3] [3 d4])) (define ptr-resolver (match parameter-value [0 reg-ref] ; position [1 values] ; immediate [2 (compose1 (λ (ptr) (+ relative-base ptr)) reg-ref)])); relative (ptr-resolver (+ ptr offset))))])) (define next-ptr (match opcode [(or 1 2 7 8) ; 4-arity: add & multiply & compare (reg-set! (resolve ptr 3) ((match opcode [1 +] [2 *] [7 (binarize <)] [8 (binarize =)]) (reg-ref (resolve ptr 1)) (reg-ref (resolve ptr 2)))) (+ ptr 4)] [(or 3 4 9) ; 2-arity: input & output (match opcode [3 (reg-set! (resolve ptr 1) (thread-receive))] [4 (thread-send calling-thd (reg-ref (resolve ptr 1)))] [9 (set! relative-base (+ relative-base (reg-ref (resolve ptr 1))))]) (+ ptr 2)] [(or 5 6) ; 3-arity: jump (if ((match opcode [5 not] [6 values]) (zero? (reg-ref (resolve ptr 1)))) (reg-ref (resolve ptr 2)) (+ ptr 3))] [99 (thread-send calling-thd 'done) (terminate)] [_ (error "unknown opcode" opcode)])) (loop next-ptr)))))) (define black 0) (define white 1) (define left +i) (define right -i) (define (paint-panels #:start initial-color) (define robot-program (make-runner (file->string "11.rktd"))) (define panels (make-hasheqv)) (let loop ([pos 0][dir +i]) (when (thread-running? robot-program) (thread-send robot-program (hash-ref panels pos initial-color))) (match (thread-receive) ['done panels] [new-color (hash-set! panels pos new-color) (define turn (match (thread-receive) [0 left] [1 right])) (define new-dir (* turn dir)) (define new-pos (+ pos new-dir)) (loop new-pos new-dir)]))) ;; 1 (check-eq? (length (hash-keys (paint-panels #:start black))) 2478) ;; 2 (define white-panels (for/list ([(loc color) (in-hash (paint-panels #:start white))] #:when (eqv? color white)) loc)) (define rows (sort (group-by imag-part white-panels) > #:key (compose1 imag-part car))) (define (make-printable row) (define real-parts (map real-part row)) (string-join (for/list ([i (in-range (add1 (apply max real-parts)))]) (if (memq i real-parts) "X" " ")) "")) ;; 2 (define painted-rows (map make-printable rows)) (check-equal? painted-rows '(" X X XX XXXX XXX X X XX XX XXXX" " X X X X X X X X X X X X X X" " XXXX X X X X X X X X X X" " X X X X XXX X X X XX XXXX X" " X X X X X X X X X X X X X X" " X X XX XXXX X X XX XXX X X XXXX")) (for-each displayln painted-rows)