From d1e05629a458bc56da70c6d86dd1e2647ba07b6e Mon Sep 17 00:00:00 2001 From: Jacopo De Simoi Date: Sun, 30 Mar 2025 23:06:19 -0400 Subject: [PATCH] And take care of number 9 too --- p9/p9.org | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 p9/p9.org diff --git a/p9/p9.org b/p9/p9.org new file mode 100644 index 0000000..d0e51f7 --- /dev/null +++ b/p9/p9.org @@ -0,0 +1,107 @@ +#+title: Solution of 2024-p9 + +Now, this was a bit more challenging than the others + +This binds ~data~ to the test input +#+begin_src emacs-lisp + (setq data "2333133121414131402") +#+end_src + +This instead binds ~data~ to the actual input +#+begin_src emacs-lisp + (with-temp-buffer + (insert-file-contents "input") + (goto-char (point-min)) + (replace-regexp "^" "\"") + (goto-char (point-min)) + (replace-regexp "$" "\"") + (goto-char (point-min)) + (insert "(setq data ") + (goto-char (point-max)) + (insert ")") + (eval-buffer)) +#+end_src + +#+RESULTS: + +This creates a index of the disk: each element is ~(file index +. length)~, where ~file index~ is ~nil~ if the node is empty +#+begin_src emacs-lisp +(setq disk-index (-map-indexed (lambda (index el) + (if (eq 0 (% index 2)) + (cons (/ index 2) el) + (cons nil el))) + (-map #'string-to-number (split-string data "\\|.+" t))) ) +#+end_src + +This creates the disk image from the index +#+begin_src emacs-lisp + (defun disk-from-index (d-index) + (-mapcat (lambda (x) (-repeat (cdr x) (car x))) d-index)) + + (setq disk (disk-from-image disk-index)) +#+end_src +* Part 1: +** The recursive approach +This works for the test input but stack overflows for the actual input +since elisp does not have tail call optimization +#+begin_src emacs-lisp +(defun defrag (disk) + (let ((i (-find-index #'not disk)) + (j (-find-last-index #'identity disk)) ) + (if (> i j) disk + (defrag (-replace-at j nil (-replace-at i (nth j disk) disk)))))) +#+end_src +** The while-loop approach +This works, but is quite horrible +#+begin_src emacs-lisp +(defun defrag-loop (disk) + (let ((i (-find-index #'not disk)) + (j (-find-last-index #'identity disk)) ) + (while (<= i j) + (setq disk (-replace-at j nil (-replace-at i (nth j disk) disk))) + (setq i (-find-index #'not disk) + j (-find-last-index #'identity disk)))) + disk ) +#+end_src +** The reduce-with-a-copy approach +#+begin_src emacs-lisp + (defun defrag-reduce (disk) + (-reduce-r-from (lambda (el acc) + (if (not el) acc + (let ((i (-find-index #'not acc)) + (j (-find-last-index #'identity acc))) + (if (> i j) acc + (-replace-last el nil (-replace-at i el acc)))))) + disk disk)) +#+end_src +And, compute! +#+begin_src emacs-lisp + (-reduce #'+ (-map-indexed (lambda (i file) (* i file)) (-non-nil (defrag-reduce disk)))) + + 6241633730082 + +#+end_src + +* Part 2: defragging whole files +This is fun, now we start from the index +#+begin_src emacs-lisp + (defun defrag-index (d-index) + (-reduce-r-from (lambda (el acc) + (if (not (car el)) acc + (let ((i (-find-index (lambda (ell) + (and (not (car ell)) (>= (cdr ell) (cdr el)))) acc)) + (j (-find-last-index (lambda (e) (equal e el)) acc))) + (if (or (not i) (> i j)) acc + (-insert-at i el (-replace-at i (cons nil (- (cdr (nth i acc)) (cdr el))) (-replace-last el (cons nil (cdr el)) acc))))))) + d-index d-index)) +#+end_src +And compute +#+begin_src emacs-lisp + (-reduce #'+ (-map-indexed (lambda (i file) (if file (* i file) 0)) (disk-from-index (defrag-index disk-index)))) +#+end_src + +#+RESULTS: +: 6265268809555 + +**