如何检查一组坐标是否与Python中的俄罗斯方块匹配

时间:2018-11-19 11:04:06

标签: python numpy coordinates tetris

我正在处理俄罗斯方块。

用坐标定义零件,其中每个零件都有一个原点块(0,0) 因此,根据您放置原始块的位置,可以将L件定义为[(0,0), (0,1), (0,2), (1,2)][(0,-1), (0,0), (0,1), (1,1)]

我想检查一组坐标A,例如[(50,50), (50,51), (50,52), (51,52)]与给定的俄罗斯方块B的形状匹配。

我目前正在使用numpy从A中的每个值中取出A值之一以到达相对坐标,然后与B比较。A的顺序始终是递增的,但不能保证与A的顺序匹配B的排序。B与其他俄罗斯方块一起存储在列表中,并且在整个程序中,它的原始块将保持不变。下面的这种方法似乎效率低下,没有考虑到B的旋转/反射

def isAinB(A,B):  # A and B are numpy arrays
    for i in range(len(A)):
        matchCoords = A - A[i]
        setM = set([tuple(x) for x in matchCoords])
        setB = set([tuple(x) for x in B])
        if setM == setB:  # Sets are used here because the ordering of M and B are not guarenteed to match
            return True
    return False

是否有一种有效的方法/功能来实现? (如果可能,还要考虑旋转和反射)

1 个答案:

答案 0 :(得分:0)

这是一种处理方法。我们的想法是首先在某个规范坐标中构建一件作品的所有变体集(您可以对每种作品进行一次操作,然后重复使用),然后将给定的一件作品置于相同的规范坐标中并进行比较。

# Rotates a piece by 90 degrees
def rotate_coords(coords):
    return [(y, -x) for x, y in coords]

# Returns a canonical coordinates representation of a piece as a frozen set
def canonical_coords(coords):
    x_min = min(x for x, _ in coords)
    y_min = min(y for _, y in coords)
    return frozenset((y - y_min, x - x_min) for x, y in coords)

# Makes all possible variations of a piece (optionally including reflections)
# as a set of canonical representations
def make_piece_variations(piece, reflections=True):
    variations = {canonical_coords(piece)}
    for i in range(3):
        piece = rotate_coords(piece)
        variations.add(canonical_coords(piece))
    if reflections:
        piece_reflected = [(y, x) for x, y in piece]
        variations.update(make_piece_variations(piece_reflected, False))
    return variations

# Checks if a given piece is in a set of variations
def matches_piece(piece, variations):
    return canonical_coords(piece) in variations

这些是一些测试:

# L-shaped piece
l_piece = [(0, 0), (0, 1), (0, 2), (1, 2)]
l_piece_variations = make_piece_variations(l_piece, reflections=True)

# Same orientation
print(matches_piece([(50, 50), (50, 51), (50, 52), (51, 52)], l_piece_variations))
# True

# Rotated
print(matches_piece([(50, 50), (51, 50), (52, 50), (52, 49)], l_piece_variations))
# True

# Reflected and rotated
print(matches_piece([(50, 50), (49, 50), (48, 50), (48, 49)], l_piece_variations))
# True

# Rotated and different order of coordinates
print(matches_piece([(50, 48), (50, 50), (49, 48), (50, 49)], l_piece_variations))
# True

# Different piece
print(matches_piece([(50, 50), (50, 51), (50, 52), (50, 53)], l_piece_variations))
# False

这不是一个特别聪明的算法,但是它在最小约束下工作。

编辑:由于在您的情况下,您说第一个块和相对顺序将始终相同,因此您可以按如下所示重新定义规范坐标,以使其更加优化(尽管性能差异可能可以忽略不计)并且其使用将受到更多限制):

def canonical_coords(coords):
    return tuple((y - coords[0][0], x - coords[0][1]) for x, y in coords[1:])

第一个坐标将始终为(0,0),因此您可以跳过该坐标并将其用作其余坐标,而不是frozenset,可以将tuple用作坐标。坐标顺序。