Last active
December 18, 2017 19:30
-
-
Save pavloo/b9b79253d39f820e50d3b8dc70aecaaa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defstruct node name weight parent) | |
(defun split-and-trim-each (&rest args) | |
(mapcar 'string-trim (apply 'split-string (append args (list t)))) | |
) | |
(defun parse-weight (str) | |
(string-to-number (substring str 1 -1)) | |
) | |
(defun process-read-line (line) | |
(let (name weight children l n node children) | |
(setq l (split-and-trim-each line "->")) | |
(setq n (split-and-trim-each (nth 0 l) " ")) | |
(setq node (make-node :name (nth 0 n) :weight (parse-weight (nth 1 n)))) | |
(when (= (length l) 2) (setq children (split-and-trim-each (nth 1 l) ","))) | |
`((:node . ,node) (:children . ,children)) | |
) | |
) | |
(defun read-file (file-path) | |
(with-temp-buffer | |
(insert-file-contents file-path) | |
(mapcar 'process-read-line (split-string (buffer-string) "\n" t)) | |
) | |
) | |
(defun find-root (file-name) | |
(let (list node parent (dict (make-hash-table :test 'equal)) name root-name diff) | |
(setq list (read-file file-name)) | |
(dolist (item list) | |
(setq node (cdr (assoc :node item))) | |
(puthash (node-name node) item dict) | |
) | |
(dolist (item list) | |
(setq parent (cdr (assoc :node item))) | |
(setq name (node-name parent)) | |
(dolist (child-name (cdr (assoc :children (gethash name dict)))) | |
(setq node (cdr (assoc :node (gethash child-name dict)))) | |
(setf (node-parent node) parent) | |
) | |
) | |
(setq root-name (catch 'break | |
(dolist (item list) | |
(setq node (cdr (assoc :node item))) | |
(when (not (node-parent node)) (throw 'break (node-name node))) | |
) | |
)) | |
(print (format "Part 1: %s" root-name)) | |
(setq diff (visit-subtree root-name dict nil nil)) | |
(print (format "Part 2: %s" (find-diff-value (nth 2 diff) (nth 1 diff) (node-weight (cdr (assoc :node (gethash (nth 0 diff) dict))))))) | |
) | |
) | |
(defun sum-subtree (head-name tree-dict) | |
(let ((s 0) node) | |
(setq node (cdr (assoc :node (gethash head-name tree-dict)))) | |
(setq s (+ s (node-weight node))) | |
(dolist (child-name (cdr (assoc :children (gethash head-name tree-dict)))) | |
(setq node (cdr (assoc :node (gethash child-name tree-dict)))) | |
(setq s (+ s (sum-subtree child-name tree-dict))) | |
) | |
s | |
) | |
) | |
(defun find-diff-value (list diff-i weight) | |
(let ((ii 0)) | |
(when (= diff-i 0) (setq ii (1- (length list)))) | |
(+ (- (node-weight (nth ii list)) (node-weight (nth diff-i list))) weight) | |
) | |
) | |
(defun visit-subtree (n-name tree-dict last-diff-i last-res) | |
(let (res diff-i diff-node node) | |
(dolist (child-name (cdr (assoc :children (gethash n-name tree-dict)))) | |
(push (make-node :name child-name :weight (sum-subtree child-name tree-dict)) res) | |
) | |
(setq diff-i (find-different (mapcar (lambda (node) (node-weight node)) res))) | |
(setq node (cdr (assoc :node (gethash n-name tree-dict)))) | |
(if (not (= diff-i -1)) | |
(visit-subtree (node-name (nth diff-i res)) tree-dict diff-i res) | |
(progn | |
(list n-name last-diff-i last-res) | |
) | |
) | |
) | |
) | |
;; this could have been sort and compare i and i + 1 | |
(defun find-different (list) | |
(let (not-eq) | |
(catch 'break | |
(loop | |
for i from 0 to (1- (length list)) | |
do | |
(progn | |
(loop | |
for j from 0 to (1- (length list)) | |
do | |
(progn | |
(when (not (= (nth i list) (nth j list))) | |
(if not-eq (throw 'break i) (setq not-eq t))) | |
) | |
) | |
(setq not-eq nil) | |
) | |
) | |
-1 | |
) | |
) | |
) | |
(find-root "./default_input.txt") ;; tknk 60 | |
(find-root "./input.txt") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment