require "ext" local blueprints = {} for line in io.lines() do local bpn = line:match("Blueprint (%d+):") bpn = tonumber(bpn) blueprints[bpn] = {} for robot, cost in line:gmatch("Each (%w+) robot costs (%d+) ore.") do --ore and clay blueprints[bpn][robot] = {ore = tonumber(cost)} end for robot, c1, r1, c2, r2 in line:gmatch("Each (%w+) robot costs (%d+) (%w+) and (%w+) (%w+).") do --obsidian and geode blueprints[bpn][robot] = {[r1] = tonumber(c1),[r2]=tonumber(c2)} end end print("Blueprints:") print(blueprints) local time = 24 local function perm_yields(n) local memgen = {} -- memoize generation -- permutate all the ways to yield n geodes local function permgen(left,tbl) --print("Perm",left) if left < 0 then return end if left == 0 then local ty = table.concat(tbl) if memgen[ty] == nil then coroutine.yield(tbl) memgen[ty] = true end end for i = time - 1,time-left - 1,-1 do local minesfor = time - i if tbl[i] == nil and (minesfor <= left) then tbl[i] = "geode" permgen(left - minesfor,tbl) tbl[i] = nil end end end return coroutine.wrap(function() permgen(n,{}) end) end local dependencies = {"clay","obsidian"} local function rperm(a,n,perm) local function rperm_helper(a,n,rst,restrict) if n == 0 then coroutine.yield(rst) else for _,v in pairs(a) do local lc = #rst rst[lc + 1] = v rperm_helper(a,n-1,rst) rst[lc + 1] = nil end end end return coroutine.wrap(function() rperm_helper(a,n,{}) end) end local state = { minute = 0, resources = {ore = 0, clay = 0, obsidian = 0, geode = 0}, robots = {ore = 1, clay = 0, obsidian = 0, geode = 0} } local function copy_state(tbl) local newtbl = {} for k,v in pairs(tbl) do newtbl[k] = v end for _,n in pairs({"resources","robots"}) do newtbl[n] = {} for k,v in pairs(tbl[n]) do newtbl[n][k] = v end end return newtbl end local function can_build(state,blueprint,name) ---print("state",state,"blueprint",blueprint,"name",name) for res, amt in pairs(blueprint[name]) do if state.resources[res] < amt then return false end end return true end local function simulate(blueprint, state, build_order, geode_times) while state.minute <= time do if geode_times[state.minute] then if not can_build(state,blueprint,"geode") then print("Failed to build geode at",state.minute) return false end elseif #build_order > 0 and can_build(state,blueprint,build_order[1]) then local rname = build_order[1] for res,amt in pairs(blueprint[rname]) do state.resources[res] = state.resources[res] - amt end state.robots[rname] = state.robots[rname] + 1 table.remove(build_order,1) end for res,count in pairs(state.robots) do state.resources[res] = state.resources[res] + count end state.minute = state.minute + 1 end return true end local function feasable(blueprint, geode_times) for i = 1,12 do print("Trying with",i,"other robots") for perm in rperm({"ore","clay","obsidian"},i) do local state = copy_state(state) if simulate(blueprint, state, perm, geode_times) then print("Successful simulation") return true end end end end for combo in perm_yields(56) do print("combo:",combo) end