在二维数组中查找适当的矩形

时间:2013-07-28 07:54:25

标签: python algorithm logic

嗯,标题不太合适,请继续阅读(我无法获得更好的标题)。

注意:使用Python 2.7,但算法也会有所帮助。

我制作了一个侧卷轴游戏,我在飞行中产生障碍物。我遇到的麻烦是弄清楚如何产生障碍。 O_O
我有一种逻辑,但是我在弄清楚整个逻辑时遇到了麻烦。

从实施的角度来看,这是我的问题:
我有一个Surface,其中我放了一些Element s,它们都是矩形 把它想象成:

0 0 0 0 0 0 0
0 0 0 0 1 1 0
0 0 0 0 1 1 0
0 0 0 0 1 1 0
0 0 0 0 0 0 0
0 1 1 0 0 1 1
0 0 0 0 0 1 1

与上述结构一样,如何确定是否可以添加axb矩形而不重叠另一个矩形(1s),以及所有矩形。此外,通过与所有其他对象保持x个元素(甚至是对角线)的距离,这意味着整个矩形是(x + 3,x + 4)。像x=1, a=3, b=4这样的东西,只有一种可能的安排:
(2s代表新对象)

2 2 2 0 0 0 0
2 2 2 0 1 1 0
2 2 2 0 1 1 0
2 2 2 0 1 1 0
0 0 0 0 0 0 0
0 1 1 0 0 1 1
0 0 0 0 0 1 1

基本上,我需要找到所有的点,方括号ab的矩形可以包含它,例如,左上角。如何实现这一目标?

注意:打开更好的想法,以便立即产生障碍!

PS:我在这里以及程序员问过这个问题,因为我认为它在两个网站上都有主题。

3 个答案:

答案 0 :(得分:1)

以下应该可以很好地运作:

def find_valid_locations(grid, z, a, b):
    check = [(0, 0, 0, 0)]
    w = z + b
    h = z + a
    while check:
        x, y, ox, oy = check.pop()
        if x + w >= len(grid) or y + h >= len(grid[0]):
            continue
        for i, row in enumerate(grid[x+ox:x+w+1], x+ox):
            for j, val in enumerate(row[y+oy:y+h+1], y+oy):
                if val:
                    break
            else:
                continue
            check.append((x, j+1, 0, 0))
            if y == 0:
                check.extend((ii, j+1, 0, 0) for ii in range(x+1, i+1))
                check.append((i+1, y, 0, 0))
            break
        else:
            yield (x, y)
            check.append((x, y+1, 0, h-1))
            if y == 0:
                check.append((x+1, y, w-1, 0))
            continue

此处的强力方法是检查每个潜在矩形位置中的所有位置,并仅返回矩形未遇到非零位置的位置。这基本上就是我们在这里所做的,具有以下优化:

  • 如果我们找到了一个有效的位置(x,y),我们可以轻松检查位置(x + 1,y)和(x,y + 1),只需通过移动它来检查添加到矩形的新位置向下或向右。
  • 如果我们在检查位置(x,y)时在位置(i,j)遇到障碍物,我们可以通过在(i + 1,y)开始下一次检查来跳过检查包括(i,j)的任何其他位置)和(x,j + 1)。

请注意,我将参数x重命名为z,以便我可以在代码中使用x作为行索引。

答案 1 :(得分:0)

您可以将曲面存储在矩阵M中,然后遍历矩阵以找到新矩形R的左上角的位置:

for all rows of matrix M
    for all columns of matrix M
       variable empty = 0 
       for all numbers from 1 to a
            for all numbers from 1 to b
                empty = empty + M(row + a, col + b)                    
       if empty == 0
           insert R(row,col) //insert R with top-left corner at M(row,col)
           break;     

答案 2 :(得分:0)

这是一个强力搜索,它考虑了一个矩形a,b的所有可能位置,其中边界c位于一个二维Python列表(列表列表)的网格中。

在调用find_placements之前,

isvalid会将边框宽度和边框高度相加。这种方式isvalid不需要考虑边界的任何内容。

我使用变量a, b, c作为宽度,高度,边框,这样它们就不会混淆坐标,这些坐标通常是x, y, z之类的东西。 gxgy是网格x和网格y的缩写。

一个差异在于,使用以这种方式表示网格的二维列表,使用grid[y][x]而不是grid[x][y]来访问单元格。其他一切都非常直接。

def find_placements(grid, a, b, c):
    """
    Return [(x, y), ...] for all valid placements in the grid
    of rectangle a x b with border c.
    """
    result = []
    for gx in xrange(len(grid[0]) - (a + c)):
        for gy in xrange(len(grid) - (b + c)):
            if isvalid(grid, (a + c), (b + c), gx, gy):
                result.append((gx, gy))
    return result


def isvalid(grid, a, b, x, y):
    """
    Return True if rect a, b fits at pos x, y
    without overlapping.
    """
    for gx in xrange(x + a):
        for gy in xrange(y + b):
            if grid[gy][gx]:
                return False
    return True

>>> grid =[
    [0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 0, 0, 0, 0],
    [0, 1, 1, 0, 0, 1, 1],
    [0, 0, 0, 0, 0, 1, 1]
]
>>> find_placements(grid, 3, 4, 1)
[(0, 0)]
>>>