Compare commits
2 Commits
7662c00cf9
...
ea9e5b7167
| Author | SHA1 | Date | |
|---|---|---|---|
| ea9e5b7167 | |||
| 6a0df03604 |
@@ -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 visit [(node "start")
|
(let count [(n 0) (lst lst)]
|
||||||
(path '())
|
(let [(sub (member obj lst))]
|
||||||
(visited-small '())]
|
(if sub
|
||||||
(assert (< (length visited-small) 20))
|
(count (+ n 1) (cdr sub))
|
||||||
(if (string=? node "end")
|
n))))
|
||||||
(set! paths (cons (cons node path) paths))
|
|
||||||
(for-each
|
; calls visitor for all possible paths in graph
|
||||||
(lambda (child)
|
; with max-small = 1, visits small caves at most once
|
||||||
(when (or (is-big? child)
|
; with max-small = 2, visits one small cave at most twice and others at most once
|
||||||
(not (member child visited-small)))
|
; with max-small >= 3 or 0, probably garbage
|
||||||
(visit child
|
(define (visit-paths graph max-small visitor)
|
||||||
(cons node path)
|
(let visit [(node "start")
|
||||||
(if (is-big? node)
|
(path '())
|
||||||
visited-small
|
(max-small max-small)]
|
||||||
(cons node visited-small)))))
|
(if (string=? node "end")
|
||||||
(hashtable-ref graph node '()))))
|
(visitor (cons node path))
|
||||||
paths))
|
(for-each
|
||||||
|
(lambda (child)
|
||||||
|
(let [(is-big (is-big? child))]
|
||||||
|
(when (and (not (string=? child "start"))
|
||||||
|
(or is-big
|
||||||
|
(< (count-members child path) max-small)))
|
||||||
|
(visit child (cons node path)
|
||||||
|
(if (and (not is-big) (member child path)) 1 max-small)))))
|
||||||
|
(hashtable-ref graph node '())))))
|
||||||
|
|
||||||
|
; 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)))))
|
||||||
|
|||||||
Reference in New Issue
Block a user