在扫雷中围绕炸弹放置数字:为什么我会将“列表索引超出范围”?

时间:2012-11-16 01:33:46

标签: python matrix minesweeper

我有一个功能,可以将“z”数量的炸弹随机分散在10x10网格中。它看起来像这样(“b”表示炸弹所在的位置。)我需要放置一个数字,表示“0”旁边有多少个炸弹(包括对角线),我不知道该怎么做。

0 0 0 0 0 0 0 0 b 0
b 0 0 b 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 b 0 0 0
0 0 0 b 0 0 0 0 0 0
0 0 b 0 0 0 0 0 0 b
0 0 0 0 0 0 0 b 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 b 0 b 0 0 0 0
0 0 0 0 0 0 0 0 0 0 

from random import*
mat1 = []
mat2 = []

def makemat(x):
    for y in range(x):
        list1 = []
        list2 = []
        for z in range(x):
            list1.append(0)
            list2.append("-")
        mat1.append(list1)
        mat2.append(list2)
makemat(5)



def printmat(mat):
    for a in range(len(mat)):
        for b in range(len(mat)):
            print(str(mat[a][b]) + "\t",end="")
        print("\t")



def addmines(z):
    count = 0
    while (count < z):
        x = randrange(0,len(mat1))       
        y = randrange(0,len(mat1))      
        if mat1[y][x] == "b":
            count -= 1
        else:
            mat1[y][x] = "b"
        count += 1
    printmat(mat1)
addmines(10)

这是我尝试放置数字的功能:

def addscores():
    for x in range(len(mat1)):
        for y in range(len(mat1)):
            if mat1[y][x] != "b":
                if mat1[y+1][x] == "b":
                    mat1[y][x] = 1 
                if mat1[y-1][x] == "b":
                    mat1[y][x] = 1                  #...ETC
            else:
                mat1[y][x] == "b"
addscores()

我不断收到错误列表索引超出范围。我该如何解决这个问题?

4 个答案:

答案 0 :(得分:0)

变化

if mat1[y+1][x] == "b":

if safeEquals(mat1, y+1, x, "b"):

并将safeEquals定义为

def safeEquals(mat, y, x, value):
    try:
        return mat1[y][x] == "b"
    except IndexError as e:
        return False

如果您在地图位置之外编制索引,这实质上允许您提供默认行为。

PS条件后执行的代码:

mat1[y][x] = 1 

应该是

mat1[y][x] += 1 

因为相邻炸弹的存在会使炸弹计数器增加(否则3会如何出现在地图上_

答案 1 :(得分:0)

让我们说(x, y) = (9, 9),你得到IndexError,因为你这样做:

if mat1[y+1][x] == "b":

尝试访问索引mat1[10],该索引不存在,因为您的列表只有10个元素长。

另外,让我们说(x, y) = (0, 0)。然后当你这样做:

if mat1[y-1][x] == "b":

您可以访问索引mat[-1],这相当于mat[9]。我很确定这不是你想要的。

有两种简单的方法可以解决这个问题:

1)包含一组额外的if语句,以确保您不会尝试访问列表边界之外的列表元素:

变化:

            if mat1[y+1][x] == "b":
                mat1[y][x] = 1 
            if mat1[y-1][x] == "b":
                mat1[y][x] = 1      

要:

            #parentheses in if statements added for clarity
            if (y < len(mat1) - 1) and (mat1[y+1][x] == "b"):
                mat1[y][x] = 1 
            if (y > 0) and (mat1[y-1][x] == "b"):
                mat1[y][x] = 1    

2)这是我喜欢的方法。在数组周围添加一层“填充”。首次创建阵列时,请执行以下操作:

WIDTH = 10
HEIGHT = 10

myMap = [[0 for i in range(WIDTH + 2)] for j in range(HEIGHT + 2)]

然后,当您访问数组中的元素时,只需确保从1开始索引,而不是0:

#do this
firstElement = myMap[1][1]

#not this
firstElement = mayMap[0][0]

#do this
for i in range(1, len(myMap) - 1): pass

#not this
for i in range(len(myMap)): pass  

答案 2 :(得分:0)

避免索引错误的一种简单方法是使用defaultdict来保留mat1mat2。作为奖励,代码更短:)

from random import randrange
from collections import defaultdict
mat1 = defaultdict(int)
mat2 = defaultdict(lambda:"-")
size = 5

def printmat(mat):
    for a in range(size):
        print("\t".join(str(mat[a, b]) for b in range(size)))


def addmines(count):
    while (count):
        x = randrange(0,size)       
        y = randrange(0,size)      
        if mat1[y, x] != "b":
            mat1[y, x] = "b"
            count -= 1
    printmat(mat1)
addmines(10)

def addscores():
    for x in range(size):
        for y in range(size):
            if mat1[y, x] != "b":
                if mat1[y+1, x] == "b":
                    mat1[y, x] = 1                  # should be +=
                if mat1[y-1, x] == "b":
                    mat1[y, x] = 1                  #...ETC
            else:
                mat1[y, x] == "b"
addscores()

答案 3 :(得分:-1)

如果y在范围内(len(mat1))则y + 1不是......