aboutsummaryrefslogtreecommitdiffstats
path: root/AoC2023/day16/solver.lisp
blob: 8b967a4e87e9ab7e481796ab283ff14ca6e30cb2 (plain)
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
;;8:57
;;10:26 part1
(ql:quickload '(fiveam arrows alexandria))
(defparameter eg-in "")

(defun in-bounds (field ray)
  (destructuring-bind (maxrow maxcol) (array-dimensions field)
    (destructuring-bind (dir row col) ray
      (declare (ignorable dir))
      (and (< -1 row maxrow)
           (< -1 col maxcol)))))

(defun next-direction (ray)
  (destructuring-bind (dir row col) ray
    (cons dir
          (ecase dir
            (up (list (1- row) col))
            (lf (list row (1- col)))
            (dw (list (1+ row) col))
            (rt (list row (1+ col)))))))

(defun mirror-bs (ray)
  (destructuring-bind (dir row col) ray
    (arrows:->
        (ecase dir
          (up 'lf)
          (lf 'up)
          (dw 'rt)
          (rt 'dw))
        (list row col)
        (list))))

(defun mirror-fs (ray)
  (destructuring-bind (dir row col) ray
    (arrows:->
        (ecase dir
          (up 'rt)
          (lf 'dw)
          (dw 'lf)
          (rt 'up))
        (list row col)
        (list))))

(defun split-v (ray)
  (destructuring-bind (dir row col) ray
    (ecase dir
      ((up dw) (list ray))
      ((lf rt) (list (list 'up row col) (list 'dw row col)) ))))

(defun split-h (ray)
  (destructuring-bind (dir row col) ray
    (ecase dir
      ((lf rt) (list ray))
      ((up dw) (list (list 'lf row col) (list 'rt row col)) ))))

(defun energized-p (energized ray)
  (destructuring-bind (dir row col) ray
    (find dir (gethash (cons row col) energized))))

(defun action (field ray energized)
  (destructuring-bind (dir row col) ray
    (unless (find dir (gethash (cons row col) energized)))
    (arrows:->>
     (ecase (aref field row col)
       (#\. (list ray))
       (#\\ (mirror-bs ray))
       (#\/ (mirror-fs ray))
       (#\| (split-v ray))
       (#\- (split-h ray)))
     (mapcar #'next-direction)
     (remove-if-not (alexandria:curry #'in-bounds field))
     (remove-if (alexandria:curry #'energized-p energized)))))

(defun advancer (field rays energized maxi)
  (loop for (dir row col) in rays do
    (push dir (gethash (cons row col) energized)))
  (if (or (null rays) (> maxi 5000))
      energized
      (let ((next-moves (mapcan (lambda (ray) (action field ray energized)) rays)))
        ;; (format t "~d Next: ~a~%" maxi next-moves)
        (advancer field next-moves energized (1+ maxi)))))

(defun solver1 (input)
  (let* ((rows (length input))
         (energized (make-hash-table :test #'equal))
         (field
           (make-array (list rows (length (car input))) :initial-contents input)))
    (advancer field (list (list 'rt 0 0)) energized 0)
    (hash-table-count energized)))

(fiveam:test solutions
  (fiveam:is (= 46 (solver1 (uiop:read-file-lines "eg-in"))))
  (fiveam:is (= 7996 (solver1 (uiop:read-file-lines "input")))))