If you have a lisp installation, emacs, org-mode, and org-babel support for lisp installed you can run this by:
- Starting slime (
M-x slime
) - Typing
C-c C-c
in the block initialize. - In the repl type
(in-package :aoc-2022-07)
- Typing
C-c C-c
in the block answers
(unless (find-package :cl-ppcre)
(ql:quickload "cl-ppcre"))
(unless (find-package :parseq)
(ql:quickload "parseq"))
(unless (find-package :lparallel)
(ql:quickload "lparallel"))
(unless (find-package :fiveam)
(ql:quickload "fiveam"))
(unless (find-package :series)
(ql:quickload "series"))
(unless (find-package :cl-permutation)
(ql:quickload "cl-permutation"))
(unless (find-package :bordeaux-threads)
(ql:quickload "bordeaux-threads"))
<<packages>>
(defpackage :aoc-2022-07
(:use :common-lisp
:parseq
:fiveam)
(:export :problem-a
:problem-b))
(in-package :aoc-2022-07)
(defun interaction-to-directories (interactions)
(loop
with root = "\\$ cd (\/)"
with cdup = "\\$ cd \\.\\."
with cdre = "\\$ cd ([a-zA-Z0-9]+)"
with lsre = "\\$ ls" ;; useless, but to cover them all
with dirre = "dir (.+)"
with filere = "(\\d+) (.+)"
for action in interactions
with filesystem = (make-hash-table :test 'equal)
with path = '()
finally (return filesystem)
do (cl-ppcre:register-groups-bind
(dir) (root action)
(setf path (list "\/")))
do (cl-ppcre:register-groups-bind
() (cdup action)
(pop path))
do (cl-ppcre:register-groups-bind
(dir) (cdre action)
(push dir path))
do (cl-ppcre:register-groups-bind
(dir) (dirre action)
(pushnew dir (gethash path filesystem)))
(cl-ppcre:register-groups-bind
((#'parse-integer size) name)
(filere action)
(pushnew (cons name size) (gethash path filesystem) :test #'equalp))))
(defun process-stream (in)
(loop for line = (read-line in nil)
while line
collect line))
(defun read-input (file)
(with-open-file (in file)
(interaction-to-directories (process-stream in))))
(defparameter *input*
(read-input "input/07.txt"))
(defparameter *max-size* 100000) ;; magic number for problem
(defun collect-sizes (filesystem &key (path '("\/")))
(let ((children nil)
(size 0))
(loop for item in (gethash path filesystem)
if (stringp item)
do (let ((child (collect-sizes filesystem :path (cons item path))))
(incf size (car child))
(setf children (append child children)))
else
do (incf size (cdr item)))
(cons size children)))
(defun part-1 (fs)
(reduce #'+ (remove-if (lambda (size) (< *max-size* size)) (collect-sizes fs))))
(defun problem-a () (format t "Problem 07 A: ~a~%" (part-1 *input*)))
(defparameter *disk-capacity* 70000000)
(defparameter *target-capacity* (- *disk-capacity* 30000000))
(defun part-2 (fs)
(let* ((sizes (collect-sizes fs))
(target (- (car sizes) *target-capacity*)))
(reduce #'min (remove-if (lambda (size) (< size target)) sizes))))
(defun problem-b () (format t "Problem 07 B: ~a~%" (part-2 *input*)))
<<read-input>>
<<input>>
<<initialize>>
<<structs>>
<<functions>>
<<input>>
<<problem-a>>
<<problem-b>>
(problem-a)
(problem-b)
Problem 07 A: 1449447 Problem 07 B: 8679207
(def-suite aoc.2022.07)
(in-suite aoc.2022.07)
(defparameter *sample-input*
"$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
dir d
$ cd a
$ ls
dir e
29116 f
2557 g
62596 h.lst
$ cd e
$ ls
584 i
$ cd ..
$ cd ..
$ cd d
$ ls
4060174 j
8033020 d.log
5626152 d.ext
7214296 k")
(defparameter *sample-fs*
(with-input-from-string (in *sample-input*)
(interaction-to-directories (process-stream in))))
(test part-1
(is (= (part-1 *sample-fs*) 95437)))
(test part-2
(is (= (part-2 *sample-fs*) 24933642)))
(run! 'aoc.2022.07)
Running test suite AOC.2022.07 Running test PART-1 . Running test PART-2 . Did 2 checks. Pass: 2 (100%) Skip: 0 ( 0%) Fail: 0 ( 0%)