(ql:quickload '(fiveam uiop cl-ppcre)) (defun material (string) (cond ((string= string "ore") :ore) ((string= string "clay") :clay) ((string= string "obsidian") :obsidian) ((string= string "geode") :geode))) (defun parse-robot-recipe (line) (cl-ppcre:register-groups-bind ((#'material robot) (#'parse-integer fq) (#'material fm) (#'parse-integer sq) (#'material sm)) ("(\\w+) robot costs (\\d+) (\\w+)(?: and (\\d+) (\\w+))?" line) (let ((first-material (fset:with (fset:empty-bag) fm fq))) (fset:map (robot (if sm (fset:with first-material sm sq) first-material)))))) (defun can-build-robot-p (requirements available) (fset:subbag? requirements available)) (defun consume (requirements available) (fset:bag-difference available requirements)) (defun material-collect (bots available-materials) (fset:bag-sum bots available-materials)) (defun bot-requirements (type recipes) (fset:lookup recipes type)) (defun next-step (build-next robots resources blueprints time-left) (if (zerop time-left) ;; (list robots resources) (fset:multiplicity resources :geode) ;; resources (let ((req (bot-requirements build-next blueprints))) (if (can-build-robot-p req resources) (let ((new-robots (fset:with robots build-next)) (resources-left (consume req resources))) (probe new-robots (material-collect robots resources-left) blueprints (1- time-left))) (next-step build-next robots (material-collect robots resources) blueprints (1- time-left)))))) (defun probe (robots resources blueprints time-left) (reduce (lambda (max next) (max max (next-step next robots resources blueprints time-left))) '(:geode :obsidian :clay :ore) :initial-value 0)) (defun start-resources () ;; (list :ore 0 :clay 0 :obsidian 0 :geode 0) (fset:empty-bag)) (defun start-bots () ;; (list :ore 1 :clay 0 :obsidian 0 :geode 0) (fset:bag :ore)) (let ((blueprints (cdar (mapcar (lambda (l) (let ((blueprint (uiop:split-string l :separator ":."))) (cons (car blueprint) (reduce #'fset:map-union (mapcar #'parse-robot-recipe (butlast (cdr blueprint))))))) (uiop:read-file-lines "eg-in")))) ;; (materials '(:ore 8 :clay 20)) (materials (start-resources)) (bots (start-bots)) ;; (bots '(:geode 1 :ore 8 :clay 20)) (time-left 24)) (probe bots materials blueprints time-left) )