2016-01-19 7 views
0

После работы на моем коде на некоторое время, оптимизируя наиболее очевидные вещи, я привел в этом:Lua код первопрохождения нуждается в оптимизации

function FindPath(start, finish, path) 
    --Define a table to hold the paths 
    local paths = {} 
    --Make a default argument 
    path = path or {start} 
    --Loop through connected nodes 
    for i,v in ipairs(start:GetConnectedParts()) do 
     --Determine if backtracking 
     local loop = false 
     for i,vv in ipairs(path) do 
      if v == vv then 
       loop = true 
      end 
     end 
     if not loop then 
      --Make a path clone 
      local npath = {unpack(path)} 
      npath[#npath+1] = v 
      if v == finish then 
       --If we reach the end add the path 
       return npath 
      else 
       --Otherwise add the shortest part extending from this node 
       paths[#paths+1] = FindPath(v, finish, npath) --NOTED HERE 
      end 
     end 
    end 
    --Find and return the shortest path 
    if #paths > 0 then 
     local lengths = {} 
     for i,v in ipairs(paths) do 
      lengths[#lengths+1] = #v 
     end 
     local least = math.min(unpack(lengths)) 
     for i,v in ipairs(paths) do 
      if #v == least then 
       return v 
      end 
     end 
    end 
end 

Проблема в том, отметил линия получает какую-то игру сценария (я считаю, это из-за массовой рекурсии без уступки). Я также чувствую, что как только проблема будет исправлена, она, вероятно, будет довольно медленной даже в масштабе платы pacman. Есть ли способ, которым я могу его оптимизировать, или, возможно, лучший метод, с которым я могу смотреть в подобном?

ОБНОВЛЕНИЕ: Я, наконец, решил уничтожить мой алгоритм из-за неэффективности и реализовал алгоритм Dijkstra для поиска пути. Для любого, кто интересуется исходным кодом, можно найти здесь: http://pastebin.com/Xivf9mwv

ответ

1

Вы знаете, что Roblox предоставляет вам PathfindingService? Он использует C-side A * pathing для вычисления довольно быстро. Я бы рекомендовал использовать его

http://wiki.roblox.com/index.php?title=API:Class/PathfindingService

+0

Мне это известно, и я часто его использую, но я работаю над кодом для друга, которому нужен ИИ, (PathfindingService заставит их пройтись по дорогам) – warspyking

+0

Тогда у нас есть код FindPath? Я подозреваю, что это может быть эта функция, вызывающая замедление. – Henry

+0

У вас есть это ... – warspyking

0

Попробуйте перестроить свой алгоритм, чтобы использовать хвостовые вызовы. Это отличный механизм, доступный в Lua.

Хвост вызова - это тип рекурсии, в которой ваша функция возвращает вызов функции как последнее, что он делает. У Lua есть правильная реализация хвостовых вызовов, и она будет одевать эту рекурсию как «перейти» под сцену, так что ваш стек никогда не ударит.

Передача «путей», как один из аргументов FindPath, может помочь в этом.

+0

Было бы неплохо, если бы roblox использовал Lua 5.2, но, увы, он использовал Lua 5.1 – warspyking

+0

Этот код предназначен для ROBLOX, где хвосты фактически отключены. – EinsteinK

+0

@EinsteinK Они не * отключены *, а ** не реализованы **. ROBLOX использует модифицированную версию Lua 5.1, но Lua только представила tailcalls в 5.2. – warspyking

-1

Я видел вашу правку о вынужденном код, но только, чтобы помочь другим, спотыкаясь на этот вопрос:

  • ipairs медленнее, чем пар, что медленнее, чем Численном -loop. Если производительность имеет значение, никогда не используйте ipairs, но используйте для i = 1, # tab loop
  • Если вы хотите клонировать таблицу, используйте цикл for. Иногда у вас есть, чтобы использовать распаковку (возврат динамического количества задних нолей), но это не такой случай. Unpack также является медленной функцией.

Замена ipairs с парами или числовыми для петель и с помощью петли вместо распаковывать увеличит производительность много.

Если вы хотите, чтобы получить наименьшее значение в таблице, используйте этот код:

local lowestValue = values[1] 
for k,v in pairs(values) do 
    if v < lowestValue then 
     lowestValue = k,v 
    end 
end 

Это может быть переписан для вашего примера путь, как так:

local least = #path[1] 
for k,v in pairs(path) do 
    if #v < least then 
     least = v 
    end 
end 

Я должен признать, , вы очень изобретательны. Не многие люди будут использовать математику.min (unpack (tab)) (не считая того, что это плохо)

+0

ipairs FASTER, чем пары, потому что он выполняет только итерацию над частью ARRAY, а не хешем. Не знаю, где у вас пара идей была быстрее. – warspyking

+0

И зачем распаковывать таблицу, которая будет использоваться для math.min ** bad ** unpack для распаковки таблицы. Использование его для распаковки в качестве аргументов для math.min кажется для меня довольно логичным. – warspyking

+0

И я проверил ваш аргумент для распаковки VS для распаковки. Я клонировал массив с 7999 пунктами, 1000 раз и выводил красный, сколько времени они занимали. Цикл for занял 9 секунд, тогда как распаковка заняла 2. (Конечно, мой тест был в Lua 5.2, но, конечно же, тест дал бы о тех же результатах на roblox) – warspyking

Смежные вопросы