aboutsummaryrefslogtreecommitdiff
path: root/2022/puzzle-7.lisp
blob: a9b302c72f492181d9aaf001c3658031ac94b7cd (plain)
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
(load "lib")
(defparameter input (uiop:read-file-string "7-input"))
(defparameter lines (get-lines input)) ;; first line is ALWAYS "$ cd /"

(defun tokenise-lines (lines)
  "Split each LINE in LINES by space"
  (mapcar (lambda (line)
       (mapcar #'clist-to-string
          (split-completely (string-to-clist line) #\Space)))
     lines))

(defun token-cmdp (token)
  "Checks if TOKEN is a command (by the first member)"
  (string= (car token) "$"))

(defun till-next-cmd (tokens)
  "Iterates over TOKENS till a command is found, returning the remaining
tokens (including command)."
  (loop
    for token-set on tokens
    if (token-cmdp (car token-set))
      return token-set))

#| What is a directory structure? You have some root directory, with
some entries.  Your current working directory (CWD), at the start of
the program, will be at the root but later on could be any descendant
of the root.  How do we manage moving around the directory structure
and ensure updates to the root?

We should maintain a HISTORY stack where
CAR(HISTORY) = (NAME of CWD . State of CWD when entering).

Firstly a function which updates the HISTORY on our current state.
UPDATE-CURRENT-DIRECTORY(CWD, HISTORY) {
CWD-ENTRY = PEEK(HISTORY);
IF NULL(CWD-ENTRY)
HISTORY = ((NIL . CWD))
ELSE
SETF((CDR CWD-ENTRY), CWD);
}

Say CWD = {... a = directory, b = file, ...}
DOWN-DIRECTORY(a, CWD, HISTORY) {
UPDATE-CURRENT-DIRECTORY(CWD, HISTORY); <-- This is so we don't lose information
HISTORY = ACONS(a, CWD@a, HISTORY);
CWD     = CWD@a;
}


Then UP-DIRECTORY(CWD, HISTORY) {
PAIR   = POP(HISTORY);               <-- (CWD-NAME . PREVIOUS-CWD-STATE)
PARENT = PEEK(HISTORY);              <-- Parent of CWD (PARENT-NAME . PARENT-STATE)
ENTRY = ASSOC(CAR(PAIR) CDR(PARENT)) <-- Gives us the CWD entry in the parent
SETF CDR(ENTRY) CWD                  <-- Update the parent
CWD = CDR(PARENT)                    <-- Update CWD
}
|#

(defun parse-ls (tokens)
  "Converts the following TOKENS till a command (via TOKEN-CMDP) into a
directory structure i.e. an alist of string names by their content."
  (loop for token in tokens
        until (token-cmdp token)
        collect
        (let ((size (car token))
              (name (cadr token)))
          (if (string= size "dir")
              `(,name . nil)
              `(,name . ,(parse-integer size))))))

(defun parse-tokens (tokens)
  (if (token-cmdp (car tokens))
      (cond
        ((string= (cadar tokens) "ls")
         (values
          (till-next-cmd (cdr tokens))
          (parse-ls (cdr tokens))))
        ((string= (cadar tokens) "cd")
         ;; TODO: Actually figure out what I should do here
         (values
          (cdr tokens)
          nil)))))