Return the first winning card’s score.
$ cat 04a.rkt #lang racket (provide example-data read-input) (require (prefix-in aoc: "aoc.rkt") (prefix-in a: "array.rkt") (prefix-in srfi42: srfi/42) (prefix-in utl: "../scheme/utl.rkt")) (define (aoc04a . args) ; Return the score of the winning board in the given bingo ; game. If no game is given, use the contest problem input; ; otherwise assume the argument is the string representation of ; a problem input. (run-the-game (apply read-input args))) (define (bingo-board board-data) ; Return an empty bingo board representing the given bingo card. (define card (a:new board-data)) ; Map a bingo number n to the count of unmarked numbers in the ; row or column containing n on the board. N is assumed to be ; somewhere on the board. (define rows (make-hash)) (define cols (make-hash)) (define (fill-board board card) (let ((n (a:rows card))) (do ((r (- n 1) (- r 1))) ((= r -1) #t) (let ((v (vector n))) (do ((c (- n 1) (- c 1))) ((= c -1) #t) (hash-set! board (a:ref card r c) v)))))) (define (mark board n) ; Mark the given bingo board with the given number; return #t ; iff the number completes a row or column in the board. (let* ((v (hash-ref board n)) (c (- (vector-ref v 0) 1))) (vector-set! v 0 c) (hash-remove! board n) (zero? c))) (fill-board rows card) (fill-board cols (a:transpose card)) (lambda (n) (if (hash-has-key? rows n) (begin (if (or (mark rows n) (mark cols n)) (apply + (hash-keys rows)) 0)) 0))) (define (read-input . arg) ; Return the given bingo set-up. If no set-up is given, use the ; contest problem input; otherwise assume the argument is the ; string representation of a problem input. (define (make-board board-data) (bingo-board (map (lambda (b) (map string->number b)) board-data))) (let ((i (aoc:aoc-read-input (if (null? arg) 4 (car arg))))) (cons (aoc:read-comma-separated-numbers (caaar i)) (map make-board (cdr i))))) (define (run-the-game bingo-game) ; Return the score of the winning board in the given bingo ; game. (call-with-current-continuation (lambda (k) (srfi42:do-ec (srfi42::list call (car bingo-game)) (srfi42::list board (cdr bingo-game)) (let ((board-value (board call))) (unless (zero? board-value) (k (* board-value call)))))))) (module+ main (aoc04a)) (aoc:define-string example-data "7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1" "" "22 13 17 11 0" " 8 2 23 4 24" "21 9 14 16 7" " 6 10 3 18 5" " 1 12 20 15 19" "" " 3 15 0 2 22" " 9 18 13 17 5" "19 8 7 25 23" "20 11 10 24 4" "14 21 16 12 6" "" "14 21 17 24 4" "10 16 15 9 19" "18 8 23 26 20" "22 11 13 6 5" " 2 0 12 3 7" ) (define example-result 4512) (module+ test (require rackunit) (check-equal? (aoc04a example-data) example-result) (check-equal? (aoc04a) 54275) ) $ raco test 04a.rkt raco test: (submod "04a.rkt" test) 2 tests passed $