AoC '21, day 10, second problem rvc


If a string of groupings is not in error, it may be incomplete, containing group opening characters with no matching closing character. For each such incomplete string, find the suffix that correctly closes the open groups, compute a score for each suffix, and return the median value of all such scores.

 $ cat 10b.rkt  
 #lang racket 
  
  
 (require "10a.rkt" "aoc.rkt") 
  
  
 (define (aoc10b . args) 
  
   ; Return the median nav-sys completion score for the second 
   ; half of the tenth AoC '21 problem.  If no argument is given, 
   ; use the contest problem input; otherwise assume the argument 
   ; is the string representation of a problem input. 
  
   (median-completion-score (apply read-input args))) 
  
  
 (define line-open-groups 
  
   ; Return the list of open groups for the given nav-system line. 
   ; The groups are returned in right-to-left order, that is, 
   ; right-most open group first and left-most open group last. 
  
   (let* 
  
     ((group-close (make-hash 
        '((#\( . #\)) (#\[ . #\]) (#\{ . #\}) (#\< . #\>)))) 
         
      (push (lambda (s e) (cons e s))) 
      (pop cdr) 
      (top car) 
         
      (is-group-open? (lambda (c) (member c '(#\( #\[ #\{ #\<)))) 
      (closes-group? (lambda (g c) 
        (and (not (null? g)) 
             (char=? (hash-ref group-close (top g)) c))))) 
  
     (lambda (nav-sys-line) 
       (let loop ((nsl nav-sys-line) (open-groups '())) 
         (if (null? nsl) 
  
           open-groups 
  
           (let 
  
             ((e (car nsl)) 
              (nsl (cdr nsl))) 
  
             (cond 
  
              ((is-group-open? e) 
                 (loop nsl (push open-groups e))) 
  
              ((closes-group? open-groups e) 
                 (loop nsl (pop open-groups))) 
  
              (#t 
                 '())))))))) 
  
  
 (define median-completion-score 
  
   ; Return the median completion score for the given nav system. 
    
   (let* 
  
     ((completion-scores (make-hash 
        '((#\( . 1) (#\[ . 2) (#\{ . 3) (#\< . 4)))) 
      (c-score (lambda (c) (hash-ref completion-scores c))) 
  
      (completion-score (lambda (l)  
        (foldl (lambda (c s) (+ (* s 5) (c-score c)) 0 l)))) 
      (median (lambda (l) 
        (car (drop (sort l <) (floor (/ (length l) 2)))))) 
      (non-null? (lambda (l) (not (null? l))))) 
  
     (lambda (nav-sys) 
       (median 
         (map completion-score 
              (filter non-null? (map line-open-groups nav-sys))))))) 
  
  
 (module+ main 
  
   (aoc10b) 
   ) 
  
  
 (define example-output 288957) 
  
  
 (module+ test 
  
   (require rackunit) 
  
   (for-each 
    (lambda (p) 
      (check-equal? 
        (median-completion-score (read-input (car p))) (cadr p))) 
    '(("(" 1) 
      ("((" 6) 
      ("[({(<(())[]>[[{[]{<()<>>" 288957) 
      ("[(()[<>])]({[<{<<[]>>(" 5566) 
      ("(((({<>}<{<{<>}{[]{[]{}" 1480781) 
      ("{<[[]]>}<{[{[{[]{()[[[]" 995444) 
      ("<{([{{}}[<[[[<>{}]]]>[]]" 294))) 
  
   (check-equal? (aoc10b example-input) example-output) 
   (check-equal? (aoc10b) 2776842859) 
   ) 
  
 $ raco test 10b.rkt  
 raco test: (submod "10b.rkt" test) 
 9 tests passed 
  
 $