code / advent / 2024/09.lisp

1(defpackage #:advent.2024.09
2  (:use #:cl #:advent.2024.00)
3  (:import-from #:serapeum
4                #:take-while)
5  (:import-from #:alexandria
6                #:compose))
7(in-package #:advent.2024.09)
8
9(defparameter *input* "09.example")
10
11;;; Day 1.
12;; 1. Decode / expand compact disc map representation
13;; 2. Move blocks left to fill empty space
14;; 3. Checksum
15
16(defun decode (&optional (str (uiop:read-file-line *input*)))
17  (loop with id = 0
18        with res = (make-array '(1000) :adjustable t
19                                       :fill-pointer 0)
20        for c across str
21        for n = (parse-integer (string c))
22        while n
23        for filep = t then (not filep)
24        if filep do
25          (progn
26            (loop for i from 1 to n do
27              (vector-push-extend id res))
28            (incf id))
29        else do
30          (loop for i from 1 to n do
31            (vector-push-extend nil res))
32        finally (return res)))
33
34(defun shift (&optional (str (uiop:read-file-line *input*)))
35  (let* ((mem (decode str))
36         (rev (nreverse (remove-if #'null (vector->list mem)))))
37    (loop for i from 0 below (length rev)
38          collect (or (aref mem i)
39                      (pop rev)))))
40
41(defun checksum (&optional (str (uiop:read-file-line *input*))) ; also solve1
42  (loop for i from 0
43        for n in (shift str)
44        sum (* i n)))
45
46;;; 24551621791131 is too high
47;; ... change `until (eq beg end)` to `until (> beg end)` ...
48;; 2096 is too low
49;;; ... change to (>= beg end) ...
50;; 6415449222092 is too high
51;; 6414919955263 is wrong
52;; 6415184586041 IS RIGHT THANK GOD :)
53
54;;; Part 2.
55;; Move whole files instead of just blocks.....
56;; ex.
57;; 00...111...2...333.44.5555.6666.777.888899
58;; 0099.111...2...333.44.5555.6666.777.8888..
59;; 0099.1117772...333.44.5555.6666.....8888..
60;; 0099.111777244.333....5555.6666.....8888..
61;; 00992111777.44.333....5555.6666.....8888..
62
63;; Do i want to redefine the input format to be a list of files with size and
64;; id?
65
66(defun length-encode (v)
67  (do ((i 0 (1+ i))
68       tmp res
69       (start 0))
70      ((>= i (length v))
71       (nreverse (cons (list (car tmp) start (length tmp)) res)))
72    (if (eq (aref v i)
73            (car tmp))
74        (push (aref v i) tmp)
75        (progn
76          (push (list (car tmp) start (length tmp)) res)
77          (setf tmp (list (aref v i)))
78          (setf start i)))))
79
80(defun shift2 (&optional (str (uiop:read-file-line *input*)))
81  (let* ((mem (length-encode (decode str)))
82         (frees (remove-if-not (compose #'null #'car) mem))
83         (files (nreverse (remove-if (compose #'null #'car) mem))))
84    (loop for (id . len) in files
85          if (find len frees :key #'third)
86            )))