diff --git a/20.rkt b/20.rkt new file mode 100644 index 0000000..15c4a4d --- /dev/null +++ b/20.rkt @@ -0,0 +1,212 @@ +#lang curly-fn racket + +(require "scripts/aoc.rkt") + +;; solution for day 20 + +(define (tile->edges tile) + (define n (for/vector ([x (in-range 10)]) + (vector-ref (vector-ref tile 0) x))) + (define e (for/vector ([x (in-range 10)]) + (vector-ref (vector-ref tile x) 9))) + (define s (for/vector ([x (in-range 10)]) + (vector-ref (vector-ref tile 9) x))) + (define w (for/vector ([x (in-range 10)]) + (vector-ref (vector-ref tile x) 0))) + (list e s w n)) + +(define (edge-match? e1 e2) + (cond + [(equal? e1 e2) 'match] + [(equal? e1 (list->vector (reverse (vector->list e2)))) 'rev-match] + [else #f])) + +(define (input->graph input) + (define ids (hash-keys input)) + (define meta (make-hash)) + (define edges + (for*/list ([id1 (in-list ids)] [id2 (in-list ids)] #:unless (= id1 id2) + [i1 (in-range 4)] [i2 (in-range 4)] + [es1 (in-value (tile->edges (hash-ref input id1)))] + [es2 (in-value (tile->edges (hash-ref input id2)))] + [m (in-value (edge-match? (list-ref es1 i1) (list-ref es2 i2)))] + #:when m) + (hash-set! meta (cons id1 id2) (list i1 i2 m)) + (list id1 id2))) + (values (undirected-graph edges) meta)) + +(define (part1 input) + (define-values [G _] (input->graph input)) + (for/product ([v (in-vertices G)]) + (define nneigh (length (get-neighbors G v))) + (if (= nneigh 2) v 1))) + +(define (tile->string tile) + (string-join (for/list ([x (in-vector tile)]) (list->string (vector->list x))) "\n")) + +(define (rotate1 vec) + (for/vector ([x (in-range (vector-length (vector-ref vec 0)))]) + (for/vector ([y (in-range (vector-length vec))]) + (vector-ref (vector-ref vec (- (vector-length vec) y 1)) x)))) + +(define (rotaten vec n) + (for/fold ([vec vec]) ([i (in-range n)]) + (rotate1 vec))) + +(define (flip-horiz vec) + (for/vector ([y (in-range (vector-length vec))]) + (for/vector ([x (in-range (vector-length (vector-ref vec 0)))]) + (vector-ref (vector-ref vec y) (- (vector-length (vector-ref vec 0)) x 1))))) + +(define (flip-vert vec) + (for/vector ([y (in-range (vector-length vec))]) + (for/vector ([x (in-range (vector-length (vector-ref vec 0)))]) + (vector-ref (vector-ref vec (- (vector-length vec) y 1)) x)))) + +(define monster-in + '(" # " + "# ## ## ###" + " # # # # # # ")) +(define monster + (for/vector ([line (in-list monster-in)]) + (list->vector (string->list line)))) + +(define (part2 input) + (define-values [G meta] (input->graph input)) + (define corners + (for/list ([v (in-vertices G)] #:when (= 2 (length (get-neighbors G v)))) v)) + (define rows (make-vector 12 #f)) + (define used-verts (mutable-set)) + (define nextrow (for*/first ([cand (in-list (rest corners))] + [path (in-value (fewest-vertices-path G (first corners) cand))] + #:when (= 12 (length path))) + path)) + (vector-set! rows 0 (list->vector nextrow)) + (set-union! used-verts (list->set nextrow)) + (for ([i (in-range 1 12)]) + (define l (first nextrow)) + (define r (last nextrow)) + (define lnext (for/first ([v (in-neighbors G l)] #:unless (set-member? used-verts v)) v)) + (define rnext (for/first ([v (in-neighbors G r)] #:unless (set-member? used-verts v)) v)) + (set! nextrow (fewest-vertices-path G lnext rnext)) + (vector-set! rows i (list->vector nextrow)) + (set-union! used-verts (list->set nextrow))) + (pretty-write rows) + (displayln (hash-ref meta (cons (vector-ref (vector-ref rows 0) 0) + (vector-ref (vector-ref rows 0) 1)))) + (displayln (hash-ref meta (cons (vector-ref (vector-ref rows 0) 0) + (vector-ref (vector-ref rows 1) 0)))) + (define corrected (make-hash)) + (define tl (vector-ref (vector-ref rows 0) 0)) + ;; assume top left is oriented right... + ;; we tuned the parse to make it so + (hash-set! corrected tl (hash-ref input tl)) + (displayln (tile->string (hash-ref input tl))) + (displayln "meow") + (for ([x (in-range 1 12)]) + (define v (vector-ref (vector-ref rows 0) x)) + (define left (vector-ref (vector-ref rows 0) (sub1 x))) + (match-define (list rot _ __) (hash-ref meta (cons v left))) + (define rotated (rotaten (hash-ref input v) (match rot + [2 0] + [3 3] + [0 2] + [1 1]))) + (define mt (edge-match? (first (tile->edges (hash-ref corrected left))) + (third (tile->edges rotated)))) + (define flipped (if (symbol=? mt 'match) rotated (flip-vert rotated))) + (hash-set! corrected v flipped) + ; (displayln (tile->string flipped)) + ; (displayln "meow") + (void)) + + (for* ([y (in-range 1 12)] [x (in-range 0 12)]) + (define v (vector-ref (vector-ref rows y) x)) + (define top (vector-ref (vector-ref rows (sub1 y)) x)) + (match-define (list rot _ __) (hash-ref meta (cons v top))) + (define rotated (rotaten (hash-ref input v) (match rot + [0 3] + [1 2] + [2 1] + [3 0]))) + (define mt (edge-match? (second (tile->edges (hash-ref corrected top))) + (fourth (tile->edges rotated)))) + (define flipped (if (symbol=? mt 'match) rotated (flip-horiz rotated))) + (hash-set! corrected v flipped) + ; (displayln (tile->string flipped)) + ; (dispalyln "meow") + (void)) + + ; (for* ([yt (in-range 12)] [yc (in-range 10)]) + ; (when (zero? yc) (printf "\n")) + ; (displayln (string-join (for/list ([xt (in-range 12)]) + ; (list->string + ; (vector->list + ; (vector-ref + ; (hash-ref corrected + ; (vector-ref (vector-ref rows yt) xt)) + ; yc)))) + ; " "))) + + (define full-image + (for/vector ([y (in-range 96)]) + (for/vector ([x (in-range 96)]) + (define yt (quotient y 8)) + (define xt (quotient x 8)) + (define yr (remainder y 8)) + (define xr (remainder x 8)) + (define tile (hash-ref corrected (vector-ref (vector-ref rows yt) xt))) + (vector-ref (vector-ref tile (add1 yr)) (add1 xr))))) + + (define (monster-match? check x y) + (define coords (mutable-set)) + + (define match? + (for*/and ([dy (in-range (vector-length check))] + [dx (in-range (vector-length (vector-ref check 0)))]) + (cond + [(char=? #\space (vector-ref (vector-ref check dy) dx)) #t] + [(char=? #\# (vector-ref (vector-ref full-image (+ y dy)) (+ x dx))) + (set-add! coords (cons (+ x dx) (+ y dy))) + #t] + [else #f]))) + (if match? coords #f)) + + (define monster-coords (mutable-set)) + (for* ([func (in-list (list identity flip-vert))] + [rotation (in-range 4)]) + (define check (func (rotaten monster rotation))) + (for* ([y (in-range (- 96 (vector-length check)))] + [x (in-range (- 96 (vector-length (vector-ref check 0))))]) + (define match? (monster-match? check x y)) + (when match? + (set-union! monster-coords match?)))) + + (define hashcount (for*/sum ([y (in-range 96)] [x (in-range 96)] + #:when (char=? (vector-ref (vector-ref full-image y) x) #\#)) + 1)) + + + (- hashcount (set-count monster-coords))) + +;; parse input file +(define (parse fname) + (define inputs (string-split (file->string fname) "\n\n")) + (for/hash ([input (in-list inputs)]) + (define lines (string-split input "\n")) + (define id (string->number (substring (first lines) 5 (sub1 (string-length (first lines)))))) + (when (false? id) (error "not shonks" (first lines))) + (values id (rotate1 (for/vector ([line (in-list (rest lines))]) + (list->vector (string->list line))))))) + + +(module+ test + (require rackunit) + ;; tests here + (displayln "no tests :(")) + +(module+ main + (define input (parse "inputs/20")) + (answer 20 1 (time (part1 input))) + (answer 20 2 (time (part2 input))) + (displayln "meow")) diff --git a/README.md b/README.md index 74eb608..8aa9e06 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ sharks third party packages used so far - `curly-fn` and `threading`: all - `graph`: day 7 + + - `brag`: day 19 ## a guide to this repo