(defstruct board () rows) (defstruct bingo () numbers boards) (defun read-bingo (name) (let* ((lines (remqual "" (file-get-lines name))) (numbers [mapcar toint (spl "," (pop lines))]) (boards (mapcar (do new board rows @1) (tuples 5 (mapcar (opip (tok #/\d+/) (mapcar toint)) lines))))) (new bingo numbers numbers boards boards))) (defmeth board check (bo) (when-match @(or @(some (* * * * *)) ((* . @nil) (* . @nil) (* . @nil) (* . @nil) (* . @nil)) ((@nil * . @nil) (@nil * . @nil) (@nil * . @nil) (@nil * . @nil) (@nil * . @nil)) ((@nil @nil * . @nil) (@nil @nil * . @nil) (@nil @nil * . @nil) (@nil @nil * . @nil) (@nil @nil * . @nil)) ((@nil @nil @nil * . @nil) (@nil @nil @nil * . @nil) (@nil @nil @nil * . @nil) (@nil @nil @nil * . @nil) (@nil @nil @nil * . @nil)) ((@nil @nil @nil @nil * . @nil) (@nil @nil @nil @nil * . @nil) (@nil @nil @nil @nil * . @nil) (@nil @nil @nil @nil * . @nil) (@nil @nil @nil @nil * . @nil))) bo.rows t)) (defmeth board daub (bo num) (upd bo.rows (mapcar (op mapcar (iffi (op eql num) (ret '*))))) bo) (defmeth board value (bo) (sum bo.rows (op sum @1 [iff numberp use (ret 0)]))) (defmeth bingo solve (bi) (each ((x bi.numbers)) (each ((bo bi.boards)) (if bo.(daub x).(check) (return-from solve (* x bo.(value))))))) (defmeth bingo solve-last (bi) (each ((x bi.numbers)) (each ((bo bi.boards)) (if (and bo.(daub x).(check) (empty (upd bi.boards (remq bo)))) (return-from solve-last (* x bo.(value))))))) (defun tests () (assert (new board rows '((* * * * *))).(check)) (assert (new board rows '((1 2 3 4 5) (* * * * *))).(check)) (assert (new board rows '((* 2 3 4 5) (* 2 3 4 5) (* 2 3 4 5) (* 2 3 4 5) (* 2 3 4 5))).(check)) (assert (new board rows '((2 * 3 4 5) (2 * 3 4 5) (2 * 3 4 5) (2 * 3 4 5) (2 * 3 4 5))).(check)) (assert (new board rows '((2 3 * 4 5) (2 3 * 4 5) (2 3 * 4 5) (2 3 * 4 5) (2 3 * 4 5))).(check)) (assert (new board rows '((2 3 4 * 5) (2 3 4 * 5) (2 3 4 * 5) (2 3 4 * 5) (2 3 4 * 5))).(check)) (assert (new board rows '((2 3 4 5 *) (2 3 4 5 *) (2 3 4 5 *) (2 3 4 5 *) (2 3 4 5 *))).(check)) (assert (not (new board rows '((* * 3 * *))).(check))) (assert (not (new board rows '((1 2 3 4 5) (* * * * 3))).(check))) (assert (not (new board rows '((* 2 3 4 5) (6 2 3 4 5) (* 2 3 4 5) (* 2 3 4 5) (* 2 3 4 5))).(check))) (assert (not (new board rows '((2 6 3 4 5) (2 * 3 4 5) (2 * 3 4 5) (2 * 3 4 5) (2 * 3 4 5))).(check))) (assert (not (new board rows '((2 3 * 4 5) (2 3 * 4 5) (2 3 * 4 5) (2 3 6 4 5) (2 3 * 4 5))).(check))) (assert (not (new board rows '((2 3 4 * 5) (2 3 4 * 5) (2 3 4 6 5) (2 3 4 * 5) (2 3 4 * 5))).(check))) (assert (not (new board rows '((2 3 4 5 *) (2 3 4 5 *) (2 3 4 5 *) (2 3 4 5 *) (2 3 4 5 6))).(check))) (assert (equal (new board rows '((1 2 3 4 5) (6 7 8 9 10) (11 12 13 14 15))).(daub 8).rows '((1 2 3 4 5) (6 7 * 9 10) (11 12 13 14 15)))) (assert (eq (new board rows '((1 * * * *) (* * * * 2) (* * 3 * *))).(value) 6)))