Skip to content

Instantly share code, notes, and snippets.

@MCJack123
Last active January 8, 2023 00:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MCJack123/5e64418d01f466d475db2f9678befcc1 to your computer and use it in GitHub Desktop.
Save MCJack123/5e64418d01f466d475db2f9678befcc1 to your computer and use it in GitHub Desktop.
Advent of Code 2022 solutions (Run in CraftOS-PC w/CCEmuX plugin)
-- 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