查找多米诺骨牌订单的有效方法

时间:2018-08-29 05:29:27

标签: python algorithm

我有一个小小的多米诺骨牌游戏,它的工作方式是这样的:我得到了N*N 4格砖,我需要对其进行排序,以便每两个相邻的图块都具有相同的编号。磁贴可以旋转。例如,这是我的2 * 2木板:

a,b,c,d = [1,2,3,4], [7,9,6,2], [6,8,8,5], [3,5,0,0]

可以通过以下方式将其可视化:

print(print_2_tiles(a,b,'a','b'))
print(print_2_tiles(d,c,'d','c'))

##############
#**1**##**7**#
#4*A*2##2*B*9#
#**3**##**6**#
##############
##############
#**3**##**6**#
#0*D*5##5*C*8#
#**0**##**8**#
##############

可以看出,“赢得”此板的唯一方法是我订购磁贴的方法,因为<a,b>仅通过2连接,<a,d>仅通过3连接,依此类推。上的<a,c>,<b,d>根本没有连接。任何瓷砖的旋转或移动都不会获得“胜利”。

我将函数编写为:

  1. 在任何给定2个图块之间查找连接
  2. 弄清楚连接给定2个图块需要多少旋转
  3. 检查所有可能性并找到正确的顺序

但是,这只是16 * 12 * 8选项的简单情况,由于存在唯一的连接器(例如,连接<a,c>的'2'在其他图块中不存在),因此我可以排除很多选项。如果我得到更大的面板(更大的字母也可能使事情复杂化... ),例如5 * 5,则选项的数量将为100 * 96 * 92 ...并且蛮力将不切。

我如何才能有效地找到正确的订单(保证董事会有一个正确的订单)?

这是我的努力:

import numpy as np
from itertools import combinations, product


# returns list of [<connector element>, <indices of element in a>, <indices of element in b>]
def find_connections(a,b):
    intersected_elem = np.array(list(set(a).intersection(b)))

    possible_connections = []

    for val in intersected_elem:
        x = list(np.where(np.array(a) == val)[0])
        y = list(np.where(np.array(b) == val)[0])
        possible_connections.append([val,x,y])

    return possible_connections

def str_tile(t, name):
    template = '''#######
#**{}**#
#{}*{}*{}#
#**{}**#
#######'''

    up,right,down,left = t

    return template.format(up,left,name.upper(),right,down)

def print_2_tiles(a,b, name_a, name_b):

    res = ''

    for line in zip(str_tile(a,name_a).splitlines(), str_tile(b,name_b).splitlines()):
        res += ''.join(line)
        res += '\n'

    return res[:-1]


def find_final_connections(tiles_ls):
    tiles_combinations = list(combinations(tiles_ls, 2))

    a_idx,b_idx = 0,1
    final_connections = []

    for comb in tiles_combinations:
        connections = find_connections(comb[0], comb[1])

        print('({},{})'.format(a_idx,b_idx), connections, end='\t')

        if len(connections):
            print('this meants {},{} are connected via {} in directions {},{}'.format(a_idx,b_idx, connections[0][0], connections[0][1][0], connections[0][2][0]))
            final_connections.append((a_idx,b_idx))
        else:
            print()

        # is there a neater way, using enumerate on itertools.combinations?
        b_idx += 1
        if b_idx == len(tiles_ls):
            a_idx += 1
            b_idx = a_idx + 1   


    print(final_connections)


a,b,c,d = [1,2,3,4], [7,9,6,2], [6,8,8,5], [3,5,0,0]
tiles_ls = [a,b,c,d]
find_final_connections(tiles_ls) # returns a 4-elem list -> success

print('#'*30)

a,b,c,d = [1,2,3,4], [7,9,6,2], [6,8,8,5], [0,5,0,0]
tiles_ls = [a,b,c,d]
find_final_connections(tiles_ls) # returns a 3-elem list -> fail

1 个答案:

答案 0 :(得分:0)

是否确定暴力破解无法做到?

我会尝试一种系统的解决方案,您依次选择每个多米诺骨牌并将其放在左上角,尝试所有四个旋转。然后选择另一个多米诺骨牌并将其放置在第二个位置,尝试所有四个旋转,并检查是否与第一个匹配。

依此类推,在任何阶段,您都可以从其余的多米诺骨牌中挑选一个多米诺骨牌,尝试四轮旋转并检查与已知邻居的兼容性。

最好将其写为递归过程。