【问题标题】:Finding an appropriate rectange in a 2-d array [closed]在二维数组中找到合适的矩形[关闭]
【发布时间】:2013-07-28 07:54:25
【问题描述】:

好吧,这个标题不太合适,请继续阅读(我找不到更好的)。

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

我正在制作一个横向卷轴游戏,在其中我会在飞行中生成障碍物。我遇到的麻烦是弄清楚如何产生障碍。 o_O
我有某种逻辑,但是我在弄清楚整个逻辑时遇到了麻烦。

所以从实现的角度来看,这是我的问题:
我有一个Surface,其中我放了一些Elements,它们都是矩形。
可以这样想:

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:我在这里和 Programmers 上都问过这个问题,因为我认为这两个网站都属于主题。

【问题讨论】:

  • 请不要交叉发帖。
  • 这个问题似乎是题外话,因为它是关于算法,而不是现有代码,并且已交叉发布到programmers.stackexchange.com/questions/206298/…
  • @MartijnPieters 我不明白为什么这是题外话,但是是的,不应该交叉发布.. :|

标签: python algorithm logic


【解决方案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, j) 的任何其他位置,从 (i+1, y) 开始下一次检查) 和 (x, j+1)。

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

【讨论】:

  • 哇!这比我预期的要快(并且比我需要的要慢),但是是否可以对其进行更多优化?它花了大约 0.9 秒,对于 7x7 网格,另一个结构是 24x32,所以它显着变慢.. 给我 1 FPS。 :(
  • 我添加了另一个优化,这样它就不会尝试检查同一个位置两次,但我不确定它是否有足够的帮助。除非您在循环中调用它,否则不确定您的时间如何正确,即使在 24x32 网格的最坏情况下,这对我来说也不会超过几毫秒。
  • 您是否为ab 的不同参数值重复调用此函数?
  • 是的..好吧,它们是随机数..
  • 好的..(这很尴尬)对不起,0.9是由于while循环,条件有误......对不起..谢谢..这很好..
【解决方案2】:

您可以将曲面存储在矩阵 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;     

【讨论】:

    【解决方案3】:

    这是一个蛮力搜索,它考虑了矩形 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)]
    >>> 
    

    【讨论】:

    • 这个方法比FJ的慢很多,慢36.45倍...
    • 我知道它很慢(蛮力),尽管您的 OP 并未表明您专门寻找性能。这只是我能想到的最简单的 impl。不过我会考虑一个更快的。
    猜你喜欢
    • 1970-01-01
    • 2012-07-04
    • 1970-01-01
    • 2016-06-09
    • 2021-06-26
    • 2011-04-13
    • 1970-01-01
    • 2012-10-11
    • 1970-01-01
    相关资源
    最近更新 更多