Last active
January 8, 2023 00:27
-
-
Save MCJack123/5e64418d01f466d475db2f9678befcc1 to your computer and use it in GitHub Desktop.
Advent of Code 2022 solutions (Run in CraftOS-PC w/CCEmuX plugin)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Usage: aoc2022 <day>-<1|2> [local] | |
-- Run `set aoc.session <session token>` before running | |
local aoc = {} | |
local function run(n, l) | |
local f = aoc[n] | |
local file | |
if l then file = fs.open("aoc.txt", "r") | |
else file = http.get("https://adventofcode.com/2022/day/" .. n:match("^%d+") .. "/input", {Cookie = "session=" .. settings.get("aoc.session")}) end | |
local start = os.epoch "utc" | |
local r = tostring(f(file)) | |
file.close() | |
print("Time: " .. ((os.epoch "utc" - start) / 1000) .. "s") | |
print(r) | |
if ccemux then ccemux.setClipboard(r) end | |
end | |
function string.nmatch(str, pattern) | |
local m = table.pack(str:match(pattern)) | |
for i = 1, m.n do m[i] = tonumber(m[i]) or m[i] end | |
return table.unpack(m, 1, m.n) | |
end | |
function string.gnmatch(str, pattern) | |
local f, k, v = str:gmatch(pattern) | |
return function(...) | |
local m = table.pack(f(...)) | |
for i = 1, m.n do m[i] = tonumber(m[i]) or m[i] end | |
return table.unpack(m, 1, m.n) | |
end, k, v | |
end | |
local pairs, ipairs, tonumber = pairs, ipairs, tonumber | |
aoc["1-1"] = function(file) | |
local elves = {0} | |
local n = 1 | |
for line in file.readLine do | |
if line == "" then | |
n = n + 1 | |
elves[n] = 0 | |
else | |
elves[n] = elves[n] + tonumber(line) | |
end | |
end | |
local n, m = 0, 0 | |
local s = 0 | |
for i, v in ipairs(elves) do | |
if v > m then n, m = i, v end | |
s = s + v | |
end | |
return m | |
end | |
aoc["1-2"] = function(file) | |
local elves = {0} | |
local n = 1 | |
for line in file.readLine do | |
if line == "" then | |
n = n + 1 | |
elves[n] = 0 | |
else | |
elves[n] = elves[n] + tonumber(line) | |
end | |
end | |
table.sort(elves, function(a, b) return a > b end) | |
return elves[1] + elves[2] + elves[3] | |
end | |
aoc["2-1"] = function(file) | |
local score = 0 | |
local map = {A = 1, B = 2, C = 3, X = 1, Y = 2, Z = 3} | |
for line in file.readLine do | |
local a, b = line:match "(.) (.)" | |
if not a then break end | |
score = score + map[b] + (map[a] == map[b] and 3 or (((map[b] - 1) - (map[a] - 1)) % 3 == 1 and 6 or 0)) | |
end | |
return score | |
end | |
aoc["2-2"] = function(file) | |
local score = 0 | |
local map = {A = 0, B = 1, C = 2} | |
local add = {X = -1, Y = 0, Z = 1} | |
for line in file.readLine do | |
local a, b = line:match "(.) (.)" | |
if not a then break end | |
score = score + ((map[a] + add[b]) % 3 + 1) + (add[b] * 3 + 3) | |
end | |
return score | |
end | |
aoc["3-1"] = function(file) | |
local lut = {} | |
for i = 1, 26 do lut[string.char(i + 96)] = i end | |
for i = 1, 26 do lut[string.char(i + 64)] = i + 26 end | |
local sum = 0 | |
for line in file.readLine do | |
local a, b = line:sub(1, #line / 2), line:sub(#line / 2 + 1) | |
local ac, common = {}, {} | |
for c in a:gmatch "." do ac[c] = true end | |
for c in b:gmatch "." do if ac[c] then sum = sum + lut[c] break end end | |
end | |
return sum | |
end | |
aoc["3-2"] = function(file) | |
local lut = {} | |
for i = 1, 26 do lut[string.char(i + 96)] = i end | |
for i = 1, 26 do lut[string.char(i + 64)] = i + 26 end | |
local sum = 0 | |
local group = {} | |
local i = 1 | |
for line in file.readLine do | |
group[i] = line | |
if i == 3 then | |
local common = group[1]:gsub("[^" .. group[2] .. "]", ""):gsub("[^" .. group[3] .. "]", ""):sub(1, 1) | |
sum = sum + lut[common] | |
i = 1 | |
group = {} | |
else i = i + 1 end | |
end | |
return sum | |
end | |
aoc["4-1"] = function(file) | |
local count = 0 | |
for line in file.readLine do | |
local as, ae, bs, be = line:match "(%d+)%-(%d+),(%d+)%-(%d+)" | |
as, ae, bs, be = tonumber(as), tonumber(ae), tonumber(bs), tonumber(be) | |
if (as <= bs and ae >= be) or (as >= bs and ae <= be) then count = count + 1 end | |
end | |
return count | |
end | |
aoc["4-2"] = function(file) | |
local count = 0 | |
for line in file.readLine do | |
local as, ae, bs, be = line:match "(%d+)%-(%d+),(%d+)%-(%d+)" | |
as, ae, bs, be = tonumber(as), tonumber(ae), tonumber(bs), tonumber(be) | |
local a, b = {}, {} | |
for i = as, ae do a[i] = i end | |
for i = bs, be do if a[i] then count = count + 1 break end end | |
end | |
return count | |
end | |
-- NOTE: The original versions as used to solve had the stacks hardcoded. | |
-- They have been removed to avoid sharing my input, and replaced with a proper | |
-- parser for the stack info in the input. | |
aoc["5-1"] = function(file) | |
local stacks = {} | |
local stacklines = {} | |
local empty = false | |
for line in file.readLine do | |
if empty then | |
local a, b, c = line:match "move (%d+) from (%d+) to (%d+)" | |
a, b, c = tonumber(a), tonumber(b), tonumber(c) | |
for i = 1, a do table.insert(stacks[c], table.remove(stacks[b])) end | |
elseif line:match "%[%a%]" then stacklines[#stacklines+1] = line | |
elseif line == "" then | |
empty = true | |
for i = #stacklines, 1, -1 do | |
local j = 1 | |
for m in stacklines[i]:gmatch "[%[ ]([A-Z ])[%] ] ?" do | |
if not stacks[j] then stacks[j] = {} end | |
if m ~= " " then table.insert(stacks[j], m) end | |
j = j + 1 | |
end | |
end | |
for i = 1, #stacks do print(#stacks[i]) end | |
end | |
end | |
local s = "" | |
for i = 1, #stacks do s = s .. stacks[i][#stacks[i]] end | |
return s | |
end | |
aoc["5-2"] = function(file) | |
local stacks = {} | |
local stacklines = {} | |
local empty = false | |
for line in file.readLine do | |
if empty then | |
local a, b, c = line:match "move (%d+) from (%d+) to (%d+)" | |
a, b, c = tonumber(a), tonumber(b), tonumber(c) | |
local n = #stacks[b] - a + 1 | |
for i = 1, a do table.insert(stacks[c], table.remove(stacks[b], n)) end | |
elseif line:match "%[%a%]" then stacklines[#stacklines+1] = line | |
elseif line == "" then | |
empty = true | |
for i = #stacklines, 1, -1 do | |
local j = 1 | |
for m in stacklines[i]:gmatch "[%[ ]([A-Z ])[%] ] ?" do | |
if not stacks[j] then stacks[j] = {} end | |
if m ~= " " then table.insert(stacks[j], m) end | |
j = j + 1 | |
end | |
end | |
for i = 1, #stacks do print(#stacks[i]) end | |
end | |
end | |
local s = "" | |
for i = 1, #stacks do s = s .. stacks[i][#stacks[i]] end | |
return s | |
end | |
aoc["6-1"] = function(file) | |
local last = {" ", " ", " ", " "} | |
for n, c in file.readLine():gmatch "()(.)" do | |
table.remove(last, 1) | |
last[4] = c | |
if n > 4 and last[1] ~= last[2] and last[2] ~= last[3] and last[3] ~= last[4] and last[1] ~= last[3] and last[1] ~= last[4] and last[2] ~= last[4] then return n end | |
end | |
end | |
aoc["6-2"] = function(file) | |
local last = {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "} | |
for n, c in file.readLine():gmatch "()(.)" do | |
table.remove(last, 1) | |
last[14] = c | |
if n > 14 then | |
local ok = true | |
for y = 1, 14 do | |
for x = 1, 14 do | |
if y ~= x and last[y] == last[x] then ok = false break end | |
end | |
end | |
if ok then return n end | |
end | |
end | |
end | |
aoc["7-1"] = function(file) | |
local fs = {} | |
local node = fs | |
-- parse | |
for line in file.readLine do | |
if line:match "^%$ cd" then | |
local d = line:match "cd (.+)$" | |
if d == ".." then node = node.__parent | |
elseif d == "/" then node = fs | |
else | |
if not node[d] then node[d] = {__parent = node} end | |
node = node[d] | |
end | |
elseif line ~= "$ ls" then | |
local sz, f = line:match "^(%S+) (.+)$" | |
if sz == "dir" then node[f] = {__parent = node} | |
else node[f] = tonumber(sz) end | |
end | |
end | |
-- size | |
local sum = 0 | |
local function sizedir(d) | |
local sz = 0 | |
for k, v in pairs(d) do if not k:match "^__" then | |
if type(v) == "number" then sz = sz + v | |
else sz = sz + sizedir(v) end | |
end end | |
d.__size = sz | |
if sz <= 100000 then sum = sum + sz end | |
return sz | |
end | |
sizedir(fs) | |
return sum | |
end | |
aoc["7-2"] = function(file) | |
local fs = {} | |
local node = fs | |
-- parse | |
for line in file.readLine do | |
if line:match "^%$ cd" then | |
local d = line:match "cd (.+)$" | |
if d == ".." then node = node.__parent | |
elseif d == "/" then node = fs | |
else | |
if not node[d] then node[d] = {__parent = node} end | |
node = node[d] | |
end | |
elseif line ~= "$ ls" then | |
local sz, f = line:match "^(%S+) (.+)$" | |
if sz == "dir" then node[f] = {__parent = node} | |
else node[f] = tonumber(sz) end | |
end | |
end | |
-- size | |
local function sizedir(d) | |
local sz = 0 | |
for k, v in pairs(d) do if not k:match "^__" then | |
if type(v) == "number" then sz = sz + v | |
else sz = sz + sizedir(v) end | |
end end | |
d.__size = sz | |
return sz | |
end | |
local needed = 30000000 - (70000000 - sizedir(fs)) | |
print(needed) | |
-- find | |
local mn, n = fs.__size, fs | |
local function find(d) | |
for k, v in pairs(d) do if not k:match "^__" then | |
if type(v) == "table" then | |
if v.__size >= needed and v.__size < mn then mn, n = v.__size, v end | |
find(v) | |
end | |
end end | |
end | |
find(fs) | |
return n.__size | |
end | |
aoc["8-1"] = function(file) | |
local grid = {} | |
for line in file.readLine do | |
local r = {} | |
for n, c in line:gmatch "()(%d)" do r[n] = tonumber(c) end | |
grid[#grid+1] = r | |
end | |
local n = 0 | |
local v = {} | |
for y = 1, #grid do | |
v[y] = {} | |
local r = grid[y] | |
local m = -1 | |
local nn = 0 | |
for x = 1, #r do | |
if r[x] <= m then | |
else if not v[y][x] then nn = nn + 1 end v[y][x] = true m = r[x] end | |
end | |
n = n + nn | |
m = -1 | |
nn = 0 | |
for x = #r, 1, -1 do | |
if r[x] <= m then | |
else if not v[y][x] then nn = nn + 1 end v[y][x] = true m = r[x] end | |
end | |
n = n + nn | |
end | |
for x = 1, #grid[1] do | |
local m = -1 | |
local nn = 0 | |
for y = 1, #grid do | |
if grid[y][x] <= m then | |
else if not v[y][x] then nn = nn + 1 end v[y][x] = true m = grid[y][x] end | |
end | |
n = n + nn | |
m = -1 | |
nn = 0 | |
for y = #grid, 1, -1 do | |
if grid[y][x] <= m then | |
else if not v[y][x] then nn = nn + 1 end v[y][x] = true m = grid[y][x] end | |
end | |
n = n + nn | |
end | |
return n | |
end | |
aoc["8-2"] = function(file) | |
local grid = {} | |
for line in file.readLine do | |
local r = {} | |
for n, c in line:gmatch "()(%d)" do r[n] = tonumber(c) end | |
grid[#grid+1] = r | |
end | |
local n = 0 | |
for y = 1, #grid do | |
for x = 1, #grid[y] do | |
local v = {0, 0, 0, 0} | |
local c = grid[y][x] | |
for xx = x + 1, #grid[y] do | |
v[1] = v[1] + 1 | |
if grid[y][xx] >= c then break end | |
end | |
for xx = x - 1, 1, -1 do | |
v[2] = v[2] + 1 | |
if grid[y][xx] >= c then break end | |
end | |
for yy = y + 1, #grid do | |
v[3] = v[3] + 1 | |
if grid[yy][x] >= c then break end | |
end | |
for yy = y - 1, 1, -1 do | |
v[4] = v[4] + 1 | |
if grid[yy][x] >= c then break end | |
end | |
n = math.max(n, v[1] * v[2] * v[3] * v[4]) | |
end | |
end | |
return n | |
end | |
aoc["9-1"] = function(file) | |
local visit = {} | |
local h, t = vector.new(0, 0), vector.new(0, 0) | |
local dl = { | |
U = vector.new(0, 1), | |
D = vector.new(0, -1), | |
L = vector.new(-1, 0), | |
R = vector.new(1, 0) | |
} | |
for line in file.readLine do | |
local dir, num = line:match "([UDLR]) (%d+)" | |
local d = dl[dir] | |
for i = 1, tonumber(num) do | |
h = h + d | |
if (h - t):length() >= 1.42 then t = h - d end | |
visit[t.y] = visit[t.y] or {} | |
visit[t.y][t.x] = true | |
end | |
end | |
local s = 0 | |
for _, r in pairs(visit) do for _ in pairs(r) do s = s + 1 end end | |
return s | |
end | |
aoc["9-2"] = function(file) | |
local visit = {} | |
local n = {} | |
for i = 1, 10 do n[i] = vector.new(0, 0) end | |
local dl = { | |
U = vector.new(0, 1), | |
D = vector.new(0, -1), | |
L = vector.new(-1, 0), | |
R = vector.new(1, 0) | |
} | |
for line in file.readLine do | |
local dir, num = line:match "([UDLR]) (%d+)" | |
local d = dl[dir] | |
for i = 1, tonumber(num) do | |
n[1] = n[1] + d | |
for j = 2, 10 do | |
if (n[j-1] - n[j]):length() >= 1.42 then | |
n[j] = n[j] + vector.new(math.max(math.min(n[j-1].x - n[j].x, 1), -1), math.max(math.min(n[j-1].y - n[j].y, 1), -1)) | |
end | |
end | |
visit[n[10].y] = visit[n[10].y] or {} | |
visit[n[10].y][n[10].x] = true | |
end | |
end | |
local s = 0 | |
for _, r in pairs(visit) do for _ in pairs(r) do s = s + 1 end end | |
return s | |
end | |
aoc["10-1"] = function(file) | |
local x = 1 | |
local i = 1 | |
local s = 0 | |
for line in file.readLine do | |
local cmd, arg = line:match "(%S+) ?(%-?%d*)" | |
if cmd == "addx" then | |
i = i + 1 | |
if (i - 20) % 40 == 0 and i < 250 then print(i, x, arg) s = s + i * x end | |
x = x + tonumber(arg) | |
end | |
i = i + 1 | |
if (i - 20) % 40 == 0 and i < 250 then print(i, x, "t") s = s + i * x end | |
end | |
return s | |
end | |
aoc["10-2"] = function(file) | |
local x = 1 | |
local i = 1 | |
term.write(math.abs(i % 40 - x % 40 - 1) < 2 and "#" or ".") | |
for line in file.readLine do | |
local cmd, arg = line:match "(%S+) ?(%-?%d*)" | |
if cmd == "addx" then | |
i = i + 1 | |
term.write(math.abs(i % 40 - x % 40 - 1) < 2 and "#" or ".") | |
if i % 40 == 0 then print() end | |
x = x + tonumber(arg) | |
end | |
i = i + 1 | |
term.write(math.abs(i % 40 - x % 40 - 1) < 2 and "#" or ".") | |
if i % 40 == 0 then print() end | |
end | |
return 0 | |
end | |
aoc["11-1"] = function(file) | |
local monkeys = {} | |
while true do | |
local s = file.readLine() | |
if not s then break end | |
local i = s:nmatch "%d+" | |
local m = {env = {}, items = {}, act = {}, num = 0} | |
monkeys[i] = m | |
for n in file.readLine():gnmatch "%d+" do m.items[#m.items+1] = n end | |
m.fn = load(file.readLine():match ": (.+)$", "=monkey", "t", m.env) | |
m.mod = file.readLine():nmatch "%d+" | |
m.act[true] = file.readLine():nmatch "%d+" | |
m.act[false] = file.readLine():nmatch "%d+" | |
if not file.readLine() then break end | |
end | |
for r = 1, 20 do | |
for i = 0, #monkeys do | |
local m = monkeys[i] | |
while #m.items > 0 do | |
m.env.old = table.remove(m.items, 1) | |
m.fn() | |
m.env.new = math.floor(m.env.new / 3) | |
table.insert(monkeys[m.act[m.env.new % m.mod == 0]].items, m.env.new) | |
m.num = m.num + 1 | |
end | |
end | |
if r == 1 then for i = 0, #monkeys do print(i .. ": " .. table.concat(monkeys[i].items, ", ")) end end | |
end | |
local n = {} | |
for i = 0, #monkeys do n[i+1] = monkeys[i].num print(i, monkeys[i].num) end | |
table.sort(n, function(a, b) return a > b end) | |
return n[1] * n[2] | |
end | |
aoc["11-2"] = function(file) | |
local monkeys = {} | |
while true do | |
local s = file.readLine() | |
if not s then break end | |
local i = s:nmatch "%d+" | |
local m = {env = {}, items = {}, act = {}, num = 0} | |
monkeys[i] = m | |
for n in file.readLine():gnmatch "%d+" do m.items[#m.items+1] = n end | |
m.fn = load(file.readLine():match ": (.+)$", "=monkey", "t", m.env) | |
m.mod = file.readLine():nmatch "%d+" | |
m.act[true] = file.readLine():nmatch "%d+" | |
m.act[false] = file.readLine():nmatch "%d+" | |
if not file.readLine() then break end | |
end | |
for i = 0, #monkeys do | |
for j = 1, #monkeys[i].items do | |
local v = monkeys[i].items[j] | |
local t = {} | |
for k = 0, #monkeys do t[k] = v % monkeys[k].mod end | |
monkeys[i].items[j] = t | |
end | |
end | |
for r = 1, 10000 do | |
for i = 0, #monkeys do | |
local m = monkeys[i] | |
while #m.items > 0 do | |
local t = table.remove(m.items, 1) | |
for j = 0, #t do | |
m.env.old = t[j] | |
m.fn() | |
t[j] = m.env.new % monkeys[j].mod | |
end | |
table.insert(monkeys[m.act[t[i] % m.mod == 0]].items, t) | |
m.num = m.num + 1 | |
end | |
end | |
end | |
local n = {} | |
for i = 0, #monkeys do n[i+1] = monkeys[i].num print(i, monkeys[i].num) end | |
table.sort(n, function(a, b) return a > b end) | |
return n[1] * n[2] | |
end | |
aoc["12-1"] = function(file) | |
local grid = {} | |
local start, goal | |
local y = 1 | |
for line in file.readLine do | |
local l = {} | |
for x, c in line:gmatch "()(.)" do | |
if c == "S" then start = vector.new(x, y, 1) l[x] = 1 | |
elseif c == "E" then goal = vector.new(x, y, 26) l[x] = 26 | |
else l[x] = c:byte() - 96 end | |
end | |
grid[y] = l | |
y = y + 1 | |
end | |
local function find(pos, n, vis) | |
if pos == goal then return n end | |
if n > 1000 then return {} end | |
local dir = {} | |
if pos.x > 1 and not vis[pos.y*100+pos.x-1] and grid[pos.y][pos.x-1] - pos.z <= 1 and grid[pos.y][pos.x-1] - pos.z > -3 then dir[#dir+1] = vector.new(pos.x - 1, pos.y, grid[pos.y][pos.x-1]) end | |
if pos.x < #grid[pos.y] and not vis[pos.y*100+pos.x+1] and grid[pos.y][pos.x+1] - pos.z <= 1 and grid[pos.y][pos.x+1] - pos.z > -3 then dir[#dir+1] = vector.new(pos.x + 1, pos.y, grid[pos.y][pos.x+1]) end | |
if pos.y > 1 and not vis[(pos.y-1)*100+pos.x] and grid[pos.y-1][pos.x] - pos.z <= 1 and grid[pos.y-1][pos.x] - pos.z > -3 then dir[#dir+1] = vector.new(pos.x, pos.y - 1, grid[pos.y-1][pos.x]) end | |
if pos.y < #grid and not vis[(pos.y+1)*100+pos.x] and grid[pos.y+1][pos.x] - pos.z <= 1 and grid[pos.y+1][pos.x] - pos.z > -3 then dir[#dir+1] = vector.new(pos.x, pos.y + 1, grid[pos.y+1][pos.x]) end | |
return dir | |
end | |
local visit = {} | |
visit[start.y*100+start.x] = true | |
local c = 1 | |
local opt = {} | |
local next = find(start, 0, visit) | |
while #next > 0 do | |
local n = {} | |
for i = 1, #next do | |
local d = find(next[i], c, visit) | |
if type(d) == "number" then opt[#opt+1] = d | |
else for _, v in ipairs(d) do | |
visit[v.y*100+v.x] = true | |
n[#n+1] = v | |
end end | |
end | |
next = n | |
c = c + 1 | |
end | |
table.sort(opt) | |
return opt[1] | |
end | |
aoc["12-2"] = function(file) | |
local grid = {} | |
local goal | |
local y = 1 | |
for line in file.readLine do | |
local l = {} | |
for x, c in line:gmatch "()(.)" do | |
if c == "S" then l[x] = 1 | |
elseif c == "E" then goal = vector.new(x, y, 26) l[x] = 26 | |
else l[x] = c:byte() - 96 end | |
end | |
grid[y] = l | |
y = y + 1 | |
end | |
local function find(pos, n, vis) | |
if pos == goal then return n end | |
if n > 1000 then return {} end | |
local dir = {} | |
if pos.x > 1 and not vis[pos.y*100+pos.x-1] and grid[pos.y][pos.x-1] - pos.z <= 1 and grid[pos.y][pos.x-1] - pos.z > -3 then dir[#dir+1] = vector.new(pos.x - 1, pos.y, grid[pos.y][pos.x-1]) end | |
if pos.x < #grid[pos.y] and not vis[pos.y*100+pos.x+1] and grid[pos.y][pos.x+1] - pos.z <= 1 and grid[pos.y][pos.x+1] - pos.z > -3 then dir[#dir+1] = vector.new(pos.x + 1, pos.y, grid[pos.y][pos.x+1]) end | |
if pos.y > 1 and not vis[(pos.y-1)*100+pos.x] and grid[pos.y-1][pos.x] - pos.z <= 1 and grid[pos.y-1][pos.x] - pos.z > -3 then dir[#dir+1] = vector.new(pos.x, pos.y - 1, grid[pos.y-1][pos.x]) end | |
if pos.y < #grid and not vis[(pos.y+1)*100+pos.x] and grid[pos.y+1][pos.x] - pos.z <= 1 and grid[pos.y+1][pos.x] - pos.z > -3 then dir[#dir+1] = vector.new(pos.x, pos.y + 1, grid[pos.y+1][pos.x]) end | |
return dir | |
end | |
local function findall(start) | |
local visit = {} | |
visit[start.y*100+start.x] = true | |
local c = 1 | |
local opt = {} | |
local next = find(start, 0, visit) | |
while #next > 0 do | |
local n = {} | |
for i = 1, #next do | |
local d = find(next[i], c, visit) | |
if type(d) == "number" then opt[#opt+1] = d | |
else for _, v in ipairs(d) do | |
visit[v.y*100+v.x] = true | |
n[#n+1] = v | |
end end | |
end | |
next = n | |
c = c + 1 | |
end | |
table.sort(opt) | |
return opt[1] | |
end | |
local opt = {} | |
for i = 1, #grid do for x, v in ipairs(grid[i]) do if v == 1 then opt[#opt+1] = findall(vector.new(x, i, 1)) end end end | |
table.sort(opt) | |
return opt[1] | |
end | |
aoc["13-1"] = function(file) | |
local function cmp(a, b) | |
local ta, tb = type(a), type(b) | |
if ta == tb then | |
if ta == "number" then return a < b, a == b | |
else | |
for i = 1, #a do | |
if not b[i] then return false, false end | |
local r, s = cmp(a[i], b[i]) | |
if not s then return r, s end | |
end | |
return true, #a == #b | |
end | |
elseif ta == "number" then return cmp({a}, b) | |
else return cmp(a, {b}) end | |
end | |
local i = 1 | |
local s = 0 | |
repeat | |
local a, b = load("return " .. file.readLine():gsub("%[", "{"):gsub("%]", "}"))(), load("return " .. file.readLine():gsub("%[", "{"):gsub("%]", "}"))() | |
if cmp(a, b) then s = s + i end | |
print(i, cmp(a, b)) | |
i=i+1 | |
until file.readLine() == nil | |
return s | |
end | |
aoc["13-2"] = function(file) | |
local function cmp(a, b) | |
local ta, tb = type(a), type(b) | |
if ta == tb then | |
if ta == "number" then return a < b, a == b | |
else | |
for i = 1, #a do | |
if not b[i] then return false, false end | |
local r, s = cmp(a[i], b[i]) | |
if not s then return r, s end | |
end | |
return true, #a == #b | |
end | |
elseif ta == "number" then return cmp({a}, b) | |
else return cmp(a, {b}) end | |
end | |
local l = {{{2}}, {{6}}} | |
for line in file.readLine do if line ~= "" then | |
l[#l+1] = load("return " .. line:gsub("%[", "{"):gsub("%]", "}"))() | |
end end | |
table.sort(l, cmp) | |
local ia, ib | |
for i, a in ipairs(l) do | |
if #a == 1 and type(a[1]) == "table" and #a[1] == 1 and type(a[1][1]) == "number" then | |
if a[1][1] == 2 then ia = i | |
elseif a[1][1] == 6 then ib = i end | |
end | |
end | |
return ia * ib | |
end | |
aoc["14-1"] = function(file) | |
local grid = {} | |
local maxy = 0 | |
for line in file.readLine do | |
local lx, ly | |
for x,y in line:gnmatch "(%d+),(%d+)" do | |
maxy = math.max(y, maxy) | |
if lx then | |
if x == lx then | |
for i = math.min(y, ly), math.max(y, ly) do | |
grid[i] = grid[i] or {} | |
grid[i][x] = 1 | |
end | |
else | |
grid[y] = grid[y] or {} | |
for i = math.min(x, lx), math.max(x, lx) do grid[y][i] = 1 end | |
end | |
end | |
lx, ly = x, y | |
end | |
end | |
local n = 0 | |
repeat | |
local x = 500 | |
local fell = true | |
for y = 0, maxy do | |
if grid[y+1] and grid[y+1][x] then | |
if not grid[y+1][x-1] then x = x - 1 | |
elseif not grid[y+1][x+1] then x = x + 1 | |
else grid[y] = grid[y] or {} grid[y][x] = 0 fell, n = false, n + 1 break end | |
end | |
end | |
until fell | |
return n | |
end | |
aoc["14-2"] = function(file) | |
local grid = {} | |
local maxy = 0 | |
for line in file.readLine do | |
local lx, ly | |
for x,y in line:gnmatch "(%d+),(%d+)" do | |
maxy = math.max(y, maxy) | |
if lx then | |
if x == lx then | |
for i = math.min(y, ly), math.max(y, ly) do | |
grid[i] = grid[i] or {} | |
grid[i][x] = 1 | |
end | |
else | |
grid[y] = grid[y] or {} | |
for i = math.min(x, lx), math.max(x, lx) do grid[y][i] = 1 end | |
end | |
end | |
lx, ly = x, y | |
end | |
end | |
grid[maxy+2] = setmetatable({}, {__index = function() return 1 end}) | |
local n = 0 | |
repeat | |
local x = 500 | |
for y = 0, maxy + 10 do | |
if grid[y+1] and grid[y+1][x] then | |
if not grid[y+1][x-1] then x = x - 1 | |
elseif not grid[y+1][x+1] then x = x + 1 | |
else grid[y] = grid[y] or {} grid[y][x] = 0 n = n + 1 break end | |
end | |
end | |
until grid[0] and grid[0][500] | |
return n | |
end | |
aoc["15-1"] = function(file) | |
local no = {} | |
local ty = 2000000 | |
for line in file.readLine do | |
local sx, sy, bx, by = line:nmatch "^Sensor at x=(%-?%d+), y=(%-?%d+): closest beacon is at x=(%-?%d+), y=(%-?%d+)$" | |
local dist = math.abs(sx - bx) + math.abs(sy - by) | |
local txs = sx - dist + math.abs(sy - ty) | |
if txs <= sx then for x = txs, 2*sx - txs - 1 do no[x] = true end end | |
end | |
local n = 0 | |
for _ in pairs(no) do n = n + 1 end | |
return n | |
end | |
aoc["15-2"] = function(file) | |
local zones = {} | |
local size = 4000000 | |
for line in file.readLine do | |
local sx, sy, bx, by = line:nmatch "^Sensor at x=(%-?%d+), y=(%-?%d+): closest beacon is at x=(%-?%d+), y=(%-?%d+)$" | |
local dist = math.abs(sx - bx) + math.abs(sy - by) | |
zones[#zones+1] = {x = sx, y = sy, dist = dist} | |
end | |
for y = 0, size do | |
local x = 0 | |
while x <= size do | |
local ok = true | |
for _, v in ipairs(zones) do | |
if math.abs(v.x - x) + math.abs(v.y - y) <= v.dist then | |
ok = false | |
x = x + 2*(v.dist - math.abs(v.y - y)) - (v.dist - (math.abs(v.x - x) + math.abs(v.y - y))) + 1 | |
break | |
end | |
end | |
if ok then return x * 4000000 + y end | |
end | |
end | |
error("failure") | |
end | |
aoc["16-1"] = function(file) | |
local valves = {} | |
local total = 0 | |
for line in file.readLine do | |
local name, rate, out = line:nmatch "Valve (%a+) has flow rate=(%d+); tunnels? leads? to valves? (.+)$" | |
local v = {name = name, rate = rate, out = {}, open = false} | |
if rate > 0 then total = total + 1 end | |
for n in out:gmatch "%a+" do v.out[#v.out+1] = n end | |
valves[name] = v | |
end | |
for _, v in pairs(valves) do for i = 1, #v.out do v.out[i] = valves[v.out[i]] end end | |
local function search(left, flow, node, i, sum) | |
if i >= 30 then return sum end | |
local add = 0 | |
for _, v in ipairs(flow) do add = add + v.rate end | |
if #left == 0 then return sum + (30 - i) * add end | |
local max = sum | |
for _, v in ipairs(left) do | |
local ll = {} | |
for _, w in ipairs(left) do if w ~= v then ll[#ll+1] = w end end | |
local ff = {v} | |
for j, w in ipairs(flow) do ff[j+1] = w end | |
local q, x = {node}, {} | |
while #q > 0 do | |
local n = table.remove(q, 1) | |
if n == v then break end | |
for _, w in ipairs(n.out) do | |
if not x[w] then | |
x[w] = true | |
w.parent = n | |
q[#q+1] = w | |
end | |
end | |
end | |
local ss = sum + add | |
local ii = i + 1 | |
local vp = v | |
while vp ~= node and ii < 30 do ss = ss + add ii = ii + 1 vp = vp.parent end | |
max = math.max(max, search(ll, ff, v, ii, ss)) | |
end | |
return max | |
end | |
local left = {} | |
for _, v in pairs(valves) do if v.rate > 0 then left[#left+1] = v end end | |
return search(left, {}, valves.AA, 0, 0) | |
end | |
aoc["16-2"] = function(file) | |
local start = os.epoch "utc" | |
local valves = {} | |
local total = 0 | |
for line in file.readLine do | |
local name, rate, out = line:nmatch "Valve (%a+) has flow rate=(%d+); tunnels? leads? to valves? (.+)$" | |
local v = {name = name, rate = rate, out = {}, open = false} | |
if rate > 0 then total = total + 1 end | |
for n in out:gmatch "%a+" do v.out[#v.out+1] = n end | |
valves[name] = v | |
end | |
for _, v in pairs(valves) do for i = 1, #v.out do v.out[i] = valves[v.out[i]] end end | |
local pmax = 0 | |
local function search(left, flow, ynode, yi, enode, ei) | |
if (yi >= 26 and ei >= 26) or #left == 0 then | |
local sum = 0 | |
for _, f in ipairs(flow) do sum = sum + f[1].rate * (26 - f[2]) end | |
if sum > pmax then print(sum) sleep(0) pmax = sum end | |
return sum | |
end | |
local max = 0 | |
for y, v in ipairs(left) do | |
local ll = {} | |
local possible = 0 | |
for _, w in ipairs(left) do | |
if w ~= v then ll[#ll+1] = w end | |
if y == 1 then possible = possible + w.rate * (26 - math.min(ei, yi)) end | |
end | |
local ff = {{v}} | |
for j, w in ipairs(flow) do | |
ff[j+1] = w | |
if y == 1 then possible = possible + w[1].rate * (26 - w[2]) end | |
end | |
if y == 1 and possible < pmax then return possible end | |
do | |
local q, x = {ynode}, {} | |
while #q > 0 do | |
local n = table.remove(q, 1) | |
if n == v then break end | |
for _, w in ipairs(n.out) do | |
if not x[w] then | |
x[w] = true | |
w.parent = n | |
q[#q+1] = w | |
end | |
end | |
end | |
end | |
local ii = yi + 1 | |
local vp = v | |
while vp ~= ynode and ii < 26 do | |
ii = ii + 1 | |
vp = vp.parent | |
end | |
ff[1][2] = ii | |
for e, ev in ipairs(ll) do | |
local ell = {} | |
possible = 0 | |
for _, w in ipairs(ll) do | |
if w ~= ev then ell[#ell+1] = w end | |
if e == 1 then possible = possible + w.rate * (26 - math.min(ei, yi)) end | |
end | |
local eff = {{ev}} | |
for j, w in ipairs(ff) do | |
eff[j+1] = w | |
if e == 1 then possible = possible + w[1].rate * (26 - w[2]) end | |
end | |
if e == 1 and possible < pmax then break end | |
do | |
local eq, ex = {enode}, {} | |
while #eq > 0 do | |
local n = table.remove(eq, 1) | |
if n == ev then break end | |
for _, w in ipairs(n.out) do | |
if not ex[w] then | |
ex[w] = true | |
w.parent = n | |
eq[#eq+1] = w | |
end | |
end | |
end | |
end | |
local eii = ei + 1 | |
local evp = ev | |
while evp ~= enode and eii < 26 do | |
eii = eii + 1 | |
evp = evp.parent | |
end | |
eff[1][2] = eii | |
max = math.max(max, search(ell, eff, v, ii, ev, eii)) | |
end | |
end | |
return max | |
end | |
local left = {} | |
for _, v in pairs(valves) do if v.rate > 0 then left[#left+1] = v end end | |
local num = search(left, {}, valves.AA, 0, valves.AA, 0) | |
start = os.epoch "utc" - start | |
print("Time taken: " .. math.floor(start / 60000) .. ":" .. ((start / 1000) % 60)) | |
return num | |
end | |
aoc["17-1"] = function(file) | |
local grid = setmetatable({}, {__index = function() return 0 end}) | |
local jets = {} | |
local rocks = { | |
{ | |
w = 4, h = 1, | |
15 | |
}, | |
{ | |
w = 3, h = 3, | |
2, 7, 2 | |
}, | |
{ | |
w = 3, h = 3, | |
7, 4, 4 | |
}, | |
{ | |
w = 1, h = 4, | |
1, 1, 1, 1 | |
}, | |
{ | |
w = 2, h = 2, | |
3, 3 | |
} | |
} | |
rocks[1].next = rocks[2] | |
rocks[2].next = rocks[3] | |
rocks[3].next = rocks[4] | |
rocks[4].next = rocks[5] | |
rocks[5].next = rocks[1] | |
for c in file.readLine():gmatch "[<>]" do | |
jets[#jets+1] = {c == ">" and 1 or -1} | |
if #jets > 1 then jets[#jets-1].next = jets[#jets] end | |
end | |
jets[#jets].next = jets[1] | |
local rock = rocks[1] | |
local jet = jets[1] | |
local function checkcollision(x, y) | |
for dy = 1, rock.h do | |
if bit32.band(grid[y+dy-1], bit32.lshift(rock[dy], x)) ~= 0 then return false end | |
end | |
return true | |
end | |
for i = 1, 2022 do | |
local x, y = 2, #grid + 4 | |
while true do | |
if x + jet[1] + rock.w < 8 and x + jet[1] >= 0 and checkcollision(x + jet[1], y) then | |
x = x + jet[1] | |
end | |
jet = jet.next | |
if y > 1 and checkcollision(x, y - 1) then y = y - 1 | |
else | |
for dy = 1, rock.h do grid[y+dy-1] = bit32.bor(grid[y+dy-1], bit32.lshift(rock[dy], x)) end | |
rock = rock.next | |
break | |
end | |
end | |
end | |
return #grid | |
end | |
aoc["17-2"] = function(file) | |
local grid = setmetatable({}, {__index = function() return 0 end}) | |
local jets = {} | |
local rocks = { | |
{ | |
w = 4, h = 1, | |
15 | |
}, | |
{ | |
w = 3, h = 3, | |
2, 7, 2 | |
}, | |
{ | |
w = 3, h = 3, | |
7, 4, 4 | |
}, | |
{ | |
w = 1, h = 4, | |
1, 1, 1, 1 | |
}, | |
{ | |
w = 2, h = 2, | |
3, 3 | |
} | |
} | |
rocks[1].next = rocks[2] | |
rocks[2].next = rocks[3] | |
rocks[3].next = rocks[4] | |
rocks[4].next = rocks[5] | |
rocks[5].next = rocks[1] | |
for c in file.readLine():gmatch "[<>]" do | |
jets[#jets+1] = {c == ">" and 1 or -1} | |
if #jets > 1 then jets[#jets-1].next = jets[#jets] end | |
end | |
jets[#jets].next = jets[1] | |
local rock = rocks[1] | |
local jet = jets[1] | |
local function checkcollision(x, y) | |
for dy = 1, rock.h do | |
if bit32.band(grid[y+dy-1], bit32.lshift(rock[dy], x)) ~= 0 then return false end | |
end | |
return true | |
end | |
-- 1. calculate initial prediction data | |
local last = {[0] = 1, 1, 1, 1, 1} | |
local lastlog = {[0] = {}, {}, {}, {}, {}} | |
for i = 1, 10000 do | |
local l = #grid | |
local x, y = 2, #grid + 4 | |
while true do | |
if x + jet[1] + rock.w < 8 and x + jet[1] >= 0 and checkcollision(x + jet[1], y) then | |
x = x + jet[1] | |
end | |
jet = jet.next | |
if y > 1 and checkcollision(x, y - 1) then y = y - 1 | |
else | |
for dy = 1, rock.h do grid[y+dy-1] = bit32.bor(grid[y+dy-1], bit32.lshift(rock[dy], x)) end | |
rock = rock.next | |
break | |
end | |
end | |
local diff = #grid - l | |
lastlog[diff][#lastlog[diff]+1] = i - last[diff] | |
last[diff] = i | |
end | |
-- 2. find period of repetition on diff 4 | |
local l4 = lastlog[4] | |
local lastval = l4[#l4] | |
local plist = {} | |
for i = #l4 - 1, 1, -1 do | |
if l4[i] == lastval then | |
local p = #l4 - i | |
for j = i - p, i - 1 do | |
if l4[j] ~= l4[j+p] then p = nil break end | |
end | |
if p then plist[4] = p break end | |
end | |
end | |
if not plist[4] then error("no period found") end | |
local period = 0 | |
for i = #l4, #l4 - plist[4] + 1, -1 do period = period + l4[i] end | |
print("found period:", period) | |
-- 3. find period of repetition for 0-3 using the previously calculated period | |
for i = 0, 3 do | |
local n, s = 0, 0 | |
for j = #lastlog[i], 1, -1 do | |
n, s = n + 1, s + lastlog[i][j] | |
if s == period then break end | |
end | |
plist[i] = n | |
end | |
print("found all periods:", table.concat(plist, ", ", 0, 4)) | |
-- 4. extract repetitions into new tables; trim data to remove repetition areas | |
local repeats = {} | |
local len = {} | |
for i = 0, 4 do | |
local r = {} | |
for j = 1, plist[i] do r[j] = lastlog[i][#lastlog[i] - plist[i] + j] end | |
repeats[i] = r | |
repeat | |
local remove = true | |
for j = 1, plist[i] do | |
if lastlog[i][#lastlog[i] - plist[i] + j] ~= r[j] then remove = false break end | |
end | |
if remove then | |
local n = #lastlog[i] | |
for j = n - plist[i] + 1, n do lastlog[i][j] = nil end | |
end | |
until not remove | |
len[i] = #lastlog[i] | |
end | |
print("initial state lengths:", table.concat(len, ", ", 0, 4)) | |
-- 5. find total time of initial states | |
local init = {[0] = 0, 0, 0, 0, 0} | |
for i = 0, 4 do for _, v in ipairs(lastlog[i]) do init[i] = init[i] + v end end | |
print("initial state times:", table.concat(init, ", ", 0, 4)) | |
-- 6. calculate all possible repetitions | |
local total = 1000000000000 | |
local sum = #lastlog[1] + 2 * #lastlog[2] + 3 * #lastlog[3] + 4 * #lastlog[4] | |
local start = math.max(table.unpack(init, 0, 4)) | |
local pos = start | |
local add = #repeats[1] + 2 * #repeats[2] + 3 * #repeats[3] + 4 * #repeats[4] | |
local rnum = math.floor((total - pos) / period) | |
sum = sum + add * rnum | |
pos = pos + period * rnum | |
print("partial sum to " .. pos .. ":", sum) | |
-- 7. simulate rest of the process to find the final answer | |
local step = { | |
[0] = table.remove(repeats[0], 1) - (start - init[0]), | |
table.remove(repeats[1], 1) - (start - init[1]), | |
table.remove(repeats[2], 1) - (start - init[2]), | |
table.remove(repeats[3], 1) - (start - init[3]), | |
table.remove(repeats[4], 1) - (start - init[4]) | |
} | |
print("initial step:", table.concat(step, ", ", 0, 4)) | |
while pos < total do | |
for i = 0, 4 do | |
if step[i] == 0 then | |
sum = sum + i | |
step[i] = table.remove(repeats[i], 1) | |
end | |
step[i] = step[i] - 1 | |
end | |
pos = pos + 1 | |
end | |
return sum | |
end | |
aoc["18-1"] = function(file) | |
local sum = 0 | |
local grid = {} | |
for line in file.readLine do | |
local x, y, z = line:nmatch "(%d+),(%d+),(%d+)" | |
sum = sum + 6 | |
grid[z+y*100+x*10000] = true | |
if grid[(z+1)+y*100+x*10000] then sum = sum - 2 end | |
if grid[(z-1)+y*100+x*10000] then sum = sum - 2 end | |
if grid[z+(y+1)*100+x*10000] then sum = sum - 2 end | |
if grid[z+(y-1)*100+x*10000] then sum = sum - 2 end | |
if grid[z+y*100+(x+1)*10000] then sum = sum - 2 end | |
if grid[z+y*100+(x-1)*10000] then sum = sum - 2 end | |
end | |
return sum | |
end | |
aoc["18-2"] = function(file) | |
local sum = 0 | |
local grid = {} | |
local minz, maxz = 99, 0 | |
for line in file.readLine do | |
local x, y, z = line:nmatch "(%d+),(%d+),(%d+)" | |
sum = sum + 6 | |
minz, maxz = math.min(minz, z), math.max(maxz, z) | |
local rz = grid[z] | |
if not rz then grid[z] = {min = y, max = y} rz = grid[z] | |
else rz.min, rz.max = math.min(rz.min, y), math.max(rz.max, y) end | |
local ry = rz[y] | |
if not ry then rz[y] = {min = x, max = x} ry = rz[y] | |
else ry.min, ry.max = math.min(ry.min, x), math.max(ry.max, x) end | |
ry[x] = true | |
if grid[z+1] and grid[z+1][y] and grid[z+1][y][x] then sum = sum - 2 end | |
if grid[z-1] and grid[z-1][y] and grid[z-1][y][x] then sum = sum - 2 end | |
if rz[y+1] and rz[y+1][x] then sum = sum - 2 end | |
if rz[y-1] and rz[y-1][x] then sum = sum - 2 end | |
if ry[x+1] then sum = sum - 2 end | |
if ry[x-1] then sum = sum - 2 end | |
end | |
for z = minz, maxz do | |
local rz = grid[z] | |
if rz then | |
for y = rz.min, rz.max do | |
local ry = rz[y] | |
if ry then | |
for x = ry.min, ry.max do | |
if not ry[x] then | |
local found = false | |
for zz = z, maxz do if grid[zz] and grid[zz][y] and grid[zz][y][x] then found = true break end end | |
if found then | |
found = false | |
for zz = z, minz, -1 do if grid[zz] and grid[zz][y] and grid[zz][y][x] then found = true break end end | |
if found then | |
found = false | |
for yy = y, rz.max do if rz[yy] and rz[yy][x] then found = true break end end | |
if found then | |
found = false | |
for yy = y, rz.min, -1 do if rz[yy] and rz[yy][x] then found = true break end end | |
if found then | |
if grid[z+1] and grid[z+1][y] and grid[z+1][y][x] then sum = sum - 1 end | |
if grid[z-1] and grid[z-1][y] and grid[z-1][y][x] then sum = sum - 1 end | |
if rz[y+1] and rz[y+1][x] then sum = sum - 1 end | |
if rz[y-1] and rz[y-1][x] then sum = sum - 1 end | |
if ry[x+1] then sum = sum - 1 end | |
if ry[x-1] then sum = sum - 1 end | |
end | |
end | |
end | |
end | |
end | |
end | |
end | |
end | |
end | |
end | |
return sum | |
end | |
aoc["19-1"] = function(file) | |
local sum = 0 | |
for line in file.readLine do | |
local id, oreCost, clayCost, obsidianCostOre, obsidianCostClay, geodeCostOre, geodeCostObsidian = line:nmatch "(%d+)%D+(%d+)%D+(%d+)%D+(%d+)%D+(%d+)%D+(%d+)%D+(%d+)" | |
local memo = {} | |
local function search(i, nOreR, nClayR, nObsR, nGeodeR, ore, clay, obs, geode) | |
if nOreR >= 100 then return geode end | |
if nClayR >= 100 then return geode end | |
if nObsR >= 100 then return geode end | |
if nGeodeR >= 100 then return geode end | |
if ore >= 100 then return geode end | |
if clay >= 100 then return geode end | |
if obs >= 100 then return geode end | |
if geode >= 100 then return geode end | |
local m = memo[nOreR + nClayR * 100 + nObsR * 10000 + nGeodeR * 1000000 + ore * 100000000 + clay * 10000000000 + obs * 1000000000000 + geode * 100000000000000 + i * 10000000000000000] | |
if m then return m end | |
if i == 8 then write(".") sleep(0) end | |
if i > 24 then return geode end | |
local g = geode | |
if ore >= oreCost then g = math.max(g, search(i + 1, nOreR + 1, nClayR, nObsR, nGeodeR, ore + nOreR - oreCost, clay + nClayR, obs + nObsR, geode + nGeodeR)) end | |
if ore >= clayCost then g = math.max(g, search(i + 1, nOreR, nClayR + 1, nObsR, nGeodeR, ore + nOreR - clayCost, clay + nClayR, obs + nObsR, geode + nGeodeR)) end | |
if ore >= obsidianCostOre and clay >= obsidianCostClay then g = math.max(g, search(i + 1, nOreR, nClayR, nObsR + 1, nGeodeR, ore + nOreR - obsidianCostOre, clay + nClayR - obsidianCostClay, obs + nObsR, geode + nGeodeR)) end | |
if ore >= geodeCostOre and obs >= geodeCostObsidian then g = math.max(g, search(i + 1, nOreR, nClayR, nObsR, nGeodeR + 1, ore + nOreR - geodeCostOre, clay + nClayR, obs + nObsR - geodeCostObsidian, geode + nGeodeR)) end | |
g = math.max(g, search(i + 1, nOreR, nClayR, nObsR, nGeodeR, ore + nOreR, clay + nClayR, obs + nObsR, geode + nGeodeR)) | |
memo[nOreR + nClayR * 100 + nObsR * 10000 + nGeodeR * 1000000 + ore * 100000000 + clay * 10000000000 + obs * 1000000000000 + geode * 100000000000000 + i * 10000000000000000] = g | |
return g | |
end | |
local g = search(1, 1, 0, 0, 0, 0, 0, 0, 0) | |
print(g) | |
sum = sum + id * g | |
end | |
return sum | |
end | |
aoc["19-2"] = function(file) | |
local sum = 1 | |
local n = 0 | |
for line in file.readLine do | |
local id, oreCost, clayCost, obsidianCostOre, obsidianCostClay, geodeCostOre, geodeCostObsidian = line:nmatch "(%d+)%D+(%d+)%D+(%d+)%D+(%d+)%D+(%d+)%D+(%d+)%D+(%d+)" | |
local memo = {} | |
local function search(i, nOreR, nClayR, nObsR, nGeodeR, ore, clay, obs, geode) | |
if nOreR >= 100 then return geode end | |
if nClayR >= 100 then return geode end | |
if nObsR >= 100 then return geode end | |
if nGeodeR >= 100 then return geode end | |
if ore >= 1000 then return geode end | |
if clay >= 1000 then return geode end | |
if obs >= 1000 then return geode end | |
if geode >= 1000 then return geode end | |
local m = memo[nOreR + nClayR * 100 + nObsR * 10000 + nGeodeR * 1000000 + ore * 100000000 + clay * 100000000000 + obs * 100000000000000 + geode * 100000000000000000 + i * 100000000000000000000] | |
if m then return m end | |
if i == 8 then write(".") sleep(0) end | |
if i > 32 then return geode end | |
local g = geode | |
if ore >= oreCost then g = math.max(g, search(i + 1, nOreR + 1, nClayR, nObsR, nGeodeR, ore + nOreR - oreCost, clay + nClayR, obs + nObsR, geode + nGeodeR)) end | |
if ore >= clayCost then g = math.max(g, search(i + 1, nOreR, nClayR + 1, nObsR, nGeodeR, ore + nOreR - clayCost, clay + nClayR, obs + nObsR, geode + nGeodeR)) end | |
if ore >= obsidianCostOre and clay >= obsidianCostClay then g = math.max(g, search(i + 1, nOreR, nClayR, nObsR + 1, nGeodeR, ore + nOreR - obsidianCostOre, clay + nClayR - obsidianCostClay, obs + nObsR, geode + nGeodeR)) end | |
if ore >= geodeCostOre and obs >= geodeCostObsidian then g = math.max(g, search(i + 1, nOreR, nClayR, nObsR, nGeodeR + 1, ore + nOreR - geodeCostOre, clay + nClayR, obs + nObsR - geodeCostObsidian, geode + nGeodeR)) end | |
g = math.max(g, search(i + 1, nOreR, nClayR, nObsR, nGeodeR, ore + nOreR, clay + nClayR, obs + nObsR, geode + nGeodeR)) | |
memo[nOreR + nClayR * 100 + nObsR * 10000 + nGeodeR * 1000000 + ore * 100000000 + clay * 10000000000 + obs * 1000000000000 + geode * 100000000000000 + i * 10000000000000000] = g | |
return g | |
end | |
local g = search(1, 1, 0, 0, 0, 0, 0, 0, 0) | |
print(g) | |
sum = sum * g | |
n = n + 1 | |
if n == 3 then break end | |
end | |
return sum | |
end | |
aoc["20-1"] = function(file) | |
local list = {} | |
local zero | |
for line in file.readLine do | |
local n = {n = tonumber(line), prev = list[#list]} | |
if n.n == 0 then zero = n end | |
if #list > 0 then list[#list].next = n end | |
list[#list+1] = n | |
end | |
list[1].prev = list[#list] | |
list[#list].next = list[1] | |
for _, v in ipairs(list) do | |
if v.n < 0 then | |
v.prev.next = v.next | |
v.next.prev = v.prev | |
for i = -1, v.n, -1 do v.prev = v.prev.prev end | |
v.next = v.prev.next | |
v.prev.next = v | |
v.next.prev = v | |
elseif v.n > 0 then | |
v.prev.next = v.next | |
v.next.prev = v.prev | |
for i = 1, v.n do v.next = v.next.next end | |
v.prev = v.next.prev | |
v.prev.next = v | |
v.next.prev = v | |
end | |
end | |
local sum = 0 | |
for i = 1, 1000 do zero = zero.next end | |
sum = sum + zero.n | |
for i = 1, 1000 do zero = zero.next end | |
sum = sum + zero.n | |
for i = 1, 1000 do zero = zero.next end | |
sum = sum + zero.n | |
return sum | |
end | |
aoc["20-2"] = function(file) | |
local list = {} | |
local zero | |
for line in file.readLine do | |
local n = {n = tonumber(line) * 811589153, prev = list[#list]} | |
if n.n == 0 then zero = n end | |
if #list > 0 then list[#list].next = n end | |
list[#list+1] = n | |
end | |
list[1].prev = list[#list] | |
list[#list].next = list[1] | |
for _ = 1, 10 do | |
for _, v in ipairs(list) do | |
local r = math.fmod(v.n, #list - 1) | |
if r < 0 then | |
v.prev.next = v.next | |
v.next.prev = v.prev | |
for _ = -1, r, -1 do v.prev = v.prev.prev end | |
v.next = v.prev.next | |
v.prev.next = v | |
v.next.prev = v | |
elseif r > 0 then | |
v.prev.next = v.next | |
v.next.prev = v.prev | |
for _ = 1, r do v.next = v.next.next end | |
v.prev = v.next.prev | |
v.prev.next = v | |
v.next.prev = v | |
end | |
end | |
end | |
local sum = 0 | |
for i = 1, 1000 do zero = zero.next end | |
print(zero.n) | |
sum = sum + zero.n | |
for i = 1, 1000 do zero = zero.next end | |
print(zero.n) | |
sum = sum + zero.n | |
for i = 1, 1000 do zero = zero.next end | |
print(zero.n) | |
sum = sum + zero.n | |
return sum | |
end | |
aoc["21-1"] = function(file) | |
local list = {} | |
for line in file.readLine do | |
local name, val = line:match "([^:]+): (.+)$" | |
if tonumber(val) then list[name] = tonumber(val) | |
else list[name] = load("return " .. val, "=" .. name, "t", list) end | |
end | |
repeat | |
for k, v in pairs(list) do if type(v) ~= "number" then | |
local ok, res = pcall(v) | |
if ok then list[k] = res end | |
end end | |
until type(list.root) == "number" | |
return list.root | |
end | |
aoc["21-2"] = function(file) | |
local list = {} | |
for line in file.readLine do | |
local name, val = line:match "([^:]+): (.+)$" | |
if tonumber(val) then list[name] = tonumber(val) | |
else list[name] = val end | |
end | |
list.humn = nil | |
repeat | |
local changed = false | |
for k, v in pairs(list) do if type(v) == "string" then | |
local ok, res = pcall(load("return " .. v, "=" .. k, "t", list)) | |
if ok then list[k] = res changed = true end | |
end end | |
until not changed | |
list.humn = "humn" | |
list.root = list.root:gsub("%+", "=") | |
repeat | |
list.root = list.root:gsub("%a+", function(s) return "(" .. list[s] .. ")" end) | |
until list.root:find("humn") and not list.root:gsub("humn", ""):find("%a") | |
local lhs, rhs = list.root:match("([^=]+) = %((%d+)%)$") | |
rhs = tonumber(rhs) | |
while lhs ~= "humn" do | |
if lhs:match "^%b()$" then lhs = lhs:sub(2, -2) | |
else | |
print(lhs) | |
local l, op, r = lhs:match "(%b()) ([%+%-%*/]) (%b())" | |
local v, k | |
if l:match "^[%d%(%)]+$" then k, v = l, r | |
elseif r:match "^[%d%(%)]+$" then k, v = r, l | |
else error("Not reduced") end | |
while k:match "^%(.+%)$" do k = k:sub(2, -2) end | |
k = tonumber(k) | |
if op == "+" then rhs = rhs - k | |
elseif op == "*" then rhs = rhs / k | |
elseif op == "-" then | |
if l == v then rhs = rhs + k | |
else rhs = k - rhs end | |
elseif op == "/" then | |
if l == v then rhs = rhs * k | |
else rhs = k / rhs end | |
end | |
lhs = v | |
end | |
end | |
return rhs | |
end | |
aoc["22-1"] = function(file) | |
local grid = {} | |
local inst = {} | |
local w = 0 | |
for line in file.readLine do | |
if line == "" then | |
local ll = file.readLine() | |
for n, d in ll:gnmatch "(%d+)([RL]?)" do | |
inst[#inst+1] = n | |
if d ~= "" then inst[#inst+1] = d end | |
end | |
else | |
local l = {} | |
for i, c in line:gmatch "()(.)" do if c ~= " " then l[i] = c == "#" end end | |
grid[#grid+1] = l | |
w = math.max(w, #line) | |
end | |
end | |
local pos = vector.new(1, 1) | |
while grid[1][pos.x] == nil do print(pos) pos.x = pos.x + 1 end | |
local dir = vector.new(1, 0) | |
for _, v in ipairs(inst) do | |
if type(v) == "number" then | |
for i = 1, v do | |
print(pos) | |
local p = pos + dir | |
local d = (grid[p.y] or {})[p.x] | |
if d == nil then | |
if dir.x == 0 then | |
if dir.y == 1 then p.y = 1 | |
else p.y = #grid end | |
elseif dir.x == 1 then p.x = 1 | |
else p.x = w end | |
while (grid[p.y] or {})[p.x] == nil do p = p + dir end | |
d = (grid[p.y] or {})[p.x] | |
end | |
if d == true then break end | |
pos = p | |
end | |
elseif v == "R" then dir = vector.new(-dir.y, dir.x) | |
elseif v == "L" then dir = vector.new(dir.y, -dir.x) | |
else error("?") end | |
end | |
local dt = {[-1] = {[0] = 3}, [0] = {[-1] = 2, [1] = 0}, [1] = {[0] = 1}} | |
return pos.y * 1000 + pos.x * 4 + dt[dir.y][dir.x] | |
end | |
aoc["22-2"] = function(file) | |
-- sectors order: top, left, bottom, right, front, back | |
--[ [ | |
-- test input | |
local sector_size = 4 | |
local sector_map = { | |
{nil, nil, 1}, | |
{6, 2, 5}, | |
{nil, nil, 3, 4} | |
} | |
local sector_connections = { | |
{ -- top | |
[-1] = {[0] = {6, vector.new(0, 1)}}, -- up | |
[0] = { | |
[-1] = {2, vector.new(0, 1)}, -- left | |
[ 1] = {4, vector.new(0, 1)} -- right | |
}, | |
[1] = {[0] = {5, vector.new(0, 1)}} -- down | |
}, | |
{ -- left | |
[-1] = {[0] = {1, vector.new(1, 0)}}, | |
[0] = { | |
[-1] = {6, vector.new(0, -1)}, | |
[ 1] = {5, vector.new(0, 1)} | |
}, | |
[1] = {[0] = {3, vector.new(1, 0)}} | |
}, | |
{ -- bottom | |
[-1] = {[0] = {5, vector.new(0, -1)}}, | |
[0] = { | |
[-1] = {2, vector.new(0, -1)}, | |
[ 1] = {4, vector.new(1, 0)} | |
}, | |
[1] = {[0] = {6, vector.new(0, -1)}} | |
}, | |
{ -- right | |
[-1] = {[0] = {5, vector.new(-1, 0)}}, | |
[0] = { | |
[-1] = {3, vector.new(-1, 0)}, | |
[ 1] = {1, vector.new(-1, 0)} | |
}, | |
[1] = {[0] = {6, vector.new(1, 0)}} | |
}, | |
{ -- front | |
[-1] = {[0] = {1, vector.new(0, -1)}}, | |
[0] = { | |
[-1] = {2, vector.new(-1, 0)}, | |
[ 1] = {4, vector.new(0, 1)} | |
}, | |
[1] = {[0] = {3, vector.new(0, 1)}} | |
}, | |
{ -- back | |
[-1] = {[0] = {1, vector.new(0, 1)}}, | |
[0] = { | |
[-1] = {4, vector.new(0, -1)}, | |
[ 1] = {2, vector.new(1, 0)} | |
}, | |
[1] = {[0] = {3, vector.new(0, -1)}} | |
}, | |
} | |
--[=[]] | |
-- your input | |
local sector_size = 50 | |
local sector_map = { | |
{nil, 1, 4}, | |
{nil, 5}, | |
{2, 3}, | |
{6} | |
} | |
local sector_connections = { | |
{ -- top | |
[-1] = {[0] = {6, vector.new(1, 0)}}, -- up | |
[0] = { | |
[-1] = {2, vector.new(1, 0)}, -- left | |
[ 1] = {4, vector.new(1, 0)} -- right | |
}, | |
[1] = {[0] = {5, vector.new(0, 1)}} -- down | |
}, | |
{ -- left | |
[-1] = {[0] = {5, vector.new(1, 0)}}, | |
[0] = { | |
[-1] = {1, vector.new(1, 0)}, | |
[ 1] = {3, vector.new(1, 0)} | |
}, | |
[1] = {[0] = {6, vector.new(0, 1)}} | |
}, | |
{ -- bottom | |
[-1] = {[0] = {5, vector.new(0, -1)}}, | |
[0] = { | |
[-1] = {2, vector.new(-1, 0)}, | |
[ 1] = {4, vector.new(-1, 0)} | |
}, | |
[1] = {[0] = {6, vector.new(-1, 0)}} | |
}, | |
{ -- right | |
[-1] = {[0] = {6, vector.new(0, -1)}}, | |
[0] = { | |
[-1] = {1, vector.new(-1, 0)}, | |
[ 1] = {3, vector.new(-1, 0)} | |
}, | |
[1] = {[0] = {5, vector.new(-1, 0)}} | |
}, | |
{ -- front | |
[-1] = {[0] = {1, vector.new(0, -1)}}, | |
[0] = { | |
[-1] = {2, vector.new(0, 1)}, | |
[ 1] = {4, vector.new(0, -1)} | |
}, | |
[1] = {[0] = {3, vector.new(0, 1)}} | |
}, | |
{ -- back | |
[-1] = {[0] = {2, vector.new(0, -1)}}, | |
[0] = { | |
[-1] = {1, vector.new(0, 1)}, | |
[ 1] = {3, vector.new(0, -1)} | |
}, | |
[1] = {[0] = {4, vector.new(0, 1)}} | |
}, | |
} | |
--]=] | |
local sector_pos = {} | |
for y, r in pairs(sector_map) do | |
for x, v in pairs(r) do | |
sector_pos[v] = vector.new((x-1) * sector_size + 1, (y-1) * sector_size + 1) | |
end | |
end | |
local grid = {} | |
local inst = {} | |
local w = 0 | |
for line in file.readLine do | |
if line == "" then | |
local ll = file.readLine() | |
for n, d in ll:gnmatch "(%d+)([RL]?)" do | |
inst[#inst+1] = n | |
if d ~= "" then inst[#inst+1] = d end | |
end | |
else | |
local l = {} | |
for i, c in line:gmatch "()(.)" do if c ~= " " then l[i] = c == "#" end end | |
grid[#grid+1] = l | |
w = math.max(w, #line) | |
end | |
end | |
local pos, dir | |
local function move(test) | |
local p = pos + dir | |
local d = (grid[p.y] or {})[p.x] | |
local pd = dir | |
if d == nil then | |
--[[local a, b, ad, bd | |
if dir.x == 0 then | |
ad, bd = vector.new(-1, dir.y), vector.new(1, dir.y) | |
local an = math.floor((pos.x - 1) / sector_size) * sector_size | |
a = vector.new(an, pos.y + dir.y * (pos.x - an)) | |
local bn = (math.floor((pos.x - 1) / sector_size) + 1) * sector_size + 1 | |
b = vector.new(bn, pos.y - dir.y * (pos.x - bn)) | |
else | |
ad, bd = vector.new(dir.x, -1), vector.new(dir.x, 1) | |
local an = math.floor((pos.y - 1) / sector_size) * sector_size | |
a = vector.new(pos.x + dir.x * (pos.y - an), an) | |
local bn = (math.floor((pos.y - 1) / sector_size) + 1) * sector_size + 1 | |
b = vector.new(pos.x - dir.x * (pos.y - bn), bn) | |
end | |
print(a, b) | |
if (grid[a.y] or {})[a.x] ~= nil then p, d, dir = a, grid[p.y][p.x], vector.new(dir.y, -dir.x) | |
elseif (grid[b.y] or {})[b.x] ~= nil then p, d, dir = b, grid[p.y][p.x], vector.new(-dir.y, dir.x) | |
else | |
local pd | |
if a.x < 1 or a.y < 1 or a.x > w or a.y > #grid then p, pd = a, ad | |
elseif b.x < 1 or b.y < 1 or b.x > w or b.y > #grid then p, pd = b, bd | |
else error("ambiguous") end | |
p = p + pd:mul(sector_size) - dir | |
local dd = vector.new(dir.y, -dir.x) | |
while (grid[p.y] or {})[p.x] == nil do | |
p = p + dd | |
assert(not (p.x < 1 or p.y < 1 or p.x > w or p.y > #grid)) | |
end | |
d = grid[p.y][p.x] | |
dir = -dir | |
end]] | |
local sector = sector_map[math.floor((pos.y - 1) / sector_size) + 1][math.floor((pos.x - 1) / sector_size) + 1] | |
local next = sector_connections[sector][dir.y][dir.x] | |
print(pos, sector, next[1]) | |
if dir:dot(next[2]) == 0 then | |
-- adjacent | |
p = sector_pos[next[1]] | |
if next[2].x == -1 then p = p + vector.new(sector_size - 1, 0) | |
elseif next[2].y == -1 then p = p + vector.new(0, sector_size - 1) end | |
p = p + vector.new(dir.y == 0 and (pos.y - 1) % sector_size or 0, dir.x == 0 and (pos.x - 1) % sector_size or 0) | |
elseif dir == next[2] then | |
-- loop around | |
p = sector_pos[next[1]] | |
if dir.x == -1 then p = p + vector.new(sector_size - 1, 0) | |
elseif dir.y == -1 then p = p + vector.new(0, sector_size - 1) end | |
p = p + vector.new(dir.x == 0 and (pos.x - 1) % sector_size or 0, dir.y == 0 and (pos.y - 1) % sector_size or 0) | |
else -- -dir == next[2] | |
-- flip | |
p = sector_pos[next[1]] | |
if next[2].x == -1 then p = p + vector.new(sector_size - 1, 0) end | |
if next[2].y == -1 then p = p + vector.new(0, sector_size - 1) end | |
p = p + vector.new( | |
math.abs(dir.y) * (sector_size - ((pos.x-1) % sector_size) - 1), | |
math.abs(dir.x) * (sector_size - ((pos.y-1) % sector_size) - 1) | |
) | |
end | |
print(p) | |
d = (grid[p.y] or {})[p.x] | |
pd = next[2] | |
end | |
if d == true and not test then return true end | |
pos = p | |
dir = pd | |
end | |
local dirnam = {"right", "down", "left", "up"} | |
for s = 1, 6 do | |
local v = vector.new(1, 0) | |
for i = 1, 4 do | |
dir = v | |
local p = sector_pos[s] + vector.new(dir.x == 0 and 22 or 0, dir.y == 0 and 22 or 0) | |
if dir.x == 1 then p = p + vector.new(sector_size - 1, 0) | |
elseif dir.y == 1 then p = p + vector.new(0, sector_size - 1) end | |
pos = p | |
move(true) | |
dir = -dir | |
move(true) | |
assert(pos == p, "sector " .. s .. " direction " .. dirnam[i] .. ": " .. pos:tostring() .. " ~= " .. p:tostring()) | |
assert(dir == -v, "sector " .. s .. " direction " .. dirnam[i] .. ": direction " .. dir:tostring() .. " ~= " .. v:tostring()) | |
v = vector.new(v.y, -v.x) | |
end | |
v = vector.new(1, 0) | |
for i = 1, 4 do | |
dir = v | |
local p = sector_pos[s] | |
if dir.x == 1 then p = p + vector.new(sector_size - 1, 0) | |
elseif dir.y == 1 then p = p + vector.new(0, sector_size - 1) end | |
pos = p | |
move(true) | |
assert((pos.x % sector_size == 0 or pos.x % sector_size == 1) and (pos.y % sector_size == 0 or pos.y % sector_size == 1), "sector " .. s .. " direction " .. dirnam[i] .. ": " .. pos:tostring() .. " not on corner") | |
dir = -dir | |
move(true) | |
assert(pos == p, "sector " .. s .. " direction " .. dirnam[i] .. ": " .. pos:tostring() .. " ~= " .. p:tostring()) | |
assert(dir == -v, "sector " .. s .. " direction " .. dirnam[i] .. ": direction " .. dir:tostring() .. " ~= " .. v:tostring()) | |
v = vector.new(v.y, -v.x) | |
end | |
end | |
print("test success") | |
pos = vector.new(1, 1) | |
while grid[1][pos.x] == nil do pos.x = pos.x + 1 end | |
dir = vector.new(1, 0) | |
for _, v in ipairs(inst) do | |
if type(v) == "number" then | |
for _ = 1, v do | |
if move() then break end | |
end | |
elseif v == "R" then dir = vector.new(-dir.y, dir.x) | |
elseif v == "L" then dir = vector.new(dir.y, -dir.x) | |
else error("?") end | |
end | |
local dt = {[-1] = {[0] = 3}, [0] = {[-1] = 2, [1] = 0}, [1] = {[0] = 1}} | |
return pos.y * 1000 + pos.x * 4 + dt[dir.y][dir.x] | |
end | |
aoc["23-1"] = function(file) | |
local elves = {} | |
local grid = {} | |
local y = 1 | |
local miny, maxy, minx, maxx = 1, 1, 1, 1 | |
for line in file.readLine do | |
grid[y] = {} | |
maxy = y | |
for x in line:gmatch "()#" do | |
elves[#elves+1] = {pos = vector.new(x, y)} | |
grid[y][x] = elves[#elves] | |
maxx = math.max(maxx, x) | |
end | |
y = y + 1 | |
end | |
local dirs = {vector.new(0, -1), vector.new(0, 1), vector.new(-1, 0), vector.new(1, 0)} | |
for i = 1, 10 do | |
local prop = {} | |
for _, v in ipairs(elves) do | |
local found = false | |
for yy = -1, 1 do | |
for xx = -1, 1 do | |
if not (yy == 0 and xx == 0) and grid[v.pos.y+yy] and grid[v.pos.y+yy][v.pos.x+xx] then found = true break end | |
end | |
end | |
if found then | |
for d = 1, 4 do | |
local np = v.pos + dirs[d] | |
local ap = v.pos + dirs[d] + vector.new(dirs[d].y, dirs[d].x) | |
local bp = v.pos + dirs[d] + vector.new(-dirs[d].y, -dirs[d].x) | |
if not (grid[np.y] and grid[np.y][np.x]) and | |
not (grid[ap.y] and grid[ap.y][ap.x]) and | |
not (grid[bp.y] and grid[bp.y][bp.x]) then | |
v.prop = np | |
prop[np.y] = prop[np.y] or {} | |
prop[np.y][np.x] = (prop[np.y][np.x] or 0) + 1 | |
break | |
end | |
end | |
end | |
end | |
miny, maxy, minx, maxx = math.huge, -math.huge, math.huge, -math.huge | |
for _, v in ipairs(elves) do | |
if v.prop and prop[v.prop.y] and prop[v.prop.y][v.prop.x] == 1 then | |
grid[v.pos.y][v.pos.x] = nil | |
v.pos = v.prop | |
v.prop = nil | |
grid[v.pos.y] = grid[v.pos.y] or {} | |
grid[v.pos.y][v.pos.x] = v | |
end | |
miny, maxy, minx, maxx = math.min(miny, v.pos.y), math.max(maxy, v.pos.y), math.min(minx, v.pos.x), math.max(maxx, v.pos.x) | |
end | |
table.insert(dirs, table.remove(dirs, 1)) | |
end | |
return (maxx - minx + 1) * (maxy - miny + 1) - #elves | |
end | |
local vnew = vector.new | |
-- Writer's note: This was way overoptimized due to breaking the code, causing | |
-- me to think that the answer was over a million. It was not. I'm leaving the | |
-- optimization here because I did the work, but the 23-1 code should work fine | |
-- on Accelerated too (maybe with a bit of localization). | |
aoc["23-2"] = function(file) | |
local elves = {} | |
local grid = {} | |
local y = 1 | |
for line in file.readLine do | |
grid[y] = {} | |
for x in line:gmatch "()#" do | |
elves[#elves+1] = {pos = vector.new(x, y)} | |
grid[y][x] = elves[#elves] | |
end | |
y = y + 1 | |
end | |
local dirs = {[0] = vector.new(0, -1), vector.new(0, 1), vector.new(-1, 0), vector.new(1, 0)} | |
local ds = 0 | |
local i = 0 | |
local nelves = #elves | |
repeat | |
i = i + 1 | |
local prop = {} | |
local pp = {} | |
for k = 1, nelves do | |
local v = elves[k] | |
local pos = v.pos | |
local found = false | |
local l_1, l, l1 = grid[pos.y-1], grid[pos.y], grid[pos.y+1] | |
if not found and l[pos.x-1] then found = true end | |
if not found and l[pos.x+1] then found = true end | |
if not found and l_1 and l_1[pos.x ] then found = true end | |
if not found and l1 and l1 [pos.x ] then found = true end | |
if not found and l_1 and l_1[pos.x-1] then found = true end | |
if not found and l_1 and l_1[pos.x+1] then found = true end | |
if not found and l1 and l1 [pos.x-1] then found = true end | |
if not found and l1 and l1 [pos.x+1] then found = true end | |
if found then | |
do | |
local dir = dirs[ds] | |
local np = pos + dir | |
local ap = np + vnew(dir.y, dir.x) | |
local bp = np + vnew(-dir.y, -dir.x) | |
if not (grid[np.y] and grid[np.y][np.x]) and | |
not (grid[ap.y] and grid[ap.y][ap.x]) and | |
not (grid[bp.y] and grid[bp.y][bp.x]) then | |
v.prop = np | |
local ll = prop[np.y] | |
if not ll then ll = {} prop[np.y] = ll end | |
ll[np.x] = (ll[np.x] or 0) + 1 | |
pp[#pp+1] = v | |
found = false | |
end | |
end | |
if found then | |
local dd = (1 + ds) % 4 | |
local dir = dirs[dd] | |
local np = pos + dir | |
local ap = np + vnew(dir.y, dir.x) | |
local bp = np + vnew(-dir.y, -dir.x) | |
if not (grid[np.y] and grid[np.y][np.x]) and | |
not (grid[ap.y] and grid[ap.y][ap.x]) and | |
not (grid[bp.y] and grid[bp.y][bp.x]) then | |
v.prop = np | |
local ll = prop[np.y] | |
if not ll then ll = {} prop[np.y] = ll end | |
ll[np.x] = (ll[np.x] or 0) + 1 | |
pp[#pp+1] = v | |
found = false | |
end | |
end | |
if found then | |
local dd = (2 + ds) % 4 | |
local dir = dirs[dd] | |
local np = pos + dir | |
local ap = np + vnew(dir.y, dir.x) | |
local bp = np + vnew(-dir.y, -dir.x) | |
if not (grid[np.y] and grid[np.y][np.x]) and | |
not (grid[ap.y] and grid[ap.y][ap.x]) and | |
not (grid[bp.y] and grid[bp.y][bp.x]) then | |
v.prop = np | |
local ll = prop[np.y] | |
if not ll then ll = {} prop[np.y] = ll end | |
ll[np.x] = (ll[np.x] or 0) + 1 | |
pp[#pp+1] = v | |
found = false | |
end | |
end | |
if found then | |
local dd = (3 + ds) % 4 | |
local dir = dirs[dd] | |
local np = pos + dir | |
local ap = np + vnew(dir.y, dir.x) | |
local bp = np + vnew(-dir.y, -dir.x) | |
if not (grid[np.y] and grid[np.y][np.x]) and | |
not (grid[ap.y] and grid[ap.y][ap.x]) and | |
not (grid[bp.y] and grid[bp.y][bp.x]) then | |
v.prop = np | |
local ll = prop[np.y] | |
if not ll then ll = {} prop[np.y] = ll end | |
ll[np.x] = (ll[np.x] or 0) + 1 | |
pp[#pp+1] = v | |
found = false | |
end | |
end | |
end | |
end | |
local moved = false | |
for k = 1, #pp do | |
local v = pp[k] | |
local pro = v.prop | |
if prop[pro.y][pro.x] == 1 then | |
moved = true | |
grid[v.pos.y][v.pos.x] = nil | |
v.pos = pro | |
v.prop = nil | |
if not grid[pro.y] then grid[pro.y] = {} end | |
grid[pro.y][pro.x] = v | |
end | |
end | |
ds = (ds + 1) % 4 | |
if i % 1000 == 0 then print(i) sleep(0) end | |
until not moved | |
return i | |
end | |
aoc["24-1"] = function(file) | |
local maps = {["<"] = {}, [">"] = {}, ["^"] = {}, v = {}} | |
local h = 1 | |
local w | |
for line in file.readLine do | |
if not line:find "##" then | |
w = #line - 2 | |
for x, c in line:gmatch "()([<>^v])" do | |
local n = (c == "<" or c == ">") and h or (x - 1) | |
maps[c][n] = maps[c][n] or {} | |
maps[c][n][(c == "<" or c == ">") and (x - 1) or h] = c | |
end | |
h = h + 1 | |
end | |
end | |
h = h - 1 | |
local stepw, steph = 1, 1 | |
local pos = 0x0100 | |
local lq = {} | |
local nlq = 1 | |
lq[1] = pos | |
local q = {} | |
local qp = {} | |
local nq = 0 | |
local n = 0 | |
local up, down, left, right = 0xFFFF, 0x0001, 0xFF00, 0x0100 | |
local i = 1 | |
local empty = {} | |
local function check(x, y) | |
return (qp[y] and qp[y][x]) or | |
(maps["<"][y] or empty)[(x + stepw - 1) % w + 1] or | |
(maps[">"][y] or empty)[(x - stepw - 1) % w + 1] or | |
(maps["^"][x] or empty)[(y + steph - 1) % h + 1] or | |
(maps["v"][x] or empty)[(y - steph - 1) % h + 1] | |
end | |
while true do | |
if i > nlq then | |
if nq == 0 then break end | |
sleep(0) | |
n = n + 1 | |
stepw = (stepw + 1) % w | |
steph = (steph + 1) % h | |
lq, nlq = q, nq | |
q, nq = {}, 0 | |
i = 1 | |
qp = {} | |
else | |
local v = lq[i] | |
i = i + 1 | |
local x, y = bit32.band(bit32.rshift(v, 8), 0xFF), bit32.band(v, 0xFF) | |
if x == w and y == h + 1 then | |
return n | |
end | |
if not check(x, y) then | |
q[nq+1], nq = v, nq + 1 | |
qp[y] = qp[y] or {} | |
qp[y][x] = true | |
end | |
if y == 0 then | |
if not check(x, y + 1) then | |
q[nq+1], nq = bit32.band(v + down, 0xFFFF), nq + 1 | |
qp[y+1] = qp[y+1] or {} | |
qp[y+1][x] = true | |
end | |
else | |
if x > 1 then | |
if not check(x - 1, y) then | |
q[nq+1], nq = bit32.band(v + left, 0xFFFF), nq + 1 | |
qp[y] = qp[y] or {} | |
qp[y][x-1] = true | |
end | |
end | |
if x < w then | |
if not check(x + 1, y) then | |
q[nq+1], nq = bit32.band(v + right, 0xFFFF), nq + 1 | |
qp[y] = qp[y] or {} | |
qp[y][x+1] = true | |
end | |
end | |
if y > 1 then | |
if not check(x, y - 1) then | |
q[nq+1], nq = bit32.band(v + up, 0xFFFF), nq + 1 | |
qp[y-1] = qp[y-1] or {} | |
qp[y-1][x] = true | |
end | |
end | |
if y < h or x == w then | |
if not check(x, y + 1) then | |
q[nq+1], nq = bit32.band(v + down, 0xFFFF), nq + 1 | |
qp[y+1] = qp[y+1] or {} | |
qp[y+1][x] = true | |
end | |
end | |
end | |
end | |
end | |
error("failure") | |
end | |
aoc["24-2"] = function(file) | |
local maps = {["<"] = {}, [">"] = {}, ["^"] = {}, v = {}} | |
local h = 1 | |
local w | |
for line in file.readLine do | |
if not line:find "##" then | |
w = #line - 2 | |
for x, c in line:gmatch "()([<>^v])" do | |
local n = (c == "<" or c == ">") and h or (x - 1) | |
maps[c][n] = maps[c][n] or {} | |
maps[c][n][(c == "<" or c == ">") and (x - 1) or h] = c | |
end | |
h = h + 1 | |
end | |
end | |
h = h - 1 | |
local stepw, steph = 1, 1 | |
local up, down, left, right = 0xFFFF, 0x0001, 0xFF00, 0x0100 | |
local empty = {} | |
local function run(pos, gx, gy) | |
local lq = {pos} | |
local nlq = 1 | |
local q = {} | |
local qp = {} | |
local nq = 0 | |
local n = 0 | |
local i = 1 | |
local function check(x, y) | |
return (qp[y] and qp[y][x]) or | |
(maps["<"][y] or empty)[(x + stepw - 1) % w + 1] or | |
(maps[">"][y] or empty)[(x - stepw - 1) % w + 1] or | |
(maps["^"][x] or empty)[(y + steph - 1) % h + 1] or | |
(maps["v"][x] or empty)[(y - steph - 1) % h + 1] | |
end | |
while true do | |
if i > nlq then | |
if nq == 0 then break end | |
sleep(0) | |
n = n + 1 | |
stepw = (stepw + 1) % w | |
steph = (steph + 1) % h | |
lq, nlq = q, nq | |
q, nq = {}, 0 | |
i = 1 | |
qp = {} | |
else | |
local v = lq[i] | |
i = i + 1 | |
local x, y = bit32.band(bit32.rshift(v, 8), 0xFF), bit32.band(v, 0xFF) | |
if x == gx and y == gy then | |
return n | |
end | |
if not check(x, y) then | |
q[nq+1], nq = v, nq + 1 | |
qp[y] = qp[y] or {} | |
qp[y][x] = true | |
end | |
if y == 0 then | |
if not check(x, y + 1) then | |
q[nq+1], nq = bit32.band(v + down, 0xFFFF), nq + 1 | |
qp[y+1] = qp[y+1] or {} | |
qp[y+1][x] = true | |
end | |
else | |
if x > 1 then | |
if not check(x - 1, y) then | |
q[nq+1], nq = bit32.band(v + left, 0xFFFF), nq + 1 | |
qp[y] = qp[y] or {} | |
qp[y][x-1] = true | |
end | |
end | |
if x < w then | |
if not check(x + 1, y) then | |
q[nq+1], nq = bit32.band(v + right, 0xFFFF), nq + 1 | |
qp[y] = qp[y] or {} | |
qp[y][x+1] = true | |
end | |
end | |
if y > 1 or (x == 1 and y == 1) then | |
if not check(x, y - 1) then | |
q[nq+1], nq = bit32.band(v + up, 0xFFFF), nq + 1 | |
qp[y-1] = qp[y-1] or {} | |
qp[y-1][x] = true | |
end | |
end | |
if y < h or (x == w and y == h) then | |
if not check(x, y + 1) then | |
q[nq+1], nq = bit32.band(v + down, 0xFFFF), nq + 1 | |
qp[y+1] = qp[y+1] or {} | |
qp[y+1][x] = true | |
end | |
end | |
end | |
end | |
end | |
error("failure") | |
end | |
return run(0x0100, w, h + 1) + run(w * 256 + h + 1, 1, 0) + run(0x0100, w, h + 1) | |
end | |
aoc["25-1"] = function(file) | |
local function snafu(n) | |
local r = 0 | |
for x, c in n:gmatch "()(.)" do r = r + 5^(#n - x) * (tonumber(c) or (c == "-" and -1 or -2)) end | |
return r | |
end | |
local sum = 0 | |
for line in file.readLine do | |
local n = snafu(line) | |
assert(n >= 0, n) | |
sum = sum + n | |
end | |
local retval = "" | |
local carry = 0 | |
while sum > 0 do | |
local d = (sum % 5) + carry | |
if d == 5 then | |
carry = 1 | |
retval = retval .. "0" | |
elseif d > 2 then | |
carry = 1 | |
retval = retval .. (d == 3 and "=" or "-") | |
else | |
carry = 0 | |
retval = retval .. d | |
end | |
sum = math.floor(sum / 5) | |
end | |
return retval:reverse() | |
end | |
run(...) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment