You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

112 lines
3.1 KiB

#+title: Solution to p12
Load the file into a list of lines
#+begin_src emacs-lisp
(require 'dash)
(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:
and split into a list of list of chars
#+begin_src emacs-lisp :no-results
(setq data-chars (-map (lambda (str) (--map (string-to-char it) (split-string str "\\|.+" t)))
data)
height (length data-chars)
width (length (car data-chars)))
#+end_src
#+RESULTS:
: 140
#+begin_src emacs-lisp :results silent
(defun acceptable-p (p)
(let ((x (car p))
(y (cadr p)))
(and (>= x 0) (>= y 0) (< x width) (< y height)) ))
(defun neighbours (p)
(let ((x (car p))
(y (cadr p)))
(-map (lambda (q) (list (+ x (car q)) (+ y (cadr q)))) '((+1 0) (-1 0) (0 1) (0 -1)))))
(defun acceptable-neighbours (p)
(-filter #'acceptable-p (neighbours p)))
(defun plant (p)
(if (not (acceptable-p p)) ?.
(nth (car p) (nth (cadr p) data-chars))))
#+end_src
collect all plants type and return a list of list of positions
#+begin_src emacs-lisp :results none
(setq plants (-distinct (-mapcat #'identity data-chars)))
(setq groups (-map (lambda (pl)
(-map #'cadr
(--filter (eq (car it) pl)
(-mapcat #'identity
(-map-indexed (lambda (y l) (-map-indexed (lambda (x el) (list el (list x y))) l)) data-chars)))))
plants))
#+end_src
now we need to split each group into regions
ACC is a list of regions. The function
#+begin_src emacs-lisp :results none
(defun agglomerate (acc el)
(let ((nbhs (acceptable-neighbours el)))
(cons (-mapcat #'identity (cons (list el) (--filter (-intersection it nbhs) acc)))
(--filter (not (-intersection it nbhs)) acc))
)
)
(setq regions (--mapcat (-reduce-from #'agglomerate nil it) groups))
#+end_src
#+begin_src emacs-lisp
(defun count-fence (el)
(let ((i (plant el))
(pos el))
(length (--filter (not (eq i it)) (-map #'plant (neighbours pos))))))
(defun vertex-p (el dir)
(let* ((x (car el))
(y (cadr el))
(a (car dir))
(b (cadr dir))
(opposite (list (+ x a) (+ y b)))
(adjh (list (+ x a) y))
(adjv (list x (+ y b))))
(or (and (not (eq (plant el) (plant adjh)))
(not (eq (plant el) (plant adjv))))
(and (eq (plant el) (plant adjh))
(eq (plant el) (plant adjv))
(not (eq (plant el) (plant opposite))))))
)
(defun count-vertices (el)
(length (-non-nil (--map (vertex-p el it) '((1 1) (1 -1) (-1 1) (-1 -1)))))
)
(-reduce #'+ (--map (* (car it) (cdr it))
(-zip-pair (-map #'length regions)
(-map (lambda (region) (-reduce #'+ (-map #'count-fence region))) regions))))
(-reduce #'+ (--map (* (car it) (cdr it))
(-zip-pair (-map #'length regions)
(-map (lambda (region) (-reduce #'+ (-map #'count-vertices region))) regions))))
#+end_src
#+RESULTS:
: 859494