AoC'21, day 8, second problem rvc


In addition to the garbled display output, the problem input also contains a list of all ten garbled digits. With a little bit of logic it's possible to determine which digit is represented by which garbled signals, and from there return the sum of the displayed values.

 $ cat 08b.rkt 
 #lang racket 
  
  
 (require 
   (prefix-in aoc08: "08a.rkt") 
   ) 
  
  
 (define (aoc08b . args) 
  
   ; Decode the garbled signals, and return the sum of the displayed  
   ; numbers.  If no display i-o is given, use the contest problem 
   ; input; otherwise assume the argument is the string representation 
   ;  of a problem input. 
  
   (apply + 
     (map (lambda (l) (decode-display l)) 
          (apply aoc08:read-input args)))) 
  
  
 (define (decode-display display-status) 
  
   ; Return the value displayed in the given display status line. 
  
   (let 
  
     ((dssm (get-digit-signal-set-mapping (car display-status)))) 
  
     (foldl 
       (lambda (ss s) (+ (dssm 'get ss) (* 10 s))) 
       0 
       (cadr display-status)))) 
  
  
 (define (get-digit-signal-set-mapping digit-signal-sets) 
  
   ; Return a mapping between digits and signal sets derived from 
   ; the given list of signal sets. 
  
   (define dssm (new-digit-signal-set-mapping)) 
  
   (define (select-segment-set p) 
  
     ; Return the segment set satisfying p; there is assumed to be 
     ; exactly one such segment set. 
  
     (let ((signal-set (filter p digit-signal-sets))) 
       (case (length signal-set) 
         ((0) (error "can't find a satisfactory segment set")) 
         ((1) (let ((ss (car signal-set))) 
                (set! digit-signal-sets (remove ss digit-signal-sets)) 
                ss)) 
         (else (error "found more than one satisfactory segment set"))))) 
  
  
   (define (get-segments-by-size n) 
  
     ; Return the segment set having the given size. 
      
     (select-segment-set (lambda (ss) (= (length ss) n)))) 
  
  
   (define (get-segments-by-difference-size ss-size d d-size) 
  
     ; Return the segment set with the given size and  
      
     (select-segment-set 
       (lambda (ss) (and (= (length ss) ss-size) 
                         (difference-size ss d d-size))))) 
  
  
   (define (difference-size s-set d d-size) 
  
     ; Return #t iff the cardinality of the difference between the 
     ; given signal set and the signal set for the given digit is 
     ; equal to the given size. 
      
     (= d-size 
        (foldl 
          (lambda (s c) (- c (if (member s s-set) 1 0))) 
          (length s-set) 
          (dssm 'get d)))) 
  
    
   ; 1, 4, 7 and 8 have unique segment counts among all the digits. 
    
   (for-each 
     (lambda (p) (dssm 'put (car p) (get-segments-by-size (cdr p)))) 
     '((1 . 2) (4 . 4) (7 . 3) (8 . 7))) 
  
   ; 3 is the only 5-segment digit with 3 segments not in 1. 
   (dssm 'put 3 (get-segments-by-difference-size 5 1 3)) 
  
   ; Without 3, 2 is the only 5-segment digit with 3 segments not in 4. 
   (dssm 'put 2 (get-segments-by-difference-size 5 4 3)) 
  
   ; The only 5-digit segment left is 5. 
   (dssm 'put 5 (get-segments-by-size 5)) 
  
   ; There are only six-segment digits left: 0 6 9. 
    
   ; 9 is the only six-segment digit with one segment not in 3. 
   (dssm 'put 9 (get-segments-by-difference-size 6 3 1)) 
  
   ; Without 9, 0 is the only six-segment digit with 2 segments not in 5 
   (dssm 'put 0 (get-segments-by-difference-size 6 5 2)) 
  
   ; 6 is the only six-segment digit left. 
   (dssm 'put 6 (get-segments-by-size 6)) 
  
   dssm) 
  
  
 (define (new-digit-signal-set-mapping) 
  
   (let 
  
     ((d2ss (make-hash)) 
      (ss2d (make-hash)) 
  
      (oops (lambda args 
        (apply raise-user-error (cons 'digit-signal-set-mapping args))))) 
      
  
     (lambda (cmd . args) 
       (case (list 'quote cmd) 
  
        (('get ) 
            (unless (= (length args) 1) 
              (oops "get expects 1 argument, got ~a" (length args)))          
  
            (let ((a (car args))) 
              (cond 
               ((number? a) 
                (hash-ref d2ss a)) 
               ((list? a) 
                (hash-ref ss2d (sort a char<?))) 
               (#t 
                (oops "get expects a value of type int or list"))))) 
        
         (('put) 
            (unless (= (length args) 2) 
              (oops "put expects 2 arguments, got ~a" (length args))) 
  
            (let ((d (car args)) 
                  (ss (sort (cadr args) char<?))) 
              (hash-set! d2ss d ss) 
              (hash-set! ss2d ss d))) 
  
   (else 
     (oops "Don't recognize ~a as a command" cmd)))))) 
  
  
 (module+ main 
   (aoc08b) 
   ) 
  
  
 (module+ test 
  
   (require rackunit) 
    
   (define dssm 
     (get-digit-signal-set-mapping (caar (aoc08:read-input "gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce")))) 
    
   (for-each 
    (lambda (p) (check-equal? (dssm 'get (car p)) (cdr p))) 
    '((0 . (#\b #\c #\d #\e #\f #\g)) 
      (1 . (#\f #\g)) 
      (2 . (#\a #\b #\c #\d #\f)) 
      (3 . (#\a #\b #\c #\f #\g)) 
      (4 . (#\a #\e #\f #\g)) 
      (5 . (#\a #\b #\c #\e #\g)) 
      (6 . (#\a #\b #\c #\d #\e #\g)) 
      (7 . (#\c #\f #\g)) 
      (8 . (#\a #\b #\c #\d #\e #\f #\g)) 
      (9 . (#\a #\b #\c #\e #\f #\g)) 
      )) 
  
   (for-each 
    (lambda (p) (check-equal? (decode-display (car (aoc08:read-input (car p)))) (cdr p))) 
    '(("be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb | fdgacbe cefdb cefbgd gcbe" . 8394) 
      ("edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec | fcgedb cgb dgebacf gc" . 9781) 
      ("fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef | cg cg fdcagb cbg" . 1197) 
      ("fbegcd cbd adcefb dageb afcb bc aefdc ecdab fgdeca fcdbega | efabcd cedba gadfec cb" . 9361) 
      ("aecbfdg fbg gf bafeg dbefa fcge gcbea fcaegb dgceab fcbdga | gecf egdcabf bgf bfgea" . 4873) 
      ("fgeab ca afcebg bdacfeg cfaedg gcfdb baec bfadeg bafgc acf | gebdcfa ecba ca fadegcb" . 8418) 
      ("dbcfg fgd bdegcaf fgec aegbdf ecdfab fbedc dacgb gdcebf gf | cefg dcbef fcge gbcadfe" . 4548) 
      ("bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd | ed bcgafe cdgba cbgef" . 1625) 
      ("egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg | gbdfcae bgc cg cgb" . 8717) 
      ("gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce" . 4315))) 
  
   (check-equal? (aoc08b aoc08:example-input) 61229) 
   (check-equal? (aoc08b) 1043697) 
   ) 
  
 $ raco test 08b.rkt 
 raco test: (submod "08b.rkt" test) 
 22 tests passed 
  
 $