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