使用列表在Python矩阵中查找对角线

时间:2018-11-21 21:48:31

标签: python

我正在尝试对游戏connect-4进行编码,而我的代码中有一部分试图在7x6矩阵中找到对角线,该对角线是连续4个或连续4个2s。 我的这部分代码无法正常工作,我尝试了所有可能的方法。有时它会检测到对角线为4 1s或4 2s的对角线。我创建了将7个零列表放置在6个零列表的每个位置的矩阵。我正在尝试仅使用列表函数来执行此操作,但是我无法使用numpy库或类似库。 好的,在代码的这一部分中,我试图查找在矩阵的每个对角线中是否连续有4个零。 PD:我只是想找到从左到右的ATM对角线。感谢您的帮助,因为英语不是我的主要语言,所以我尽力解释了我的问题。 这是我的代码:

import random
llista = [0]*6 #when i say llista y mean matrix
for i in range(6):
    llista[i]=[0]*7

#Here i fill the 7*6 matrix of 0s 1s and 2s randomly so i can see if it works.
for i in range(30):
    x=random.randrange(-1,-7,-1)
    y=random.randrange(0,7,1)
    llista[x][y]=1
for i in range(30):
    x=random.randrange(-1,-7,-1)
    y=random.randrange(0,7,1)
    llista[x][y]=2
#This 2 loops here are too see if it is possible to have a diagonal in the matrece because if you want a diagonal u need at least a one or 2 in the center, the problem is not here.
for i in range(-1,-7,-1):
    possible = False
    if llista[i][3]==1:
        possible = True
        break

for i in range(7):
    possible2 = False
    if llista[-4][i]==1 or llista[-4][i]==1:
        possible2=True
        break

if possible==True and possible2==True:
#The problem starts here. This first loop i use it too find the diagonals that go from left to right. I want to find diagonals of 4 1s or 4 2s.
for i in range(len(llista)-3):
    for j in range(len(llista[i])-3):
        #This if is too see if we have four 1 or 2 togheter in the list, if we have them it prints the sentence below.
        if (llista[i][j]==1 and llista[i+1][j+1]==1 and llista[i+2][j+2]==1 and llista[i+3][j+3]==1)  or (llista[i][j]==2 and llista[i+1][j+1]==2 and llista[i+2][j+2]==2 and llista[i+3][j+3]==2 ):
            print("There is at least one left to right diagonal")

#This loop is the same than the last one but to find diagonals from right to left (a 4 diagonal made of 1s or 2s)
    for i in range(len(llista)):
        for j in range(len(llista[i])):
            if i-3<0 and j-3<0:
                if (llista[i][j]==1 and llista[i-1][j-1]==1 and llista[i-2][j-2]==1 and llista[i-3][j-3]==1)  or (llista[i][j]==2 and llista[i-1][j-1]==2 and llista[i-2][j-2]==2 and llista[i-3][j-3]==2 ):
                   print("There is at least one right to left diagonal")

#Here i print the matrix
for i in range(6):
    print(llista[i])
#So this program should say if there is at least one left to right diagonal 

或从右到左对角线。      #我不想使用尚未被使用的功能,并且我不想做另一种方式,因为我必须理解这种方式。谢谢

3 个答案:

答案 0 :(得分:0)

由于解析条件语句的方式,也许您没有得到正确的答案。 你应该有

if cond1 or cond2:
    # do something

,条件放在括号()中。目前,括号中仅包含您的第二个条件。 请尝试以下操作:

if (matrix[i][j]==1 and matrix[i+1][j+1]==1 and matrix[i+2][j+2]==1 and matrix[i+3][j+3]==1)  or (matrix[i][j]==2 and matrix[i+1][j+1]==2 and matrix[i+2][j+2]==2 and matrix[i+3][j+3]==2 ):
    print("There is at least one left to right diagonal")

答案 1 :(得分:0)

您可以考虑使用numpy解决此问题。这里有一些代码可以帮助您入门。

import numpy as np
from itertools import groupby

def check_diagonals(matrix):
    for offset in range(-2, 4):
        diag = matrix.diagonal(offset=offset)
        if max([sum(1 for _ in g) for k, g in  groupby(diag)]) >= 4:
            return True, k
    return False, None

# random test matrix
matrix = np.random.randint(0, 3, 6 * 7)
matrix = matrix.reshape(6,7)

# left to right check
resp_tuple = check_diagonals(matrix)
if resp_tuple[0]:
    print("There is at least one left to right diagonal: {}'s'".format(resp_tuple[1]))
else:
    # right to left
    resp_tuple = check_diagonals(np.fliplr(matrix))
    if resp_tuple[0]:
        print("There is at least one right to left diagonal:     {}'s'".format(resp_tuple[1]))
    else:
        # No diagonals
        print('No diagonals')

答案 2 :(得分:0)

如果您考虑“从右到左”循环的逻辑,实际上您实际上是在执行与“从左到右”循环相反的顺序。要真正获得“从右到左”的传递权,您必须使ij索引朝不同的方向移动。

因此,本节中的条件语句应如下所示:

if i-3>=0 and j+3<7:
    if (llista[i][j]==1 and llista[i-1][j+1]==1 and llista[i-2][j+2]==1 and llista[i-3][j+3]==1)  or (llista[i][j]==2 and llista[i-1][j+1]==2 and llista[i-2][j+2]==2 and llista[i-3][j+3]==2 ):
        print("There is at least one right to left diagonal")

如AResem所示,通过导入numpyitertools之类的库,您可以使用大量的优化方法。出于以下原因,该答案并不完全正确。

当您说return True, k时,您并没有对k的值进行任何控制,因为它在上面的列表推导中使用过,并且仅具有迭代的最后一项的值。因此,当您的函数找到对角线时,它将在大约三分之二的时间报告错误的数字。

以下是经过编辑的函数,可以提供正确的结果:

def check_diagonals(matrix):
    for offset in range(-2, 4):
        diag = matrix.diagonal(offset=offset)

        # Here you can create a tuple of numbers with the number of times they are repeated. 
        # This allows you to keep your k and g values associated.
        repeat_groups = [(k, sum(1 for _ in g)) for k, g in  groupby(diag)]

        # By using the built-in max function with the 'key' keyword, you can find 
        # the maximum number of repeats and return the number associated with that.
        num, max_repeats = max(repeat_groups, key=lambda item: item[1])
        if max_repeats >= 4:
            return True, num
    return False, None

如果在添加了print语句的情况下运行此功能,则可以得到如下输出:

Matrix: 
[[1 0 2 2 1 0 1]
 [0 2 0 2 1 1 1]
 [2 2 0 0 0 0 1]
 [0 0 2 2 0 2 2]
 [2 1 1 1 1 1 0]
 [2 2 0 2 1 0 2]]

offset -2
diag [2 0 1 2]
repeat_groups [(2, 1), (0, 1), (1, 1), (2, 1)]
num, max_repeats 2 1

offset -1
diag [0 2 2 1 1]
repeat_groups [(0, 1), (2, 2), (1, 2)]
num, max_repeats 2 2

offset 0
diag [1 2 0 2 1 0]
repeat_groups [(1, 1), (2, 1), (0, 1), (2, 1), (1, 1), (0, 1)]
num, max_repeats 1 1

offset 1
diag [0 0 0 0 1 2]
repeat_groups [(0, 4), (1, 1), (2, 1)]
num, max_repeats 0 4
(True, 0)
There is at least one left to right diagonal: 0's' # Correct!

如果您想忽略零的对角线,则可以轻松添加一个额外条件,例如

if max_repeats >= 4 and num != 0:
    return True, num

如果需要,您可以尝试不使用numpy而重新创建它。