-
Notifications
You must be signed in to change notification settings - Fork 1
/
day04.lisp
79 lines (67 loc) · 2.52 KB
/
day04.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
(mgl-pax:define-package :aoc.2021.04
(:nicknames :2021.04)
(:use :cl :aoc.util :mgl-pax)
(:import-from :cl-ppcre #:split))
(in-package :2021.04)
(defsummary (:title "Giant Squid")
"**Part 1** - Bingo Subsystem"
(play-bingo function)
"**Part 2** - Let the Squid Win"
(play-bingo-final function))
(defvar *wins*
'((0 1 2 3 4)
(5 6 7 8 9)
(10 11 12 13 14)
(15 16 17 18 19)
(20 21 22 23 24)
(0 5 10 15 20)
(1 6 11 16 21)
(2 7 12 17 22)
(3 8 13 18 23)
(4 9 14 19 24)
(0 6 12 18 24)
(4 8 12 16 20)))
(defun build-data (&optional input)
(read-day-input #'identity :separator "\\n\\n" :input input))
(defun parse-nums-by (regex string)
(map 'vector #'parse-integer (remove "" (cl-ppcre:split regex string) :test #'string=)))
(defun find-winner (chosen boards)
(dolist (board boards)
(dolist (win *wins*)
(let ((numbers (mapcar (lambda (x) (aref board x)) win)))
(when (every (lambda (x) (member x chosen)) numbers)
(return-from find-winner board))))))
(defun score-for (chosen board)
(* (first chosen)
(reduce #'+ (remove-if (lambda (x) (member x chosen)) board))))
(defun play-bingo (order boards)
(loop with chosen = '()
for number across order
for winner = (find-winner chosen boards)
until winner
do (push number chosen)
finally (return (score-for chosen winner))))
(defun part-1 (&optional (data (build-data)))
(let ((order (parse-nums-by "," (first data)))
(boards (mapcar (lambda (board) (parse-nums-by "\\s+" board)) (rest data))))
(play-bingo order boards)))
(defun filter-boards (order boards)
(loop with chosen = '()
for number across order
do (loop for winner = (find-winner chosen boards)
while winner
do (setf boards (remove winner boards :test #'equalp)))
until (= 1 (length boards))
do (push number chosen)
finally (return (list chosen order (1- (length chosen)) boards))))
(defun play-bingo-final (order boards)
(destructuring-bind (chosen order index boards) (filter-boards order boards)
(loop for number = (aref order (incf index))
for winner = (find-winner chosen boards)
until winner
do (push number chosen)
finally (return (score-for chosen winner)))))
(defun part-2 (&optional (data (build-data)))
(let ((order (parse-nums-by "," (first data)))
(boards (mapcar (lambda (board) (parse-nums-by "\\s+" board)) (rest data))))
(play-bingo-final order boards)))