Skip to content

Instantly share code, notes, and snippets.

@pavloo
Last active December 18, 2017 19:30
Show Gist options
  • Save pavloo/b9b79253d39f820e50d3b8dc70aecaaa to your computer and use it in GitHub Desktop.
Save pavloo/b9b79253d39f820e50d3b8dc70aecaaa to your computer and use it in GitHub Desktop.
(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