154 lines
3.3 KiB
Lua
154 lines
3.3 KiB
Lua
|
#!/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
|
||
|
depth = depth - 2
|
||
|
|
||
|
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]
|
||
|
if room[1] == nil then
|
||
|
if room[2] == nil then
|
||
|
return
|
||
|
else
|
||
|
local c = room[2]
|
||
|
room[2] = nil
|
||
|
return c, 2, targets[c] == i
|
||
|
end
|
||
|
else
|
||
|
local c = room[1]
|
||
|
room[1] = nil
|
||
|
return c, 1, targets[c] == i and targets[room[2]] == i
|
||
|
end
|
||
|
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]
|
||
|
if room[2] == nil and room[1] == nil then
|
||
|
return t, math.abs(t - l) + 2
|
||
|
elseif room[2] == c and room[1] == nil then
|
||
|
return t, math.abs(t - l) + 1
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local nhall = 0
|
||
|
local minscore = math.huge
|
||
|
-- global: length, depth, hall, rooms, ncorrect, nhall, minscore
|
||
|
-- returns: score
|
||
|
function backtrack(step, score)
|
||
|
-- print(step)
|
||
|
-- printit()
|
||
|
if step > 16 then
|
||
|
elseif ncorrect == 8 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)
|