Advent of Code 2020 solutions in Racket, I guess
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
4.2 KiB

#lang racket
(require "lib/common.rkt"
(struct posn (x y) #:transparent)
(define (board-dim board)
(cons (vector-length (vector-ref board 0))
(vector-length board)))
(define (board-set! board x y val)
(vector-set! (vector-ref board y) x val))
(define (board-ref board x y)
(vector-ref (vector-ref board y) x))
(define (board-copy board)
(vector-copy (vector-map vector-copy board)))
(define (parse prt)
(define (get-board-id str)
(match str
[(pregexp "Tile ([0-9]+):" (list _ (app string->number id))) id]
[else (error "oh no")]))
(define boards (string-split (port->string prt) "\n\n"))
(for/hash ([brd (in-list boards)])
(match-define (list (app get-board-id id) lines ...) (string-split brd "\n"))
(values id (list->vector (map (compose1 list->vector string->list) lines)))))
(define (board-edges board)
(match-define (cons m n) (board-dim board))
(list (for/vector ([row (in-vector board)]) ; LEFT
(vector-ref row 0))
(for/vector ([row (in-vector board)]) ; RIGHT
(vector-ref row (sub1 m)))
(vector-ref board 0) ; TOP
(vector-ref board (sub1 n)))) ; BOTTOM
(define (matching-edge? e1 e2)
(cond [(equal? e1 e2) 'match]
[(equal? e1 (vector-reverse e2)) 'rev-match]
[else #f]))
(define/match (edge-num->symbol n)
[(0) 'left]
[(1) 'right]
[(2) 'top]
[(3) 'bottom]
[(_) (error "bad input: edge-num->symbol")])
(define (gen-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)]
[edges1 (in-value (board-edges (hash-ref input id1)))]
[edges2 (in-value (board-edges (hash-ref input id2)))]
[m (in-value (matching-edge? (list-ref edges1 i1) (list-ref edges2 i2)))]
#:when m)
(hash-set! meta
(cons id1 id2)
(list (edge-num->symbol i1) (edge-num->symbol i2) m))
(list id1 id2)))
(values (unweighted-graph/undirected edges) meta))
(define (day20a input)
(define-values (G _) (gen-graph input))
(for/product ([v (in-vertices G)])
(define neighbors (length (get-neighbors G v)))
(if (= neighbors 2) v 1)))
(define (trim-board board)
(match-define (cons m n) (board-dim board))
(for/vector ([y (in-range 1 (sub1 n))])
(for/vector ([x (in-range 1 (sub1 m))])
(board-ref board x y))))
(define (answer-noninteractive answer)
(printf "trying answer: ~s\n" answer)
(unless (aoc-complete? 20 2)
(define resp
(aoc-submit-answer (getenv "AOC_YEAR")
(getenv "AOC_SESSION")
(~a answer)))
(printf "server responded: ~a\n" resp)
(define (day20b input)
(define trimmed-boards (map trim-board (hash-values input)))
(define num-hashes
(for/sum ([b (in-list trimmed-boards)])
(for/sum ([row (in-vector b)])
(vector-count (curry char=? #\#) row))))
(displayln num-hashes)
(let loop ([guess 18] [fn sub1])
(define res (answer-noninteractive (- num-hashes (* 15 guess))))
(cond [(or (eq? res 'answer-correct)
(eq? res 'already-completed))
(displayln "you done it\n")]
[(<= guess 5)
(loop 27 add1)]
[(eq? res 'rate-limited)
(sleep 905)
(loop guess fn)]
(sleep 905)
(loop (fn guess) fn)])))
(module+ main
(call-with-input-file "data/day20.txt"
(λ (prt)
(define input (parse prt))
(answer 20 1 (day20a input))
(day20b input))))
(module+ test
(define (dbg-board board)
(for ([row (in-vector board)])
(displayln (vector->list row)))
(call-with-input-file "data/day20.test.txt"
(λ (prt)
(define input (parse prt))
(dbg-board (trim-board (hash-ref input 2311)))
(for/sum ([b (in-list (map trim-board (hash-values input)))])
(for/sum ([row (in-vector b)])
(vector-count (curry char=? #\#) row)))))))