aboutsummaryrefslogtreecommitdiffstats
path: root/AoC2022/17/solver.lisp
blob: 0be6c02ccab6d5d78304dae345a85de3c28be217 (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
(ql:quickload '(:fiveam :uiop :arrows))

(defparameter *chamber-width* 7)

(defun point (x y)
  (+ x (* y *chamber-width*)))

(defun coords (point)
  (floor point *chamber-width*))

(defparameter *rocks*
  (vector (list (point 0 0) (point 1 0) (point 2 0) (point 3 0))
          (list (point 1 0)
                (point 0 1) (point 1 1) (point 2 1)
                (point 1 2))
          (list (point 0 0) (point 1 0) (point 2 0)
                (point 2 1)
                (point 2 2))
          (list (point 0 0) (point 0 1) (point 0 2) (point 0 3))
          (list (point 0 0) (point 1 0)
                (point 0 1) (point 1 1))))

(defun left (point) (1- point))
(defun right (point) (1+ point))
(defun down (point) (- point *chamber-width*))

(defun no-collision-move (object direction obstacles)
  (mapcar
   (lambda (current)
     (let ((next (funcall
                  (ecase direction
                    (#\> #'right)
                    (#\< #'left)
                    (#\v #'down))
                  current)))
       (multiple-value-bind (y2 x2) (coords next)
         (and (>= y2 0)
              ;; no rolling boundaries
              (multiple-value-bind (y x) (coords current)
                (= 1 (+ (abs (- x x2)) (abs (- y y2)))))
              (not (member next obstacles :test #'=))
              next))))
   object))

(defun gen-object (seq)
  (let ((len (length seq))
        (index 0))
    (lambda ()
      (prog1 (aref seq index)
        (setf index (mod (1+ index) len))))))

(defun place-rock (rock highpoint)
  (let ((left-pad 2))
    (mapcar (lambda (point) (+ point left-pad (* *chamber-width* highpoint))) rock)))

(defun advance (chamber next-move rock)
  (let ((next-place (no-collision-move rock next-move chamber)))
    (if (every #'integerp next-place)
        next-place rock)))

(defun next-move (chamber next-move rock)
  (let* ((shift (advance chamber next-move rock))
         (drop (advance chamber #\v shift)))
    (values drop (equal shift drop))))

(defun simulate (chamber rock next-shift)
  (multiple-value-bind (new-place done-falling-p)
      (next-move chamber (funcall next-shift) rock)
    (if done-falling-p
        (append new-place chamber)
        (simulate chamber new-place next-shift))))

(defun highpoint (obstacles)
  (1+ (coords (reduce #'max obstacles))))

(defun solver (drops-left highpoint obstacles next-rock next-shift)
  (if (zerop drops-left)
      (values highpoint obstacles)
      (let ((obstacles (simulate obstacles
                                 (place-rock (funcall next-rock) (+ highpoint 3))
                                 next-shift)))
        (solver (1- drops-left) (highpoint obstacles) obstacles next-rock next-shift))))

(fiveam:test solutions
  (fiveam:is
   (= 3068 (solver 2022 0 nil (gen-object *rocks*) (gen-object (uiop:read-file-line "eg-in")))))
  (fiveam:is
   (= 3141 (solver 2022 0 nil (gen-object *rocks*) (gen-object (uiop:read-file-line "input"))))))

;; (print (solver 1000000000000 0 nil (gen-object *rocks*) (gen-object (uiop:read-file-line "eg-in"))))