;;; 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 " " ((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)))))