158 lines
3.5 KiB
Lua
Executable File
158 lines
3.5 KiB
Lua
Executable File
#!/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)
|