Compare commits

...

2 Commits

Author SHA1 Message Date
ea9e5b7167 indentation 2021-12-12 20:37:37 +01:00
6a0df03604 day 12 part 2 2021-12-12 20:36:33 +01:00

View File

@@ -1,5 +1,7 @@
(load "../common.scm") (load "../common.scm")
; graphs in this code are represented by hashtables of node names to list of node names
; splits string into two at first separator character encountered ; splits string into two at first separator character encountered
; returns #f if there is given separator is not present ; returns #f if there is given separator is not present
(define (split-string str separator) (define (split-string str separator)
@@ -12,7 +14,8 @@
(substring str (+ i 1) len)) (substring str (+ i 1) len))
(loop (+ i 1))))))) (loop (+ i 1)))))))
(define (add-edge nodes start end) ; add a directed edge to given graph
(define (add-edge! nodes start end)
(hashtable-update! nodes start (hashtable-update! nodes start
(lambda (node) (lambda (node)
(if (member end node) (if (member end node)
@@ -20,6 +23,7 @@
(cons end node))) (cons end node)))
'())) '()))
; build graph from edges defined in a file
(define (make-graph file) (define (make-graph file)
(let [(lines (get-lines file)) (let [(lines (get-lines file))
(nodes (make-hashtable string-hash string=? 20))] (nodes (make-hashtable string-hash string=? 20))]
@@ -28,37 +32,77 @@
(let [(edge (split-string line #\-))] (let [(edge (split-string line #\-))]
(let [(start (car edge)) (let [(start (car edge))
(end (cadr edge))] (end (cadr edge))]
(add-edge nodes start end) (add-edge! nodes start end)
(add-edge nodes end start)))) (add-edge! nodes end start))))
lines) lines)
nodes)) nodes))
; big caves are uppercase nodes
(define (is-big? node) (define (is-big? node)
(char-upper-case? (string-ref node 0))) (char-upper-case? (string-ref node 0)))
(define (find-paths graph) ; count how many obj there is in lst
(let [(paths '())] (define (count-members obj lst)
(let count [(n 0) (lst lst)]
(let [(sub (member obj lst))]
(if sub
(count (+ n 1) (cdr sub))
n))))
; calls visitor for all possible paths in graph
; with max-small = 1, visits small caves at most once
; with max-small = 2, visits one small cave at most twice and others at most once
; with max-small >= 3 or 0, probably garbage
(define (visit-paths graph max-small visitor)
(let visit [(node "start") (let visit [(node "start")
(path '()) (path '())
(visited-small '())] (max-small max-small)]
(assert (< (length visited-small) 20))
(if (string=? node "end") (if (string=? node "end")
(set! paths (cons (cons node path) paths)) (visitor (cons node path))
(for-each (for-each
(lambda (child) (lambda (child)
(when (or (is-big? child) (let [(is-big (is-big? child))]
(not (member child visited-small))) (when (and (not (string=? child "start"))
(visit child (or is-big
(cons node path) (< (count-members child path) max-small)))
(if (is-big? node) (visit child (cons node path)
visited-small (if (and (not is-big) (member child path)) 1 max-small)))))
(cons node visited-small))))) (hashtable-ref graph node '())))))
(hashtable-ref graph node '()))))
paths)) ; computes how many possible paths there are in graph
(define (count-paths graph max-small)
(let [(count 0)]
(visit-paths graph max-small
(lambda (path)
(set! count (+ 1 count))))
count))
; print all possible paths
(define (print-paths graph max-small)
(visit-paths graph max-small
(lambda (path)
(printf "~a~%" (reverse path)))))
;(let [(nodes (make-hashtable string-hash string=? 20))]
; (define (add-2! s e)
; (add-edge! nodes s e)
; (add-edge! nodes e s))
; (add-2! "start" "A")
; (add-2! "start" "b")
; (add-2! "A" "c")
; (add-2! "A" "b")
; (add-2! "b" "d")
; (add-2! "A" "end")
; (add-2! "b" "end")
; (printf "~a of them at 1 small~%" (count-paths nodes 1))
; (printf "~a of them at one 2 small~%" (count-paths nodes 2))
; (print-paths nodes 2))
(call-with-input-file (call-with-input-file
"input" "input"
(lambda (file) (lambda (file)
(let [(graph (make-graph file))] (let [(graph (make-graph file))]
(printf "part 1:~% ~a paths with at most 1 visit to small caves.~%" (printf "part 1:~% ~a paths with at most 1 visit to small caves.~%"
(length (find-paths graph)))))) (count-paths graph 1))
(printf "part 2:~% ~a paths with at most 2 visits to small caves.~%"
(count-paths graph 2)))))