我正在使用一个使用tilemap的游戏。地图上的正方形可以是墙,也可以是空的。我尝试开发的算法应该在地图上取一个点,并返回从该点可以到达的单元格数(等于包含该点的扇区区域)。
让执行算法的函数以二维数组的形式采用x坐标,y坐标和地图。
function sectorArea(x_coord,y_coord,map) { ... }
假设地图看起来像这样(其中1'代表墙壁):
map = [0,0,1,0,0,0],
[0,0,1,0,0,0],
[1,1,1,0,0,0],
[0,0,0,0,0,0]
然后sectorArea(0,0,map) == 4
和sectorArea(4,0,map) == 15
。
我天真的实现是递归的。目标单元被传递给go
函数,然后该函数在任何相邻的空单元上进行递归 - 最终遍布扇区中的所有空单元。它运行得太慢并且很快达到了调用堆栈限制:
function sectorArea(x_coord,y_coord,map) {
# First convert the map into an array of objects of the form:
# { value: 0 or 1,
# visited: false }
objMap = convertMap(map);
# The recursive function:
function go(x,y) {
if ( outOfBounds(x) || outOfBounds(y) ||
objMap[y][x].value == 1 || objMap[y][x].visited )
return 0;
else
objMap[y][x].visited = true;
return 1 + go(x+1,y) + go(x-1,y) + go(x,y+1) + go(x,y-1);
}
return go(x_coord,y_coord);
}
有人能建议更好的算法吗?如果速度是主要问题,那么非确定性解决方案实际上会很好,因为速度是主要问题(在单个节拍期间,算法可以在不同点上调用3到4次)。
答案 0 :(得分:1)
也许你可以加速算法本身。 Wikipedia表明扫描线方法是有效的。
对于重复的调用:您可以缓存结果,这样您就不必每次都再次运行区域计算。
一种方法可能是在瓷砖旁边保留整数的区域图。这表示几个区域,其中特殊值-1例如表示没有区域。 (此区域地图也可用作visited
属性。)除此之外,请保留(短)区域数组及其区域。
在上面的示例中:
当您计算(0, 0)
的面积时,您将为西北角的四个图块指定0。您还可以将区域4附加到区域阵列。
当您计算(0, 1)
的区域时,您会注意到该坐标的区域地图的值为零,而不是-1。这意味着该区域已经计算好了。
当您计算(4, 4)
的面积时,您会在区域地图中找到-1。这意味着该地区尚未计算。这样做,用1标记区域并将新区域15附加到区域数组。
我不知道董事会改变的频率。必须重新计算区域时,将区域映射清空并清空阵列列表。
区域地图仅创建一次,不会为每个刻度重新创建。 (当经常重新创建objMap
而不是被覆盖时,我可以将此视为代码中的潜在瓶颈。)