world
是一个二维数组,填充有0(AIR
)或1(BLOCK
)。我们的任务是将world
拆分为不重叠的矩形,以便将这些矩形粘合在一起时,可以得到原始的world
。矩形的数量应最小化(如果这会增加很多的计算时间,就不必最小,只要足够小即可),并且矩形应看起来更像正方形而不是条纹(边长的比例应为比1更接近0)。
我能够提出一种算法,但是它有一些问题。
center_of_mass
函数返回矩形区域的质心。如果该区域中没有任何块,则返回None
。
def center_of_mass(grid, x1,y1, x2,y2):
cx = 0
cy = 0
mass = 0
for x in range(x1,x2+1):
for y in range(y1,y2+1):
if 0<=x<w and 0<=y<h and grid[x][y] == BLOCK:
cx += x
cy += y
mass += 1
if mass == 0:
return None
else:
cx = round(cx/mass)
cy = round(cy/mass)
return cx, cy
scom
函数在矩形区域中找到第一个suitable center of mass
(SCoM):
if world[center_of_mass] is filled with a block, return coordinates from center_of_mass
else{
split the grid into 4 rectangles with the division point at center_of_mass
foreach rect in split_rectangles{
if scom of rect != None{
return center_of_mass(rect)
}
}
if wasn't able to find a SCoM or the region is 0-sized, return None
}
def scom(grid, x1,y1, x2,y2):
p = center_of_mass(grid, x1,y1, x2,y2)
if p is None:
return None
else:
cx, cy = p
if grid[cx][cy] != BLOCK:
if abs(x1-x2)==0 and abs(y1-y2)==0:
return None
else:
px = x1 + (x2-x1)//2
py = y1 + (x2-x1)//2
r = [(x1,y1,px,py),(px+1,y1,x2,py),
(px+1,py+1,x2,y2),(x1,py+1,px,y2)]
for rect in r:
x = scom(grid, *rect)
if x is not None:
return x
else:
return cx, cy
下一个函数stretch
采用2d网格grid
和一个矩形,该矩形适合某些块,并尝试在所有4个方向上扩展该矩形,直到不可能。然后返回展开的矩形。
def stretch(grid, x1, y1, x2, y2):
can_grow = True
while can_grow:
can_grow = False
for vec in ((1,0),(0,1),(-1,0),(0,-1)):
for x,y in extension(x1, y1, x2, y2, vec):
if (x>=w or x<0 or y>=h or y<0)\
or grid[x][y] == AIR or grid[x][y]>BLOCK:
break
else:
x1,y1,x2,y2 = add_to_rect(x1,y1,x2,y2, vec)
can_grow = True
return (x1, y1, x2, y2)
apply_rect
函数采用一个grid
和一个rect
角,并用给定的数字替换给定矩形内的网格中的所有内容。数字不同,因为我想稍后可视化该划分。
def apply_rect(grid, rect, n=MARKED):
for x,y in all_points(*rect):
grid[x][y] = n
算法的主要部分是:
基本上,我搜索一个合适的重心,以使矩形具有很多可以生长的区域,从而使它们最终更像正方形。相反,如果我只是扫描网格以找到其中有一个块的第一个单元,那么我将得到很多条纹(我已经检查过了。令人惊讶的是,矩形的数量通常几乎是相同的)。>
number_of_rects = 0
found = True
while found:
found = True
p = scom(world, 0,0, w-1,h-1)
if p is None:
found = False
else:
x,y = p
if found:
rect = stretch(world, x,y, x,y)
number_of_rects += 1
apply_rect(world, rect, number_of_rects+3)
这是输入:
这是输出:
这几乎是我所需要的。但是,有两个问题:
2。左角由像素大小的正方形而不是单个条纹组成。我该如何解决?显而易见的解决方案是扫描最左边的列并将所有像素收集到不同的矩形中。但是,如果我将游戏世界划分为较小的块(例如32x32甚至更小的块),然后将这些块划分为矩形,则左侧的方形意大利面条可能会破坏有效的划分。 —已修复。 / p>