211 lines
6.9 KiB
Common Lisp
211 lines
6.9 KiB
Common Lisp
;;; wow, now this is complicated.
|
|
|
|
;; first read in until the empty line
|
|
;; and somehow construct internal representation
|
|
;; i want Stack data structure. cool. where is that?
|
|
|
|
;; use list with PUSH and REMOVE ?
|
|
|
|
(defparameter *some-stack* (list 1 2 3))
|
|
(push 1 *some-stack*)
|
|
(pop *some-stack*)
|
|
*some-stack*
|
|
;; well, yea. list is a stack. ok
|
|
;; so I need to have addressable from 1 to n
|
|
;; lists
|
|
;; and after i read them - reverse
|
|
|
|
;; i guess i could read in the string. and calculate index of the list
|
|
(defparameter *test-string-0* " [D]")
|
|
(defparameter *test-string* "[Z] [M] [P]")
|
|
|
|
;; [Z] [M] [P]
|
|
;; 1 2 3
|
|
;; 01234567890
|
|
;; so. first letter is at 1 (after 0) and next letter is at i+4
|
|
;; let's write function that translates that string into '((1 Z) (2 M) (3 P))
|
|
;; and would translate *test-string* into '((2 D))
|
|
;; i guess i could just iterate by i+4 from i=1 until the end of the string, and that's it
|
|
|
|
(defun parse-crate-string (str)
|
|
(do
|
|
((str-index 1 (+ 4 str-index))
|
|
(index 1 (1+ index))
|
|
(accum (list)))
|
|
((> str-index (1- (length str))) accum)
|
|
(let ((box-label (aref str str-index)))
|
|
(if (not (eq box-label #\ ))
|
|
(setq accum (push (list index (aref str str-index)) accum))))))
|
|
|
|
(defparameter *test-line-parsed* (parse-crate-string *test-string*))
|
|
|
|
(do
|
|
( (index 1 (+ 4 index)))
|
|
((> index 15) "hello")
|
|
(format t "lala ~D~%" index)
|
|
)
|
|
|
|
(do ((temp-one 1 (1+ temp-one))
|
|
(temp-two 0 (1- temp-two)))
|
|
((> (- temp-one temp-two) 5) temp-one))
|
|
|
|
(aref "hello-world" 1)
|
|
(aref " hello-world" 0)
|
|
(aref "hello-world" 11)
|
|
(length "hello-world")
|
|
|
|
;;; now. for each string I want to take index, take list on that index and put the label on top
|
|
|
|
;; now, i want "common lisp MAP", and ideally with default
|
|
(defparameter *test-table* (make-hash-table))
|
|
(gethash 1 *test-table*)
|
|
(setf (gethash 2 *test-table*) "hello")
|
|
(gethash 2 *test-table*)
|
|
|
|
(gethash 3 *test-table* (list)) ; so anyway by default it returns NIL
|
|
|
|
*test-line-parsed*
|
|
(mapcar (lambda (box-descr)
|
|
(let* ((index (first box-descr))
|
|
(label (second box-descr))
|
|
(cur-list (gethash index *test-table*)))
|
|
(setf (gethash index *test-table*) (push label cur-list))))
|
|
*test-line-parsed*)
|
|
|
|
*test-table*
|
|
|
|
(defun apply-parsed-line-to-lists (parsed-line table)
|
|
(mapcar (lambda (box-descr)
|
|
(let* ((index (first box-descr))
|
|
(label (second box-descr))
|
|
(cur-list (gethash index table)))
|
|
(setf (gethash index table) (push label cur-list))))
|
|
parsed-line))
|
|
|
|
(apply-parsed-line-to-lists *test-line-parsed* *test-table*)
|
|
|
|
(defparameter *full-test-boxes* " [D]
|
|
[N] [C]
|
|
[Z] [M] [P] ")
|
|
|
|
(require 'cl-ppcre)
|
|
(cl-ppcre:split (cl-ppcre:create-scanner :end-anchor) *full-test-boxes*)
|
|
(cl-ppcre:split (cl-ppcre:create-scanner "\n") *full-test-boxes*)
|
|
;; all of this didn't fucking work. can't split the line by the newline, what a joke
|
|
|
|
;;; god. i'm ready to create these lists manually.
|
|
;;; ugh.
|
|
|
|
(defparameter *all-test-boxes-lines* (list
|
|
" [D]"
|
|
"[N] [C]"
|
|
"[Z] [M] [P]"))
|
|
|
|
(defparameter *all-input-boxes-lines* (list
|
|
" [C] [N] [R]"
|
|
"[J] [T] [H] [P] [L]"
|
|
"[F] [S] [T] [B] [M] [D]"
|
|
"[C] [L] [J] [Z] [S] [L] [B]"
|
|
"[N] [Q] [G] [J] [J] [F] [F] [R]"
|
|
"[D] [V] [B] [L] [B] [Q] [D] [M] [T]"
|
|
"[B] [Z] [Z] [T] [V] [S] [V] [S] [D]"
|
|
"[W] [P] [P] [D] [G] [P] [B] [P] [V]"))
|
|
|
|
|
|
(defun get-boxes-lists-hashtable (boxes-lines)
|
|
(let ((hash-table (make-hash-table))
|
|
(parsed-lines (mapcar #'parse-crate-string boxes-lines)))
|
|
(mapcar (lambda (parsed-line) (apply-parsed-line-to-lists parsed-line hash-table)) parsed-lines)
|
|
(maphash (lambda (key list) (setf (gethash key hash-table) (reverse list))) hash-table)
|
|
hash-table))
|
|
|
|
(defparameter *test-boxes* (get-boxes-lists-hashtable *all-test-boxes-lines*))
|
|
(gethash 2 (get-boxes-lists-hashtable *all-test-boxes-lines*))
|
|
;; yay. ok. good enough.
|
|
|
|
|
|
;; now i need a function that would modify that hash table for each line
|
|
;; "move 1 from 2 to 1"
|
|
;; if i just to intern, would i get numbers?
|
|
(cddr (mapcar #'intern (cl-ppcre:split " " "move 1 from 2 to 1")))
|
|
;; nope that would be a symbol
|
|
;; allright, let's just emit list of numbers
|
|
(let ((string "move 1 from 2 to 3"))
|
|
(do*
|
|
((words (cl-ppcre:split " " string) (cddr words))
|
|
(number (parse-integer (second words)) (parse-integer (second words)))
|
|
(nums (list number) (push number nums)))
|
|
((not (cddr words)) (reverse nums))))
|
|
|
|
(defun command-string-to-indices (str)
|
|
(do*
|
|
((words (cl-ppcre:split " " str) (cddr words))
|
|
(number (parse-integer (second words)) (parse-integer (second words)))
|
|
(nums (list number) (push number nums)))
|
|
((not (cddr words)) (reverse nums))))
|
|
(command-string-to-indices "move 1 from 2 to 1")
|
|
|
|
(defun run-command (hashtable amount from to)
|
|
(loop
|
|
for i from 1 to amount
|
|
do (push (pop (gethash from hashtable)) (gethash to hashtable))))
|
|
|
|
(run-command *test-boxes* 3 2 1)
|
|
(gethash 2 *test-boxes*)
|
|
(gethash 1 *test-boxes*)
|
|
|
|
(with-open-file (in "day5-test-input.txt")
|
|
(loop
|
|
for line = (read-line in nil nil)
|
|
while line
|
|
do (apply #'run-command (cons *test-boxes* (command-string-to-indices line)))))
|
|
|
|
;; https://riptutorial.com/common-lisp/example/4463/looping-over-hash-tables
|
|
(print (coerce (loop
|
|
for v from 1 to 3
|
|
collect (first (gethash v *test-boxes*))) 'string))
|
|
|
|
(defparameter *day-5-boxes* (get-boxes-lists-hashtable *all-input-boxes-lines*))
|
|
(gethash 1 *day-5-boxes*)
|
|
(with-open-file (in "day5-input.txt")
|
|
(loop
|
|
for line = (read-line in nil nil)
|
|
while line
|
|
do (apply #'run-command (cons *day-5-boxes* (command-string-to-indices line)))))
|
|
|
|
;; printing things as a string
|
|
(print (coerce (loop
|
|
for v from 1 to (hash-table-count *day-5-boxes*)
|
|
collect (first (gethash v *day-5-boxes*))) 'string))
|
|
|
|
(getf :count *day-5-boxes*)
|
|
(hash-table-count *day-5-boxes*)
|
|
|
|
;; oh, wow. now i need to implement moving "with retaining order".
|
|
;; cool
|
|
|
|
(defun run-command-9001 (hashtable amount from to)
|
|
(let ((moving-part (subseq (gethash from hashtable) 0 amount))
|
|
(remaining-part (subseq (gethash from hashtable) amount)))
|
|
(setf (gethash from hashtable) remaining-part)
|
|
(setf (gethash to hashtable) (concatenate 'list moving-part (gethash to hashtable)))))
|
|
|
|
;; so, taking is subseq, but wound need to drop these elements
|
|
;; but how to prepend list to another list? concat?
|
|
(concatenate 'list (list 1 2 3) (list 5 6 7))
|
|
(subseq (list 1 2 3 4 5) 0 2) ; so "until end"
|
|
(subseq (list 1 2 3 4 5) 2)
|
|
|
|
;; nullify hash with boxes before running
|
|
(with-open-file (in "day5-test-input.txt")
|
|
(loop
|
|
for line = (read-line in nil nil)
|
|
while line
|
|
do (apply #'run-command-9001 (cons *test-boxes* (command-string-to-indices line)))))
|
|
|
|
(with-open-file (in "day5-input.txt")
|
|
(loop
|
|
for line = (read-line in nil nil)
|
|
while line
|
|
do (apply #'run-command-9001 (cons *day-5-boxes* (command-string-to-indices line)))))
|