adventofcode-2021/day23/part2.lua

158 lines
3.5 KiB
Lua
Raw Normal View History

2021-12-23 11:49:11 +01:00
#!/usr/bin/env luajit
require("utils")
local targets = { A=3, B=5, C=7, D=9 }
local costs = { A=1, B=10, C=100, D=1000 }
local f = io.open(arg[3])
local line = f:read("*l") -- #####
line = f:read("*l") -- #...#
local hall = {}
local length = #line - 2
line = f:read("*l") -- ##A#B##
local rooms = {}
local depth = 1
local ncorrect = 0
while line do
local l = 0
for char in chars(line) do
if char ~= "#" and char ~= " " then
if rooms[l] == nil then rooms[l] = {} end
table.insert(rooms[l], char)
if targets[char] == l then ncorrect = ncorrect + 1 end
end
l = l + 1
end
line = f:read("*l") -- ##A#B##
depth = depth + 1
end
table.insert(rooms[3], 2, "D")
table.insert(rooms[3], 2, "D")
table.insert(rooms[5], 2, "B"); ncorrect = ncorrect + 1 -- this line
table.insert(rooms[5], 2, "C")
table.insert(rooms[7], 2, "A")
table.insert(rooms[7], 2, "B")
table.insert(rooms[9], 2, "C")
table.insert(rooms[9], 2, "A")
function printit()
for l = 1, length do io.write(hall[l] or ".") end
io.write("\n")
for d = 1, depth do
for l = 1, length do
if rooms[l] then
io.write(rooms[l][d] or ".")
else
io.write(" ")
end
end
io.write("\n")
end
end
printit()
function addtoroom(rooms, room, char)
local room = rooms[room]
for d = depth, 1, -1 do
if room[d] == nil then
room[d] = char
return
end
end
end
function removefromroom(rooms, i)
local room = rooms[i]
local c, dst, complete = nil, nil, true
for d = depth, 1, -1 do
if room[d] ~= nil then
c, dst = room[d], d
if targets[c] ~= i then complete = false end
end
end
if dst then room[dst] = nil end
return c, dst, complete
end
function pathtoroom(l, c, hall, rooms)
local t = targets[c]
if rooms[t][1] ~= nil then return end
for p = l + sign(t - l), t, sign(t - l) do
if hall[p] ~= nil then return end
end
local room = rooms[t]
for d = depth, 1, -1 do
if room[d] == nil then
return t, math.abs(t - l) + d
elseif room[d] ~= c then
return
end
end
end
local nhall = 0
local minscore = math.huge
-- global: length, depth, hall, rooms, ncorrect, nhall, minscore
-- returns: score
function backtrack(step, score)
if step > 32 then
elseif ncorrect == 16 and score < minscore then
minscore = score
print(minscore)
elseif score > minscore then
else
-- move into rooms
for l = 1, length do
if hall[l] ~= nil then
local c = hall[l]
local room, distance = pathtoroom(l, c, hall, rooms)
if room then
hall[l] = nil
addtoroom(rooms, room, c)
ncorrect = ncorrect + 1
backtrack(step + 1, score + distance * costs[c])
ncorrect = ncorrect - 1
removefromroom(rooms, room)
hall[l] = c
end
end
end
-- remove from rooms
for l, room in pairs(rooms) do
local c, distance, complete = removefromroom(rooms, l)
if c ~= nil then
if not complete then
if targets[c] == l then ncorrect = ncorrect - 1 end
-- left
local t = l - 1
while t >= 1 and hall[t] == nil do
if rooms[t] == nil then
hall[t] = c
backtrack(step + 1, score + (distance + l - t) * costs[c])
hall[t] = nil
end
t = t - 1
end
-- right
local t = l + 1
while t <= length and hall[t] == nil do
if rooms[t] == nil then
hall[t] = c
backtrack(step + 1, score + (distance + t - l) * costs[c])
hall[t] = nil
end
t = t + 1
end
if targets[c] == l then ncorrect = ncorrect + 1 end
end
addtoroom(rooms, l, c)
end
end
end
end
backtrack(0, 0)
print(minscore)