diff --git a/aoc-racket.scrbl b/aoc-racket.scrbl index 87dbc89..60ffe33 100644 --- a/aoc-racket.scrbl +++ b/aoc-racket.scrbl @@ -43,4 +43,4 @@ You can install this package (if you haven't already) with @include-section[(submod "day20.rkt" doc)] @include-section[(submod "day21.rkt" doc)] @include-section[(submod "day22.rkt" doc)] -@include-section[(submod "day23.rkt" doc)] \ No newline at end of file +@;include-section[(submod "day23.rkt" doc)] \ No newline at end of file diff --git a/day23.scrbl b/day23.scrbl index a78ed51..5182f4c 100644 --- a/day23.scrbl +++ b/day23.scrbl @@ -16,18 +16,74 @@ @section{What's the value in register @tt{b} after the program runs?} +The virtual machine has two registers, @tt{a} and @tt{b}, that both start at 0. It also has six instructions: + +@itemlist[ + + @item{@tt{hlf r} sets register r to half its current value, then continues.} + @item{@tt{tpl r} sets register r to triple its current value, then continues.} + @item{@tt{inc r} adds 1 to register r, then continues.} + @item{@tt{jmp offset} jumps the instruction that is @tt{offset} steps away. An @tt{offset} can be positive or negative.} + @item{@tt{jie r, offset} is like @tt{jmp}, but only jumps if r is even.} + @item{@tt{jio r, offset} jumps by @tt{offset} if register r = 1.} + ] + +Although the virtual machine has the equivalent of functions & variables, the jump instructions add a complication. We can't just evaluate the instructions top to bottom. We have to maintain a list of all the instructions, and a pointer to where we are, so if we get a jump instruction, we can move to the right place. + +Because we have to repeatedly update the values of the register, it'll be more convenient to use a hash table (which is designed for this purpose). @chunk[ (require racket rackunit) (provide (all-defined-out)) - - + (define registers (make-hash '((a . 0)(b . 0)))) + + (define-syntax-rule (define-reg-updater id thunk) + (define (id reg) + (hash-update! registers reg thunk))) + + (define-reg-updater tpl (λ(val) (* 3 val))) + (define-reg-updater inc (λ(val) (add1 val))) + (define-reg-updater hlf (λ(val) (/ val 2))) + + (define (jmpf reg num pred) + (if (pred (hash-ref registers reg)) num 1)) + + (define-syntax (ins stx) + (syntax-case stx (jmp jio jie) + [(_ jio reg num) + #'(jmpf 'reg num (λ(x) (= 1 x)))] + [(_ jie reg num) + #'(jmpf 'reg num even?)] + [(_ jmp num) + #'num] + [(_ op reg) + #'(op 'reg)] + [else #'(void)])) + + (define-syntax (parse-instructions stx) + (syntax-case stx () + [(_ input-str) + #'(let* ([str (string-replace input-str "," "")] + [lines (string-split str "\n")] + [datums) + 42)])) + ] @chunk[ (define (q1 input-str) + (define instructions (parse-instructions input-str)) + (let eval-instruction ([idx 0]) + (if (>= idx (length instructions)) + (hash-ref registers 'b) + (let* ([inst (list-ref instructions idx)] + [result (inst)] + [next-idx (+ (if (number? result) + result + 1) idx)]) + (eval-instruction next-idx)))) 184)]