Solve time is like 36 hours, that must be a record! Change-Id: I3713f033d83e6179a5d5fa7513952ee3864a6164 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2238 Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
		
			
				
	
	
		
			92 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			EmacsLisp
		
	
	
	
	
	
			
		
		
	
	
			92 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			EmacsLisp
		
	
	
	
	
	
;; Advent of Code 2020 - Day 7
 | 
						|
 | 
						|
(require 'cl-lib)
 | 
						|
(require 'dash)
 | 
						|
(require 'f)
 | 
						|
(require 's)
 | 
						|
(require 'ht)
 | 
						|
 | 
						|
(defvar day7/input
 | 
						|
  (s-lines (s-chomp (f-read "/tmp/aoc/day7.txt"))))
 | 
						|
 | 
						|
(defun day7/parse-bag (input)
 | 
						|
  (string-match (rx line-start
 | 
						|
                    (group (one-or-more (or letter space)))
 | 
						|
                    "s contain "
 | 
						|
                    (group (one-or-more anything))
 | 
						|
                    "." line-end)
 | 
						|
                input)
 | 
						|
  (cons (match-string 1 input)
 | 
						|
        (-map
 | 
						|
         (lambda (content)
 | 
						|
           (unless (equal content "no other bags")
 | 
						|
             (progn
 | 
						|
               (string-match
 | 
						|
                (rx (group (one-or-more digit))
 | 
						|
                    space
 | 
						|
                    (group (one-or-more anything) "bag"))
 | 
						|
                content)
 | 
						|
               (cons (match-string 2 content)
 | 
						|
                     (string-to-number (match-string 1 content))))))
 | 
						|
         (s-split ", " (match-string 2 input)))))
 | 
						|
 | 
						|
(defun day7/id-or-next (table bag-type)
 | 
						|
  (unless (ht-contains? table bag-type)
 | 
						|
    (ht-set table bag-type (length (ht-keys table))))
 | 
						|
  (ht-get table bag-type))
 | 
						|
 | 
						|
(defun day7/build-graph (input &optional flip)
 | 
						|
  "Represent graph mappings directionally using an adjacency
 | 
						|
  matrix, because that's probably easiest.
 | 
						|
 | 
						|
  By default an edge means 'contains', with optional argument
 | 
						|
  FLIP edges are inverted and mean 'contained by'."
 | 
						|
 | 
						|
  (let ((bag-mapping (ht-create))
 | 
						|
        (graph (let ((length (length input)))
 | 
						|
                 (apply #'vector
 | 
						|
                        (-map (lambda (_) (make-vector length 0)) input)))))
 | 
						|
    (cl-loop for bag in (-map #'day7/parse-bag input)
 | 
						|
             for bag-id = (day7/id-or-next bag-mapping (car bag))
 | 
						|
             do (-each (-filter #'identity (cdr bag))
 | 
						|
                  (pcase-lambda (`(,contained-type . ,count))
 | 
						|
                    (let ((contained-id (day7/id-or-next bag-mapping contained-type)))
 | 
						|
                      (if flip
 | 
						|
                          (aset (aref graph contained-id) bag-id count)
 | 
						|
                        (aset (aref graph bag-id) contained-id count))))))
 | 
						|
    (cons bag-mapping graph)))
 | 
						|
 | 
						|
;; Puzzle 1
 | 
						|
 | 
						|
(defun day7/find-ancestors (visited graph start)
 | 
						|
  (ht-set visited start t)
 | 
						|
  (cl-loop for bag-count being the elements of (aref graph start)
 | 
						|
           using (index bag-id)
 | 
						|
           when (and (> bag-count 0)
 | 
						|
                     (not (ht-contains? visited bag-id)))
 | 
						|
           do (day7/find-ancestors visited graph bag-id)))
 | 
						|
 | 
						|
(message
 | 
						|
 "Solution to day7/1: %s"
 | 
						|
 (pcase-let* ((`(,mapping . ,graph) (day7/build-graph day7/input t))
 | 
						|
              (shiny-gold-id (ht-get mapping "shiny gold bag"))
 | 
						|
              (visited (ht-create)))
 | 
						|
   (day7/find-ancestors visited graph shiny-gold-id)
 | 
						|
   (- (length (ht-keys visited)) 1)))
 | 
						|
 | 
						|
;; Puzzle 2
 | 
						|
 | 
						|
(defun ht-find-by-value (table value)
 | 
						|
  (ht-find (lambda (_key item-value) (equal item-value value)) table))
 | 
						|
 | 
						|
(defun day7/count-contained-bags (mapping graph start)
 | 
						|
  (cl-loop for bag-count being the elements of (aref graph start)
 | 
						|
           using (index bag-id)
 | 
						|
           when (> bag-count 0)
 | 
						|
           sum (+ bag-count
 | 
						|
                  (* bag-count (day7/count-contained-bags mapping graph bag-id)))))
 | 
						|
 | 
						|
(message "Solution to day7/2: %s"
 | 
						|
         (pcase-let* ((`(,mapping . ,graph) (day7/build-graph day7/input))
 | 
						|
                      (shiny-gold-id (ht-get mapping "shiny gold bag")))
 | 
						|
           (day7/count-contained-bags mapping graph shiny-gold-id)))
 |