Last active
December 8, 2022 00:22
-
-
Save quephird/f4906fdccee0d9ff03e92acf3f55bdb7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(require ['clojure.string :as 'str]) | |
;; The file system is represented by a deep hashmap | |
;; of file and directory names as keys, and either a | |
;; file size or list of subdirectory names and files as | |
;; their values. | |
(def file-system (atom {"/" {}})) | |
;; The current directory is always a vector of names. | |
;; For example, the path "/foo/bar/baz" is represented by | |
;; the vector ["/" "foo" "bar" "baz"]. | |
(def current-directory (atom [])) | |
(defn handle-cd [arg] | |
(cond | |
(= "/" arg) | |
(reset! current-directory ["/"]) | |
(= ".." arg) | |
(swap! current-directory #(-> % drop-last vec)) | |
:else | |
(swap! current-directory conj arg))) | |
(defn handle-ls [] | |
;; This is effectively a no-op but is here for clarity. | |
nil) | |
(defn handle-command [command arg] | |
(cond | |
(= "cd" command) | |
(handle-cd arg) | |
:else | |
(handle-ls))) | |
(defn handle-create-directory [new-dir] | |
(swap! file-system assoc-in (conj @current-directory new-dir) {})) | |
(defn handle-create-file [new-file size] | |
(swap! file-system assoc-in (conj @current-directory new-file) (Integer/parseInt size))) | |
(defn handle-command-output [a b] | |
(cond | |
(= "dir" a) | |
(handle-create-directory b) | |
:else | |
(handle-create-file b a))) | |
(defn parse-line [line] | |
(let [[a b c] (str/split line #" ")] | |
(cond | |
(= "$" a) | |
(handle-command b c) | |
:else | |
(handle-command-output a b)))) | |
(defn parse-file [lines] | |
(loop [[line & rest] lines] | |
(if (empty? line) | |
nil | |
(do | |
(parse-line line) | |
(recur rest))))) | |
(defn directory? [path] | |
(map? (get-in @file-system path))) | |
(defn file? [path] | |
(int? (get-in @file-system path))) | |
(defn contents-paths [dir-path] | |
(->> dir-path | |
(get-in @file-system) | |
keys | |
(map #(conj dir-path %)))) | |
(defn subdirectories [path] | |
(if (file? path) | |
nil | |
(->> path | |
contents-paths | |
(filter directory?)))) | |
(defn all-directory-paths [starting-path] | |
(let [subdirs (subdirectories starting-path)] | |
(apply concat [starting-path] (map all-directory-paths subdirs)))) | |
(defn size [path] | |
(if (file? path) | |
(get-in @file-system path) | |
(let [contents (get-in @file-system path)] | |
(->> (keys contents) | |
(map #(conj path %)) | |
(map size) | |
(apply +))))) | |
(defn load-input [filename] | |
(->> filename | |
slurp | |
str/split-lines | |
parse-file)) | |
(defn solution-part-1 [] | |
(->> ["/"] | |
all-directory-paths | |
(map size) | |
(filter #(<= % 100000)) | |
(apply +))) | |
(defn solution-part-2 [] | |
(let [used-space (size ["/"]) | |
unused-space (- 70000000 used-space) | |
min-space-to-recover (- 30000000 unused-space)] | |
(->> ["/"] | |
all-directory-paths | |
(map size) | |
(filter #(>= % min-space-to-recover)) | |
(apply min)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment