this is "optimization"
This commit is contained in:
parent
83f65babdf
commit
bf52645d93
@ -134,7 +134,7 @@
|
|||||||
(let* ((will-collect-this-minute (calc-resources-to-be-collected s))
|
(let* ((will-collect-this-minute (calc-resources-to-be-collected s))
|
||||||
(max-if-building
|
(max-if-building
|
||||||
(loop
|
(loop
|
||||||
for bot-type in *add-types*
|
for bot-type in (get-possible-bot-builds blueprints s)
|
||||||
for state-with-new-bot = (create-robot blueprints bot-type s)
|
for state-with-new-bot = (create-robot blueprints bot-type s)
|
||||||
when state-with-new-bot
|
when state-with-new-bot
|
||||||
maximize (progn
|
maximize (progn
|
||||||
@ -164,7 +164,7 @@
|
|||||||
:geode (:ore 2 :obsidian 7)))
|
:geode (:ore 2 :obsidian 7)))
|
||||||
(setq *test-state* (make-instance 'state))
|
(setq *test-state* (make-instance 'state))
|
||||||
|
|
||||||
(print (find-max-geod *test-blueprint* *test-state* 1))
|
;; (print (find-max-geod *test-blueprint* *test-state* 1))
|
||||||
;; => 0
|
;; => 0
|
||||||
;; that's because i have no ability to "wait"
|
;; that's because i have no ability to "wait"
|
||||||
;; whoops
|
;; whoops
|
||||||
@ -212,3 +212,180 @@
|
|||||||
;; but only over states with same amount of steps?
|
;; but only over states with same amount of steps?
|
||||||
|
|
||||||
;; ok. let's commit what i have right now and try to trim?
|
;; ok. let's commit what i have right now and try to trim?
|
||||||
|
|
||||||
|
;; how could i compare with that "cur-max" and update that cur-max?
|
||||||
|
;; no, i don't understand
|
||||||
|
|
||||||
|
(format t "some result ~a~%" (find-max-geod *test-blueprint* *test-state* 1))
|
||||||
|
|
||||||
|
;; well, yes one optimizaiton - stop building robots, when resource is to the top of
|
||||||
|
;; max daily expense
|
||||||
|
;; that would reduce a lot
|
||||||
|
;; 1)
|
||||||
|
;; would be nice to put these into (possible-robots-to-build)
|
||||||
|
;; so that it would also filtered out unnecessary new robots
|
||||||
|
;;
|
||||||
|
;; 2)
|
||||||
|
;; "keep global current max state" how would i compare and check if it's impossible to beat?
|
||||||
|
;; with "even if i could to build geod machine every day for rest N days"
|
||||||
|
|
||||||
|
*test-blueprint*
|
||||||
|
*test-state*
|
||||||
|
(add-resources '(:ore 10) *test-state*)
|
||||||
|
(incf (getf (robots *test-state*) :ore) 2)
|
||||||
|
(any-use-of-creating-robot *test-blueprint* *test-state* :ore)
|
||||||
|
(any-use-of-creating-robot *test-blueprint* *test-state* :clay)
|
||||||
|
(any-use-of-creating-robot *test-blueprint* *test-state* :obsidian)
|
||||||
|
(any-use-of-creating-robot *test-blueprint* *test-state* :geode)
|
||||||
|
|
||||||
|
(max-need *test-blueprint* *test-state* :ore)
|
||||||
|
(max-need *test-blueprint* *test-state* :clay)
|
||||||
|
(max-need *test-blueprint* *test-state* :obsidian)
|
||||||
|
(max-need *test-blueprint* *test-state* :geode)
|
||||||
|
|
||||||
|
;; and this is not good for :geode, we want as much as possible
|
||||||
|
|
||||||
|
(get-possible-bot-builds *test-blueprint* *test-state*)
|
||||||
|
|
||||||
|
;; and now let's add static "max state"?
|
||||||
|
;; i'd need comparison like "can catch up" with that found max "is dominated by"
|
||||||
|
;; and also way to update that maximal state?
|
||||||
|
;;
|
||||||
|
;; so, what will that be?
|
||||||
|
;; comparison for update, should it also be if i found a state that dominates?
|
||||||
|
;; only for satiated states?
|
||||||
|
;;
|
||||||
|
;; if day is same or more
|
||||||
|
;; but the amount of geode robots and geodes is smaller?
|
||||||
|
(is-satiated-p *test-blueprint* *test-state*)
|
||||||
|
(incf (getf (robots *test-state*) :obsidian 0) 20)
|
||||||
|
;; seems to work,
|
||||||
|
;; but i already want to utilize some test framework
|
||||||
|
|
||||||
|
;; whelp. i do want to test this
|
||||||
|
;; 4 14 7 to be satisfied
|
||||||
|
(is-satiated-p
|
||||||
|
*test-blueprint*
|
||||||
|
(make-instance 'state :robots '(:ore 4 :clay 14 :obsidian 7 :geode 2)))
|
||||||
|
|
||||||
|
(is-satiated-p
|
||||||
|
*test-blueprint*
|
||||||
|
(make-instance 'state :resources '(:ore 4 :clay 14 :obsidian 7 :geode 2))) ; not, need robots
|
||||||
|
|
||||||
|
(is-satiated-p
|
||||||
|
*test-blueprint*
|
||||||
|
(make-instance 'state :robots '(:ore 4 :clay 14 :obsidian 7 :geode 2)))
|
||||||
|
|
||||||
|
;; now for checking is-dominated. ugh.
|
||||||
|
(a-dominates-b-p
|
||||||
|
*test-blueprint*
|
||||||
|
(make-instance 'state :robots '(:ore 4 :clay 14 :obsidian 7 :geode 2))
|
||||||
|
(make-instance 'state :robots '(:ore 4 :clay 14 :obsidian 7 :geode 2)))
|
||||||
|
|
||||||
|
;; both satiated, but second bigger
|
||||||
|
(a-dominates-b-p
|
||||||
|
*test-blueprint*
|
||||||
|
(make-instance 'state :robots '(:ore 5 :clay 17 :obsidian 7 :geode 2))
|
||||||
|
(make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 7 :geode 2)))
|
||||||
|
;;
|
||||||
|
;; both satiated, but second not always bigger
|
||||||
|
(a-dominates-b-p
|
||||||
|
*test-blueprint*
|
||||||
|
(make-instance 'state :robots '(:ore 5 :clay 17 :obsidian 9 :geode 2))
|
||||||
|
(make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 8 :geode 2)))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; first not satiated, even though second is bigger - nil
|
||||||
|
(a-dominates-b-p
|
||||||
|
*test-blueprint*
|
||||||
|
(make-instance 'state :robots '(:ore 2 :clay 17 :obsidian 9 :geode 2))
|
||||||
|
(make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 8 :geode 2)))
|
||||||
|
|
||||||
|
;; and that's not right. if we have on same amount of steps
|
||||||
|
;; reference as satiated and checking as not - wouldn't keep up
|
||||||
|
;; so big check should be whether steps are even in imagination permit
|
||||||
|
;; ugh. that would mean putting minute\step into state.
|
||||||
|
|
||||||
|
;; um, let's not do it right now?
|
||||||
|
;; for both satiated is a very weak check, but let's try it like this?
|
||||||
|
|
||||||
|
(setq *test-state* (make-instance 'state))
|
||||||
|
(setf (cur-found-max *test-state*) (make-instance 'state))
|
||||||
|
|
||||||
|
;; so whelp
|
||||||
|
;; should have committed after doing the "build makes sence list"
|
||||||
|
;;
|
||||||
|
;; my problems are because "is dominated by" is not simmetrical to "dominates"
|
||||||
|
;; and i want both
|
||||||
|
;;
|
||||||
|
;; now in the loop set first satiated as domination
|
||||||
|
;; after that compare if our set dominates that one and swap
|
||||||
|
;; and compare if it's dominated by that one and prune
|
||||||
|
|
||||||
|
;; so, only if ref earlier than checked state.
|
||||||
|
;; and then - if checked not saitated, or by all resources less than
|
||||||
|
;; but i do want tests
|
||||||
|
|
||||||
|
;; both satiated, but second bigger
|
||||||
|
(a-dominates-b-p
|
||||||
|
*test-blueprint*
|
||||||
|
(make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 7 :geode 2) :minute 2)
|
||||||
|
(make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 7 :geode 2) :minute 3))
|
||||||
|
;; should be NIL
|
||||||
|
;; now want to check for different amount of steps.
|
||||||
|
;; so if same resources but first is earlier - it dominates
|
||||||
|
(minute (make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 7 :geode 2) :minute 2))
|
||||||
|
;; i was putting :minute 2 into :robots plist, cool, no thanks to you types
|
||||||
|
(minute (make-instance 'state :robots '(:ore 6 :clay 18 :obsidian 7 :geode 2) :minute 2))
|
||||||
|
|
||||||
|
;; ok. this also seems well.
|
||||||
|
;; then main loop? on fisrt satiated set as `cur-found-max`
|
||||||
|
;; and after that always check -
|
||||||
|
|
||||||
|
(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))
|
||||||
|
|
||||||
|
(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
|
||||||
|
(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
|
||||||
|
(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 ))))
|
||||||
|
;; (break)
|
||||||
|
;; (format t "would build ~a~%" possible-bot-builds)
|
||||||
|
(max (or max-if-building 0) if-not-building))))))
|
||||||
|
|
||||||
|
(setq *test-state* (make-instance 'state))
|
||||||
|
(setf (cur-found-max *test-state*) nil)
|
||||||
|
(print (find-max-geod-2 *test-blueprint* *test-state*))
|
||||||
|
|
||||||
|
;; so, why doesn't it ever builds obsidian?
|
||||||
|
*test-blueprint*
|
||||||
|
;; because is "has to build something if it can" whops
|
||||||
|
52
day19.lisp
52
day19.lisp
@ -7,7 +7,10 @@
|
|||||||
|
|
||||||
(defclass state ()
|
(defclass state ()
|
||||||
((resources :accessor resources :initform nil :initarg :resources)
|
((resources :accessor resources :initform nil :initarg :resources)
|
||||||
(robots :accessor robots :initform (list :ore 1) :initarg :robots)))
|
(robots :accessor robots :initform (list :ore 1) :initarg :robots)
|
||||||
|
(minute :accessor minute :initarg :minute :initform 1 )
|
||||||
|
(cur-found-max :initform nil :accessor cur-found-max :allocation :class) ; would be nice to add types
|
||||||
|
))
|
||||||
|
|
||||||
(defmethod print-object ((obj state) stream)
|
(defmethod print-object ((obj state) stream)
|
||||||
(print-unreadable-object (obj stream :type t)
|
(print-unreadable-object (obj stream :type t)
|
||||||
@ -18,8 +21,7 @@
|
|||||||
|
|
||||||
;; example of blueprint:
|
;; example of blueprint:
|
||||||
(defparameter *test-blueprint*
|
(defparameter *test-blueprint*
|
||||||
'(:id 1
|
'(:ore (:ore 4)
|
||||||
:ore (:ore 4)
|
|
||||||
:clay (:ore 2)
|
:clay (:ore 2)
|
||||||
:obsidian (:ore 3 :clay 14)
|
:obsidian (:ore 3 :clay 14)
|
||||||
:geode (:ore 2 :obsidian 7)))
|
:geode (:ore 2 :obsidian 7)))
|
||||||
@ -30,7 +32,8 @@
|
|||||||
|
|
||||||
(defmethod copy-state ((s state))
|
(defmethod copy-state ((s state))
|
||||||
(make-instance 'state :resources (copy-list (resources s))
|
(make-instance 'state :resources (copy-list (resources s))
|
||||||
:robots (copy-list (robots s))))
|
:robots (copy-list (robots s))
|
||||||
|
:minute (minute s)))
|
||||||
|
|
||||||
(defmethod can-create-robot (blueprints type (s state))
|
(defmethod can-create-robot (blueprints type (s state))
|
||||||
(let ((this-robot-costs (getf blueprints type)))
|
(let ((this-robot-costs (getf blueprints type)))
|
||||||
@ -53,6 +56,43 @@
|
|||||||
(loop for (resource amount) on new-resources by #'cddr
|
(loop for (resource amount) on new-resources by #'cddr
|
||||||
do (incf (getf (resources s) resource 0) amount)))
|
do (incf (getf (resources s) resource 0) amount)))
|
||||||
|
|
||||||
|
;; robot is unnecessary if resouce it brings is alreay produced
|
||||||
|
;; at amount of maximal possible per-turn expence
|
||||||
|
(defmethod max-need (blueprints (s state) resource-type)
|
||||||
|
(loop
|
||||||
|
for (la blueprint) on blueprints by #'cddr
|
||||||
|
;; do (print blueprint)
|
||||||
|
maximize (getf blueprint resource-type 0)))
|
||||||
|
|
||||||
|
(defmethod any-use-of-creating-robot (blueprints (s state) robot-type)
|
||||||
|
(if (eq :geode robot-type)
|
||||||
|
t ; always reason to build more geode robots
|
||||||
|
(let ((max-need (max-need blueprints s robot-type))
|
||||||
|
(state-production (getf (robots s) robot-type 0)))
|
||||||
|
;; (format t "comparing need ~a with prod ~a" max-need state-production)
|
||||||
|
(> max-need state-production))))
|
||||||
|
|
||||||
(defmethod get-possible-bot-builds (blueprints (s state))
|
(defmethod get-possible-bot-builds (blueprints (s state))
|
||||||
(remove-if-not (lambda (robot-type) (can-create-robot blueprints robot-type s))
|
(remove-if-not (lambda (robot-type)
|
||||||
*all-types*))
|
(any-use-of-creating-robot blueprints s robot-type))
|
||||||
|
(remove-if-not (lambda (robot-type)
|
||||||
|
(can-create-robot blueprints robot-type s))
|
||||||
|
*all-types*)))
|
||||||
|
|
||||||
|
;; true when no longer need to build secondary robots
|
||||||
|
(defmethod is-satiated-p (blueprints (s state))
|
||||||
|
(loop for type in '(:ore :clay :obsidian)
|
||||||
|
never (any-use-of-creating-robot blueprints s type)))
|
||||||
|
|
||||||
|
(defmethod a-dominates-b-p (blueprints (a state) (b state))
|
||||||
|
;; (declare (optimize (debug 3)))
|
||||||
|
(when (is-satiated-p blueprints a) ; when not a satiated - don't know
|
||||||
|
(and
|
||||||
|
(<= (minute a) (minute b)) ; a earlier than b
|
||||||
|
(or
|
||||||
|
(not (is-satiated-p blueprints b))
|
||||||
|
(loop for resource-type in *all-types* ; for both satiated compare all resources
|
||||||
|
always (and (>= (getf (resources a) resource-type 0)
|
||||||
|
(getf (resources b) resource-type 0))
|
||||||
|
(>= (getf (robots a) resource-type 0)
|
||||||
|
(getf (robots b) resource-type 0))))))))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user