src/2018/days/day-12.lisp @ baf889db8d40
2019/07
| author | Steve Losh <steve@stevelosh.com> |
|---|---|
| date | Sat, 07 Dec 2019 16:58:32 -0500 |
| parents | cd781337a694 |
| children | 182bdd87fd9e |
(defpackage :advent/2018/12 #.cl-user::*advent-use*) (in-package :advent/2018/12) (named-readtables:in-readtable :interpol-syntax) ;;;; Pots --------------------------------------------------------------------- (defstruct pots data min max) (defmethod print-object ((o pots) s) (print-unreadable-object (o s :type t) (format s "~D to ~D: ~A" (pots-min o) (pots-max o) (iterate (for i :from (pots-min o) :to (pots-max o)) (collect (if (plusp (pot o i)) #\# #\.) :result-type 'string))))) (defun-inline pot (pots i) (if (hset-contains-p (pots-data pots) i) 1 0)) (defun add-pot (pots i) (hset-insert! (pots-data pots) i)) (defun rem-pot (pots i) (hset-remove! (pots-data pots) i)) (defun surroundings (pots i) (make-array 5 :element-type 'bit :initial-contents (list (pot pots (- i 2)) (pot pots (- i 1)) (pot pots i) (pot pots (+ i 1)) (pot pots (+ i 2))))) (defun score (pots) (summation (hset-elements (pots-data pots)))) ;;;; Input Parsing ------------------------------------------------------------ (defun rune-bit (rune) (ecase rune (#\# 1) (#\. 0))) (defun runes-to-bits (runes) (map 'bit-vector #'rune-bit runes)) (defun vector-to-hash-set (vector &key (test #'eql)) (iterate (with result = (make-hash-set :test test)) (for value :in-vector vector :with-index i) (when (plusp value) (hset-insert! result i)))) (defun parse-initial-line (line) (ppcre:register-groups-bind (state) (#?r"initial state: (\S+)" line) (-<> state runes-to-bits (positions-if #'plusp <>) (make-hash-set :initial-contents <>)))) (defun parse-rule (line) (ppcre:register-groups-bind (surroundings result) (#?r"(\S+) => (\S)" line) (values (runes-to-bits surroundings) (rune-bit (aref result 0))))) (defun read-problem (stream) (let* ((initial (parse-initial-line (read-line stream))) (state (prog1 (make-pots :data initial :min (extremum (hset-elements initial) '<) :max (extremum (hset-elements initial) '>)) (read-line stream))) (rules (iterate (for line :in-stream stream :using #'read-line) (unless (string= "" line) (for (values key result) = (parse-rule line)) (collect-hash (key result) :test #'equal))))) (values state rules))) ;;;; Solve -------------------------------------------------------------------- (defun tick (pots rules) (with-slots (min max) pots (iterate (for i :from (- min 2) :to (+ max 2)) (for current = (pot pots i)) (for surroundings = (surroundings pots i)) (for next = (gethash surroundings rules)) (when (plusp next) (minimizing i :into next-min) (maximizing i :into next-max)) (when (/= current next) (if (plusp next) (collect i :into add) (collect i :into rem))) (finally (map nil (curry #'add-pot pots) add) (map nil (curry #'rem-pot pots) rem) (setf min next-min max next-max) pots)))) (define-problem (2018 12) (data) () ;; can't really test noninteractively :( (multiple-value-bind (pots rules) (read-problem data) (values (progn (do-repeat 20 (tick pots rules)) (score pots)) (iterate (for tick :from 20) (format t "~%After ~D tick~:P:~%~A~%score: ~D~%> " tick pots (score pots)) (force-output) (for input = (read-line)) (until (string= "q" input)) (tick pots rules))))) (defun part-2 () (let* ((score-per-tick 20) (starting-tick 350) (starting-value 7508) (ticks (- 50000000000 starting-tick))) (+ starting-value (* score-per-tick ticks))))