aboutsummaryrefslogtreecommitdiffstats
path: root/AoC2023/day18/solver.lisp
blob: 62adac230ac85866ad0907a9bbf51de1eb619e26 (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
;;8:16
;;9:33
;;10:45
(ql:quickload '(fiveam arrows cl-ppcre))

(defun move (dir)
  (ecase dir
    ((R 0) (list 0 1))
    ((D 1) (list 1 0))
    ((L 2) (list 0 -1))
    ((U 3) (list -1 0))))

(defun parse (filename part)
  (mapcar (lambda (line)
            (destructuring-bind (dir len rest)
                (cl-ppcre:split " " line)
              (if (eq part 'first)
                  (list (intern dir) (parse-integer len))
                  (list
                   (digit-char-p (aref rest 7))
                   (parse-integer
                    (subseq rest 2 7) :radix 16)))))
          (uiop:read-file-lines filename)))

(defun polygon-area (points)
  (destructuring-bind ((fx fy) (lx ly)) (cons (car points) (last points))
    (arrows:->
        (loop for ((x y) (nx ny)) on points by #'cdr
              when nx
                sum (- (* x ny) (* y nx)))
        (+ (- (* lx fy) (* ly fx)))
        (/ 2)
        (abs))))

(fiveam:test partials
  (fiveam:is (= 4.5 (polygon-area '((1 1) (3 2) (2 6))))))

(defun solver (filename part &aux (row 0) (col 0) (perimeter 0))
  (let ((points
          (loop
            for (dir len) in (parse filename part)
            collect
            (destructuring-bind (dr dc) (move dir)
              (incf perimeter len)
              (list
               (incf row (* dr len))
               (incf col (* dc len)))))))
    ;; poligon area is for no width boundary
    ;; thus add half-perimeter. Think on a square
    ;; top and left edges contain area, but right & bottom not
    ;; thus add that part of perimeter as with. Then add 1 because
    ;; the corner on bottom right
    (+
     1
     (/ perimeter 2)
     (polygon-area points))))

(fiveam:test solutions
  (fiveam:is (= 62 (solver "eg-in" 'first)))
  (fiveam:is (= 76387 (solver "input" 'first)))
  (fiveam:is (= 952408144115 (solver "eg-in" 'second)))
  (fiveam:is (= 250022188522074 (solver "input" 'second))))