;; https://adventofcode.com/2022/day/19 (defpackage :day-19 (:use :cl)) (in-package :day-19) (defparameter *all-types* '(:geode :obsidian :clay :ore)) (defclass state () ((resources :accessor resources :initform nil :initarg :resources) (robots :accessor robots :initform (list :ore 1) :initarg :robots))) (defmethod print-object ((obj state) stream) (print-unreadable-object (obj stream :type t) (with-slots (resources robots) obj (format stream "collected: ~a, with robots: ~a" resources robots)))) ;; example of blueprint: (defparameter *test-blueprint* '(:id 1 :ore (:ore 4) :clay (:ore 2) :obsidian (:ore 3 :clay 14) :geode (:ore 2 :obsidian 7))) ;; thank you blambert & stackoverflow ;; https://stackoverflow.com/questions/11067899/is-there-a-generic-method-for-cloning-clos-objects ;; oh, but this is shallow copy and lists reused. crap (defmethod copy-state ((s state)) (make-instance 'state :resources (copy-list (resources s)) :robots (copy-list (robots s)))) (defmethod can-create-robot (blueprints type (s state)) (let ((this-robot-costs (getf blueprints type))) (loop for (resource amount) on this-robot-costs by #'cddr always (>= (getf (resources s) resource 0) amount)))) (defmethod create-robot (blueprints type (s state)) (when (can-create-robot blueprints type s) (let ((this-robot-costs (getf blueprints type)) (copied-state (copy-state s))) (loop for (resource amount) on this-robot-costs by #'cddr do (incf (getf (resources copied-state) resource 0) (- amount))) (incf (getf (robots copied-state) type 0)) copied-state))) (defmethod calc-resources-to-be-collected ((s state)) (robots s)) (defmethod add-resources (new-resources (s state)) (loop for (resource amount) on new-resources by #'cddr do (incf (getf (resources s) resource 0) amount))) (defmethod get-possible-bot-builds (blueprints (s state)) (remove-if-not (lambda (robot-type) (can-create-robot blueprints robot-type s)) *all-types*))