diff --git a/day19-2-input.txt b/day19-2-input.txt new file mode 100644 index 0000000..22c16d9 --- /dev/null +++ b/day19-2-input.txt @@ -0,0 +1,3 @@ +Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 12 clay. Each geode robot costs 4 ore and 19 obsidian. +Blueprint 2: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 11 clay. Each geode robot costs 4 ore and 12 obsidian. +Blueprint 3: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 2 ore and 11 obsidian. diff --git a/day19-input.txt b/day19-input.txt new file mode 100644 index 0000000..2c1044f --- /dev/null +++ b/day19-input.txt @@ -0,0 +1,30 @@ +Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 12 clay. Each geode robot costs 4 ore and 19 obsidian. +Blueprint 2: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 11 clay. Each geode robot costs 4 ore and 12 obsidian. +Blueprint 3: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 2 ore and 11 obsidian. +Blueprint 4: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 4 ore and 20 obsidian. +Blueprint 5: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 16 clay. Each geode robot costs 4 ore and 17 obsidian. +Blueprint 6: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 19 clay. Each geode robot costs 2 ore and 12 obsidian. +Blueprint 7: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 9 clay. Each geode robot costs 2 ore and 10 obsidian. +Blueprint 8: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 5 clay. Each geode robot costs 3 ore and 7 obsidian. +Blueprint 9: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 11 clay. Each geode robot costs 4 ore and 8 obsidian. +Blueprint 10: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 16 clay. Each geode robot costs 2 ore and 15 obsidian. +Blueprint 11: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 20 clay. Each geode robot costs 2 ore and 19 obsidian. +Blueprint 12: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 16 clay. Each geode robot costs 3 ore and 20 obsidian. +Blueprint 13: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 3 ore and 14 obsidian. +Blueprint 14: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 2 ore and 15 obsidian. +Blueprint 15: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 3 ore and 12 obsidian. +Blueprint 16: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 17 clay. Each geode robot costs 3 ore and 19 obsidian. +Blueprint 17: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 4 ore and 9 obsidian. +Blueprint 18: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 6 clay. Each geode robot costs 3 ore and 16 obsidian. +Blueprint 19: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 6 clay. Each geode robot costs 2 ore and 14 obsidian. +Blueprint 20: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 11 clay. Each geode robot costs 3 ore and 15 obsidian. +Blueprint 21: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 18 clay. Each geode robot costs 4 ore and 19 obsidian. +Blueprint 22: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 2 ore and 20 obsidian. +Blueprint 23: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 5 clay. Each geode robot costs 2 ore and 10 obsidian. +Blueprint 24: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 10 clay. Each geode robot costs 2 ore and 14 obsidian. +Blueprint 25: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 7 clay. Each geode robot costs 4 ore and 13 obsidian. +Blueprint 26: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 20 clay. Each geode robot costs 2 ore and 20 obsidian. +Blueprint 27: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 18 clay. Each geode robot costs 2 ore and 19 obsidian. +Blueprint 28: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 10 clay. Each geode robot costs 2 ore and 7 obsidian. +Blueprint 29: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 15 clay. Each geode robot costs 3 ore and 7 obsidian. +Blueprint 30: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 4 ore and 18 obsidian. diff --git a/day19-scratch.lisp b/day19-scratch.lisp index 3e632ad..1c21f7c 100644 --- a/day19-scratch.lisp +++ b/day19-scratch.lisp @@ -344,22 +344,15 @@ (defmethod find-max-geod-2 (blueprints (s state)) ;; (declare (optimize (debug 3))) - (format t "in step for ~a; with ~a~%" (minute s) s) - (when (and - (not (cur-found-max s)) ; first pruning max - (is-satiated-p blueprints s)) - (setf (cur-found-max s) s)) - + ;; (format t "in step for ~a; with ~a~%" (minute s) s) (cond ((= 25 (minute s)) ; exit condition fully calculated (getf (resources s) :geode 0)) - ((and (cur-found-max s) (a-dominates-b-p blueprints (cur-found-max s) s) - 0)) ; pruning this branch + ((< (estimate s) (cur-found-max s)) + ;; (print "pruning") + 0) ; pruning this branch (t ; default check (progn - (when (and (cur-found-max s) - (a-dominates-b-p blueprints s (cur-found-max s))) - (setf (cur-found-max s) s)) ; set current state as domineering (let* ((will-collect-this-minute (calc-resources-to-be-collected s)) (possible-bot-builds (get-possible-bot-builds blueprints s)) (max-if-building @@ -377,15 +370,93 @@ ;; (break) (add-resources will-collect-this-minute state-copy) (incf (minute state-copy)) - (find-max-geod-2 blueprints state-copy )))) + (find-max-geod-2 blueprints state-copy ))) + (recursed-max (max (or max-if-building 0) if-not-building))) ;; (break) ;; (format t "would build ~a~%" possible-bot-builds) - (max (or max-if-building 0) if-not-building)))))) + (when (> recursed-max (cur-found-max s)) + (setf (cur-found-max s) recursed-max)) + recursed-max + ))))) (setq *test-state* (make-instance 'state)) -(setf (cur-found-max *test-state*) nil) -(print (find-max-geod-2 *test-blueprint* *test-state*)) +(setf (cur-found-max *test-state*) 0) +(timing (print (find-max-geod-2 *test-blueprint* *test-state*))) +(timing (let ((a 1) (b 2)) (* a b 15))) +;; thank you CL-Cookbook: https://cl-cookbook.sourceforge.net/dates_and_times.html +(defmacro timing (&body forms) + (let ((real1 (gensym)) + (real2 (gensym)) + (run1 (gensym)) + (run2 (gensym)) + (result (gensym))) + `(let* ((,real1 (get-internal-real-time)) + (,run1 (get-internal-run-time)) + (,result (progn ,@forms)) + (,run2 (get-internal-run-time)) + (,real2 (get-internal-real-time))) + (format *debug-io* ";;; Computation took:~%") + (format *debug-io* ";;; ~f seconds of real time~%" + (/ (- ,real2 ,real1) internal-time-units-per-second)) + (format t ";;; ~f seconds of run time~%" + (/ (- ,run2 ,run1) internal-time-units-per-second)) + ,result))) ;; so, why doesn't it ever builds obsidian? *test-blueprint* ;; because is "has to build something if it can" whops +;; wow 20 seconds. cool + +;; last things: +;; read in the line for the blueprints into plist +;; then loop over lines in file +;; for each line compute max, multiply by index +;; and sum +;; ok, i guess + +(rest (remove-if-not #'identity + (mapcar (lambda (str) (parse-integer str :junk-allowed t)) + (ppcre:split " " + "Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian.")))) + +(blueprint-line-to-plist "Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian.") + +;; and now loop over file. + +(print (with-open-file (in "day19-test.txt") + (loop + for line = (read-line in nil nil) + for n from 1 + for blueprints = (when line (progn + (format t "Starting processing for ~a~%" line) + (blueprint-line-to-plist line))) + for max-geo = 0 + ;; for max-geo = (when blueprints + ;; (progn + ;; (setf (cur-found-max *test-state*) 0) + ;; (timing (find-max-geod-2 blueprints (make-instance 'state))))) + while blueprints + do (format t "processed ~a : ~a. its max is ~a~%" n blueprints max-geo) + summing (* n max-geo)))) + + +(format t "and the result is : ~a~%" (read-and-calc-part-1 "day19-test.txt")) + +(format t "and the result is : ~a~%" (read-and-calc-part-1 "day19-input.txt")) + +;; wtf is taking so long in between the processings? + +(apply #'* (list 2 3 5)) + +;; but before that - change exit point +(format t "and the result is : ~a~%" (read-and-calc-part-2 "day19-2-input.txt")) +;; 261 is too low. so +;; but in previous my maxes were 0 1 2 +;; and current are 3 3 29 +;; but still not good +;; ugh. what about test input? + +(format t "and the result is : ~a~%" (read-and-calc-part-2 "day19-test.txt")) +;; my calc : 18 and 55 +;; correct : 56 and 62 +;; coooool. let's move on. diff --git a/day19-test.txt b/day19-test.txt new file mode 100644 index 0000000..f39c094 --- /dev/null +++ b/day19-test.txt @@ -0,0 +1,2 @@ +Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian. +Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian. diff --git a/day19.lisp b/day19.lisp index 5205148..8eaa242 100644 --- a/day19.lisp +++ b/day19.lisp @@ -3,6 +3,8 @@ (:use :cl)) (in-package :day-19) +(ql:quickload 'cl-ppcre) + (defparameter *all-types* '(:geode :obsidian :clay :ore)) (defclass state () @@ -96,3 +98,96 @@ (getf (resources b) resource-type 0)) (>= (getf (robots a) resource-type 0) (getf (robots b) resource-type 0)))))))) + +;; loose bound on geodes +(defmethod estimate ((s state)) + (let ((time-left (- 25 (minute s)))) + (+ (getf (resources s) :geode 0) + (* time-left (getf (robots s) :geode 0)) + (/ (* time-left (1- time-left)) 2)))) + +(defmethod find-max-geod-2 (blueprints (s state)) + (declare (optimize (speed 3))) + ;; (declare (optimize (debug 3))) + ;; (format t "in step for ~a; with ~a~%" (minute s) s) + (cond + ( + (= 33 (minute s)) ; exit condition fully calculated + ;; (= 25 (minute s)) ; exit condition fully calculated + (getf (resources s) :geode 0)) + ((< (estimate s) (cur-found-max s)) + ;; (print "pruning") + 0) ; pruning this branch + (t ; default check + (progn + (let* ((will-collect-this-minute (calc-resources-to-be-collected s)) + (possible-bot-builds (get-possible-bot-builds blueprints s)) + (max-if-building + (when possible-bot-builds + (loop + for bot-type in possible-bot-builds + for state-with-new-bot = (create-robot blueprints bot-type s) + when state-with-new-bot + maximize (progn + (add-resources will-collect-this-minute state-with-new-bot) + (incf (minute state-with-new-bot)) + (find-max-geod-2 blueprints state-with-new-bot ))))) + (if-not-building + (let ((state-copy (copy-state s))) + ;; (break) + (add-resources will-collect-this-minute state-copy) + (incf (minute state-copy)) + (find-max-geod-2 blueprints state-copy ))) + (recursed-max (max (or max-if-building 0) if-not-building))) + ;; (break) + ;; (format t "would build ~a~%" possible-bot-builds) + (when (> recursed-max (cur-found-max s)) + (setf (cur-found-max s) recursed-max)) + recursed-max + ))))) + + +(defun blueprint-line-to-plist (line) + (destructuring-bind + (ore-cost-in-ore clay-cost-in-ore obs-cost-in-ore obs-cost-in-clay + geod-cost-in-ore geod-cost-in-obs) + (rest (remove-if-not #'identity + (mapcar (lambda (str) (parse-integer str :junk-allowed t)) + (ppcre:split " " line)))) + `(:ore (:ore ,ore-cost-in-ore) + :clay (:ore ,clay-cost-in-ore) + :obsidian (:ore ,obs-cost-in-ore :clay ,obs-cost-in-clay) + :geode (:ore ,geod-cost-in-ore :obsidian ,geod-cost-in-obs)))) + +(defun read-and-calc-part-1 (filename) + (with-open-file (in filename) + (loop + for line = (read-line in nil nil) + for n from 1 + for blueprints = (when line (blueprint-line-to-plist line)) + for max-geo = (when blueprints + (progn + (setf (cur-found-max *test-state*) + 0) + (format t "Starting processing for ~a" line) + (timing (find-max-geod-2 blueprints (make-instance 'state))))) + while blueprints + do (format t "processed ~a. its max is ~a~%" n max-geo) + summing (* n max-geo)))) + +(defun read-and-calc-part-2 (filename) + (with-open-file (in filename) + (loop + for line = (read-line in nil nil) + for n from 1 + for blueprints = (when line (progn + (format t "Starting processing for ~a~%" line) + (blueprint-line-to-plist line))) + for max-geo = (when blueprints + (progn + (setf (cur-found-max *test-state*) 0) + (timing (find-max-geod-2 blueprints (make-instance 'state))))) + while blueprints + do (format t "processed ~a. its max is ~a~%" n max-geo) + collecting max-geo into maxes + finally (return (apply #'* maxes)))))