2020-12-08 05:17:32 +00:00
|
|
|
#lang curly-fn racket
|
|
|
|
|
|
|
|
(require "scripts/aoc.rkt")
|
|
|
|
|
|
|
|
;; solution for day 8
|
|
|
|
|
|
|
|
(struct insn [type arg] #:transparent)
|
|
|
|
|
|
|
|
;; helper functions here
|
|
|
|
|
2020-12-08 05:26:18 +00:00
|
|
|
(define (execute-program prg)
|
2020-12-08 05:17:32 +00:00
|
|
|
(define (execute pc acc [seen (mutable-set)])
|
2020-12-08 05:26:18 +00:00
|
|
|
(cond
|
|
|
|
[(set-member? seen pc) (cons 'loop acc)]
|
|
|
|
[(>= pc (vector-length prg)) (cons 'done acc)]
|
|
|
|
[else
|
|
|
|
(match-define (insn type arg) (vector-ref prg pc))
|
|
|
|
(set-add! seen pc)
|
|
|
|
(match type
|
|
|
|
["nop" (execute (add1 pc) acc seen)]
|
|
|
|
["jmp" (execute (+ pc arg) acc seen)]
|
|
|
|
["acc" (execute (add1 pc) (+ acc arg) seen)])]))
|
2020-12-08 05:17:32 +00:00
|
|
|
(execute 0 0))
|
|
|
|
|
2020-12-08 05:26:18 +00:00
|
|
|
(define (part1 input)
|
|
|
|
(cdr (execute-program input)))
|
2020-12-08 05:17:32 +00:00
|
|
|
|
2020-12-08 05:26:18 +00:00
|
|
|
(define (part2 input)
|
2020-12-08 08:18:07 +00:00
|
|
|
(define target-pc (vector-length input))
|
|
|
|
;; create naive CFG (as list of edges)
|
|
|
|
(define model/list
|
|
|
|
(for/list ([i (in-naturals)] [ins (in-vector input)])
|
|
|
|
(match-define (insn type arg) ins)
|
|
|
|
(match type
|
|
|
|
[(or "nop" "acc") (list i (add1 i))]
|
|
|
|
["jmp" (list i (+ i arg))])))
|
|
|
|
;; detect connected components of unweighted CFG
|
|
|
|
(define ccs (map list->set (cc (undirected-graph model/list))))
|
|
|
|
;; find which components we need to connect
|
|
|
|
(define to-cc (for/first ([cc (in-list ccs)] #:when (set-member? cc target-pc)) cc))
|
|
|
|
;; execute the program, but bail as soon as there's a way to to-cc
|
|
|
|
(define (execute/graph G [v 0] [acc 0] [changed? #f])
|
|
|
|
(cond
|
|
|
|
;; done!
|
|
|
|
[(= target-pc v) acc]
|
|
|
|
;; not done, yet....
|
|
|
|
[else
|
|
|
|
;; fetch instruction
|
|
|
|
(match-define (insn type arg) (vector-ref input v))
|
|
|
|
;; determine the "alternate target" if this instruction were mutated
|
|
|
|
(define alt-target (match type
|
|
|
|
["nop" (+ v arg)]
|
|
|
|
["jmp" (add1 v)]
|
|
|
|
["acc" #f]))
|
|
|
|
;; calculate new accumulator
|
|
|
|
(define new-acc (if (string=? type "acc") (+ acc arg) acc))
|
|
|
|
;; if we haven't mutated an instruction yet, and alt-target goes into to-cc, use it
|
|
|
|
(if (and (not changed?) alt-target (set-member? to-cc alt-target))
|
|
|
|
(execute/graph G alt-target new-acc #t)
|
|
|
|
(execute/graph G (first (get-neighbors G v)) new-acc changed?))]))
|
|
|
|
(execute/graph (directed-graph model/list)))
|
2020-12-08 05:17:32 +00:00
|
|
|
|
|
|
|
(module+ main
|
|
|
|
(define input
|
2020-12-08 05:26:18 +00:00
|
|
|
(for/vector ([line (in-list (file->lines "inputs/8"))])
|
2020-12-08 05:17:32 +00:00
|
|
|
(match (string-split line)
|
|
|
|
[(list a b) (insn a (string->number b))]
|
|
|
|
[x (error "not shonks" x)])))
|
2020-12-08 05:26:18 +00:00
|
|
|
|
2020-12-08 05:17:32 +00:00
|
|
|
;; part 1
|
|
|
|
(answer 8 1 (part1 input))
|
|
|
|
|
|
|
|
;; part 2
|
|
|
|
(answer 8 2 (part2 input))
|
|
|
|
|
|
|
|
(displayln "meow"))
|