103 lines
2.3 KiB
Scheme
103 lines
2.3 KiB
Scheme
(load "../common.scm")
|
|
|
|
; check if character can close chunk
|
|
(define (closing? c)
|
|
(case c
|
|
(#\) #t)
|
|
(#\} #t)
|
|
(#\] #t)
|
|
(#\> #t)
|
|
(else #f)))
|
|
|
|
; check if character can close chunk starting by o
|
|
(define (is-closed-by? o c)
|
|
(or (and (char=? o #\<) (char=? c #\>))
|
|
(and (char=? o #\{) (char=? c #\}))
|
|
(and (char=? o #\() (char=? c #\)))
|
|
(and (char=? o #\[) (char=? c #\]))))
|
|
|
|
; return character needed to close chunk started by o
|
|
(define (close o)
|
|
(case o
|
|
(#\( #\))
|
|
(#\{ #\})
|
|
(#\[ #\])
|
|
(#\< #\>)
|
|
(else #f)))
|
|
|
|
; if given line is corrupt, returns expected character
|
|
(define (corrupt-char? line)
|
|
(let loop [(i 0)]
|
|
(if (< i (string-length line))
|
|
(let [(c (string-ref line i))]
|
|
(if (closing? c)
|
|
i
|
|
(let [(close-index (loop (+ i 1)))]
|
|
(if (number? close-index)
|
|
(let [(d (string-ref line close-index))]
|
|
(if (is-closed-by? c d)
|
|
(loop (+ close-index 1))
|
|
d))
|
|
close-index))))
|
|
#t)))
|
|
|
|
; compute score after syntax checking all given lines
|
|
(define (score-illegal-lines lines)
|
|
(fold-left
|
|
(lambda (score line)
|
|
(+ score
|
|
(case (corrupt-char? line)
|
|
(#\) 3)
|
|
(#\] 57)
|
|
(#\} 1197)
|
|
(#\> 25137)
|
|
(else 0))))
|
|
0 lines))
|
|
|
|
; returns #t if line is corrupt
|
|
(define (corrupt? line)
|
|
(char? (corrupt-char? line)))
|
|
|
|
(define (not-corrupt? line)
|
|
(not (corrupt? line)))
|
|
|
|
; returns list of characters needed to autocomplete the given line
|
|
(define (complete incomplete-line)
|
|
(let [(stack '())]
|
|
(string-for-each
|
|
(lambda (c)
|
|
(if (closing? c)
|
|
(set! stack (cdr stack))
|
|
(set! stack (cons c stack))))
|
|
incomplete-line)
|
|
(map close stack)))
|
|
|
|
; returns auto complete score applied to incomplete lines of input
|
|
(define (score-autocomplete lines)
|
|
(define (score completion)
|
|
(fold-left
|
|
(lambda (s c)
|
|
(+ (* s 5)
|
|
(case c
|
|
(#\) 1)
|
|
(#\] 2)
|
|
(#\} 3)
|
|
(#\> 4))))
|
|
0 completion))
|
|
(let [(scores (sort <
|
|
(map score
|
|
(map complete
|
|
(filter not-corrupt? lines)))))]
|
|
(list-ref scores (div (length scores) 2))))
|
|
|
|
(call-with-input-file
|
|
"input"
|
|
(lambda (file)
|
|
(let [(lines (get-lines file))]
|
|
(printf "part 1:~% Illegal lines score = ~a~%"
|
|
(score-illegal-lines lines))
|
|
(printf "part 2:~% Completed lines score = ~a~%"
|
|
(score-autocomplete lines)))))
|
|
|
|
|