#!/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)