summaryrefslogtreecommitdiff
path: root/19/1.lua
blob: 209efc1f3af92612382eb1793996c6b8f4444db2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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