aboutsummaryrefslogtreecommitdiff
path: root/2022/Day07/part-two.cl
blob: 267cf48258919261281a308359e71ad0f321e119 (plain) (blame)
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
;;; https://gitlab.com/Syndamia/senzill
(require :senzill)
(use-package :senzill.math)
(use-package :senzill.collections)
(use-package :senzill.io)

(defconstant +filesystem-size+ 70000000)
(defconstant +needed-space+ 30000000)

(ask-for-stream (prog-input)
  ;;; Every 3 consecutive values (in FOLDERS) represent one folder, where
  ;;; the first is it's name, second is size of all files inside and third is parent folder.
  (let* ((folders '("/" 0 -1)) (current-folder 0) (temp-size 0))
    (defun parse-cd (loc)
      "Updates CURRENT-FOLDER to point to index of chosen folder"
      (if (string= loc "..")
          (setf current-folder (nth (+ 2 current-folder) folders))
          (+= current-folder (position-if (lambda (x) (and (stringp x) (string= x loc)))
                                          (nthcdr current-folder folders)
                                          :from-end T)))) ; Dirty trick for not properly handling folders with same names in different locations

    (defun parse-dir (name)
      "Adds a new folder inside FOLDERS"
      (push-back name           folders)
      (push-back 0              folders)
      (push-back current-folder folders))

    ;;; Parses input lines
    (doread-lines (inpt :read-line-options (prog-input NIL))
                  ;; "$ ls" isn't parsed, because we don't need to
                  (cond ;; if we have "$ cd"
                        ((and (char= (char inpt 0) #\$) (char= (char inpt 2) #\c))
                         (parse-cd (subseq inpt 5)))
                        ;; if we have "dir ..."
                        ((char= (char inpt 0) #\d)
                         (parse-dir (subseq inpt 4)))
                        ;; if we have "<NUMBER> <FILE_NAME>"
                        ((digit-char-p (char inpt 0))
                         (setf temp-size (parse-integer inpt :junk-allowed T))
                         ;;; Adds the file size to the current folder and all parent folders
                         ;;; This could be extracted to the final summation, but this way it's simpler
                         (loop for fol = current-folder then (nth (+ 2 fol) folders)
                               until (= fol -1) do
                               (+= (nth (+ 1 fol) folders)
                                   temp-size)))))

    (let ((free-space (- +filesystem-size+ (second folders))))
      ;;; LREST is a tail of FOLDERS, where on each iteration it starts with the file size of each folder
      (loop for lrest on (cdr folders) by #'cdddr
            if (>= (+ free-space (car lrest)) +needed-space+)
              minimize (car lrest) into result
            finally (print result)))))