Day 18: Part 1 second attempt (unsolved).
This commit is contained in:
parent
160655eecc
commit
73494014a7
143
src/18.rkt
143
src/18.rkt
|
@ -1,6 +1,6 @@
|
||||||
#lang racket
|
#lang racket
|
||||||
|
|
||||||
(require data/queue
|
(require data/heap
|
||||||
graph
|
graph
|
||||||
(except-in "../lib.rkt" transpose))
|
(except-in "../lib.rkt" transpose))
|
||||||
|
|
||||||
|
@ -18,7 +18,15 @@
|
||||||
|
|
||||||
(define height
|
(define height
|
||||||
(length list-grid))
|
(length list-grid))
|
||||||
|
|
||||||
|
;; start : (coord . char)
|
||||||
|
;; coord = (list number number)
|
||||||
|
(define start
|
||||||
|
(cons (list (round (/ width 2))
|
||||||
|
(round (/ height 2)))
|
||||||
|
#\@))
|
||||||
|
|
||||||
|
;; get-char : coord -> char
|
||||||
(define (get-char coord)
|
(define (get-char coord)
|
||||||
(match-let ([(list x y) coord])
|
(match-let ([(list x y) coord])
|
||||||
(if (or (< x 0) (< y 0)
|
(if (or (< x 0) (< y 0)
|
||||||
|
@ -27,48 +35,99 @@
|
||||||
#\#
|
#\#
|
||||||
(vector-ref (vector-ref vector-grid y) x))))
|
(vector-ref (vector-ref vector-grid y) x))))
|
||||||
|
|
||||||
|
;; neighbours : coord -> (listof coord)
|
||||||
|
;; If the coordinate is occupiable (by a key, door, or bot),
|
||||||
|
;; return the neighbouring coordinates that are also occupiable
|
||||||
(define (neighbours coord)
|
(define (neighbours coord)
|
||||||
(match-let ([(list x y) coord])
|
(if (char=? #\# (get-char coord)) '()
|
||||||
(let ([U (list x (sub1 y))]
|
(match-let ([(list x y) coord])
|
||||||
[D (list x (add1 y))]
|
(let ([U (list x (sub1 y))]
|
||||||
[L (list (sub1 x) y)]
|
[D (list x (add1 y))]
|
||||||
[R (list (add1 x) y)])
|
[L (list (sub1 x) y)]
|
||||||
(filter-not
|
[R (list (add1 x) y)])
|
||||||
(∘ (∂ char=? #\#) (∂ get-char))
|
(filter-not
|
||||||
(list U D L R)))))
|
(∘ (∂ char=? #\#) (∂ get-char))
|
||||||
|
(list U D L R))))))
|
||||||
|
|
||||||
(define key-door-graph
|
;; graph-grid : unweighted, undirected graph
|
||||||
(let* ([Q (make-queue)]
|
;; Vertices are (coord . char)
|
||||||
[entrance (list (round (/ width 2))
|
;; Edges between traversable coordinates
|
||||||
(round (/ height 2)))]
|
(define graph-grid
|
||||||
[visited (make-hash `((,entrance . #t)))]
|
(let* ([coords (cartesian-product (range 1 (sub1 width))
|
||||||
[graph (weighted-graph/undirected '())])
|
(range 1 (sub1 height)))]
|
||||||
(enqueue! Q (list entrance #\@ 0))
|
[graph (unweighted-graph/undirected '())])
|
||||||
(let loop ()
|
(for-each
|
||||||
(if (queue-empty? Q)
|
(λ (coord)
|
||||||
graph
|
(let ([ncoords (neighbours coord)])
|
||||||
(match-let* ([(list coord prev dist) (dequeue! Q)]
|
(for-each
|
||||||
[ncoords (neighbours coord)])
|
(λ (ncoord)
|
||||||
(for-each
|
(add-edge! graph
|
||||||
(λ (ncoord)
|
(cons coord (get-char coord))
|
||||||
(let ([nc (get-char ncoord)])
|
(cons ncoord (get-char ncoord))))
|
||||||
(cond
|
ncoords)))
|
||||||
[(hash-ref visited ncoord #f)]
|
coords)
|
||||||
[(char=? #\. nc)
|
graph))
|
||||||
(hash-set! visited ncoord #t)
|
|
||||||
(enqueue! Q (list ncoord prev (add1 dist)))]
|
|
||||||
[else
|
|
||||||
(hash-set! visited ncoord #t)
|
|
||||||
(enqueue! Q (list ncoord nc 0))
|
|
||||||
(add-edge! graph prev nc (add1 dist))])))
|
|
||||||
ncoords)
|
|
||||||
(loop))))))
|
|
||||||
|
|
||||||
(define ordered-keys
|
;; keys : (listof (coord . char))
|
||||||
(let ([keys (filter char-lower-case? (get-vertices key-door-graph))])
|
;; Pairs of keys and their coordinates, including #\@
|
||||||
(displayln keys)
|
(define keys
|
||||||
(define (sort-fn c1 c2)
|
(let ([coords (cartesian-product (range 1 (sub1 width))
|
||||||
(not (member (char-upcase c2) (fewest-vertices-path key-door-graph #\@ c1))))
|
(range 1 (sub1 height)))])
|
||||||
(sort keys sort-fn)))
|
(foldl (λ (coord keys)
|
||||||
|
(let ([char (get-char coord)])
|
||||||
|
(if (or (char=? #\@ char)
|
||||||
|
(char-lower-case? char))
|
||||||
|
(cons (cons coord char) keys)
|
||||||
|
keys)))
|
||||||
|
'() coords)))
|
||||||
|
|
||||||
|
;; doors : (hashof (char => (listof char)))
|
||||||
|
;; A hashmap from keys to the list of keys for the doors
|
||||||
|
;; that stand between the starting point #\@ and that key
|
||||||
|
(define doors-hash
|
||||||
|
(let ([hash (make-hash)])
|
||||||
|
(for ([key keys])
|
||||||
|
(let ([path (fewest-vertices-path graph-grid start key)])
|
||||||
|
(hash-set! hash (cdr key)
|
||||||
|
(filter-map
|
||||||
|
(λ (v)
|
||||||
|
(if (char-upper-case? (cdr v))
|
||||||
|
(char-downcase (cdr v))
|
||||||
|
#f))
|
||||||
|
path))))
|
||||||
|
hash))
|
||||||
|
|
||||||
|
;; key-graph : weighted, undirected graph
|
||||||
|
;; Vertices are char (keys)
|
||||||
|
;; Edges between neighbouring keys
|
||||||
|
;; Weights are distances between keys
|
||||||
|
(define key-graph
|
||||||
|
(let ([graph (weighted-graph/undirected '())]
|
||||||
|
[key-pairs (combinations keys 2)])
|
||||||
|
(for ([pair key-pairs])
|
||||||
|
(match-let* ([(list key1 key2) pair]
|
||||||
|
[path (fewest-vertices-path graph-grid key1 key2)]
|
||||||
|
[distance (sub1 (length path))])
|
||||||
|
(add-edge! graph (cdr key1) (cdr key2) distance)))
|
||||||
|
graph))
|
||||||
|
|
||||||
|
(define (search)
|
||||||
|
(let ([heap (make-heap (λ (v1 v2) (< (last v1) (last v2))))])
|
||||||
|
(heap-add! heap (list #\@ (make-immutable-hash '((#\@ . #t))) 0))
|
||||||
|
(match-let loop ([(list key hash count) (heap-min heap)])
|
||||||
|
(heap-remove-min! heap)
|
||||||
|
(if (= (hash-count hash) (length keys))
|
||||||
|
count
|
||||||
|
(let* ([visitable
|
||||||
|
(filter (λ (nkey)
|
||||||
|
(and (not (hash-has-key? hash nkey))
|
||||||
|
(andmap (∂ hash-has-key? hash) (hash-ref doors-hash nkey))))
|
||||||
|
(get-neighbors key-graph key))])
|
||||||
|
(for ([nkey visitable])
|
||||||
|
(heap-add! heap
|
||||||
|
(list nkey
|
||||||
|
(hash-set hash nkey #t)
|
||||||
|
(+ count (edge-weight key-graph key nkey)))))
|
||||||
|
(loop (heap-min heap)))))))
|
||||||
|
|
||||||
#;(for-each displayln (map (λ (s) (string-replace (string-replace s "#" "█") "." " ")) input))
|
#;(for-each displayln (map (λ (s) (string-replace (string-replace s "#" "█") "." " ")) input))
|
Loading…
Reference in New Issue