嗨,所以我正在做扫雷游戏,而网格生成部分让我有些困惑。到目前为止,这是我的代码:
from random import randint
import pygame
def MineGen():
mineamount = 100
grid_across = 40
grid_up = 25
mine_list = []
my2dthatlist = []
numacoss = 0
for i in range (mineamount):
numacoss = randint(1,40)
my2dthatlist.append(numacoss)
numup = randint(1,25)
my2dthatlist.append(numup)
mine_list.append(my2dthatlist)
my2dthatlist = []
return mine_list
def GridGen():
grid_across = 40
grid_up = 25
GRIDD = [[0]* grid_across for i in range(grid_up)]
return GRIDD
def MineGrid(GridOutMine, mine_list):
mineplace = 0
placeX = 0
placeY = 0
for i in range(100):
mineplace = mine_list[i]
placeX = mineplace[0]
placeY = mineplace[1]
GridOutMine[placeX][placeY] = 1
print(GridOutMine)
mine_list = MineGen()
GridOutMine = GridGen()
MineGrid(GridOutMine, mine_list)
我的问题是我的列表索引超出了范围
GridOutMine[placeX][placeY] = 1
部分。我真的不知道为什么会这样。如果您能为我提供一些帮助,或者只是对我的代码发表一些一般性评论,我将非常感谢。
答案 0 :(得分:2)
这是因为,与range
不同,random.randint
在指定范围内(包括范围内)输出数字。也就是说,randint(1, 25)
可能会输出25,这对于只有25个元素(因为最后一个索引是24)的列表来说不是有效索引。
在MineGen
中,您需要将randint(1, 25)
更改为randint(1, 25-1)
或randint(1, 24)
,对于randint(1, 40)
,也必须将其更改为randint(1, 39)
。我实际上会建议randint(0, 24)
和(0, 39)
,但我不知道这是否是故意的。
关于此代码,还有很多其他事情可以/应该加以改进,但是我建议您在CodeReview上进行此类输入,而不是在代码运行后在这里进行输入(它们不会修复损坏的代码)。
编辑:
此外,您正在以错误的顺序索引网格。这是一列(25个长)的行(40个长),因此您需要先在Y维度中为其索引,然后在X中:GridOutMine[placeY][placeX] = 1
答案 1 :(得分:1)
如果您试图为游戏构建网格并希望在用户可以与之交互的GUI中显示按钮,则可能需要从以下代码开始,作为其余代码的基本框架写作。
import tkinter
import functools
class MineSweep(tkinter.Frame):
@classmethod
def main(cls, width, height):
root = tkinter.Tk()
window = cls(root, width, height)
root.mainloop()
def __init__(self, master, width, height):
super().__init__(master)
self.__width = width
self.__height = height
self.__build_buttons()
self.grid()
def __build_buttons(self):
self.__buttons = []
for y in range(self.__height):
row = []
for x in range(self.__width):
button = tkinter.Button(self)
button.grid(column=x, row=y)
button['text'] = '?'
command = functools.partial(self.__push, x, y)
button['command'] = command
row.append(button)
self.__buttons.append(row)
def __push(self, x, y):
print('Column = {}\nRow = {}'.format(x, y))
if __name__ == '__main__':
MineSweep.main(10, 10)
如果您想让扫雷游戏的更完整示例从自己的想法中汲取灵感或适应自己的需求,以下程序将实现您可能希望从完成的游戏中获得的许多功能。
import tkinter
import functools
import random
from tkinter.simpledialog import askstring, Dialog
from tkinter.messagebox import showinfo
import os.path
################################################################################
class MineSweep(tkinter.Frame):
@classmethod
def main(cls, width, height, mines, scores):
root = tkinter.Tk()
root.resizable(False, False)
root.title('MineSweep')
window = cls(root, width, height, mines, scores)
root.protocol('WM_DELETE_WINDOW', window.close)
root.mainloop()
################################################################################
def __init__(self, master, width, height, mines, scores):
super().__init__(master)
self.__width = width
self.__height = height
self.__mines = mines
self.__wondering = width * height
self.__started = False
self.__playing = True
self.__scores = ScoreTable()
self.__record_file = scores
if os.path.isfile(scores):
self.__scores.load(scores)
self.__build_timer()
self.__build_buttons()
self.grid()
def close(self):
self.__scores.save(self.__record_file)
self.quit()
def __build_timer(self):
self.__secs = tkinter.IntVar()
self.__timer = tkinter.Label(textvariable=self.__secs)
self.__timer.grid(columnspan=self.__width, sticky=tkinter.EW)
self.__after_handle = None
def __build_buttons(self):
self.__reset_button = tkinter.Button(self)
self.__reset_button['text'] = 'Reset'
self.__reset_button['command'] = self.__reset
self.__reset_button.grid(column=0, row=1,
columnspan=self.__width, sticky=tkinter.EW)
self.__reset_button.blink_handle = None
self.__buttons = []
for y in range(self.__height):
row = []
for x in range(self.__width):
button = tkinter.Button(self, width=2, height=1,
text='?', fg='red')
button.grid(column=x, row=y+2)
command = functools.partial(self.__push, x, y)
button['command'] = command
row.append(button)
self.__buttons.append(row)
def __reset(self):
for row in self.__buttons:
for button in row:
button.config(text='?', fg='red')
self.__started = False
self.__playing = True
self.__wondering = self.__width * self.__height
if self.__after_handle is not None:
self.after_cancel(self.__after_handle)
self.__after_handle = None
self.__secs.set(0)
def __push(self, x, y, real=True):
button = self.__buttons[y][x]
if self.__playing:
if not self.__started:
self.__build_mines()
while self.__buttons[y][x].mine:
self.__build_mines()
self.__started = True
self.__after_handle = self.after(1000, self.__tick)
if not button.pushed:
self.__push_button(button, x, y)
elif real:
self.__blink(button, button['bg'], 'red')
elif real:
self.__blink(button, button['bg'], 'red')
def __blink(self, button, from_bg, to_bg, times=8):
if button.blink_handle is not None and times == 8:
return
button['bg'] = (to_bg, from_bg)[times & 1]
times -= 1
if times:
blinker = functools.partial(self.__blink, button,
from_bg, to_bg, times)
button.blink_handle = self.after(250, blinker)
else:
button.blink_handle = None
def __tick(self):
self.__after_handle = self.after(1000, self.__tick)
self.__secs.set(self.__secs.get() + 1)
def __push_button(self, button, x, y):
button.pushed = True
if button.mine:
button['text'] = 'X'
self.__playing = False
self.after_cancel(self.__after_handle)
self.__after_handle = None
self.__blink(self.__reset_button, button['bg'], 'red')
else:
button['fg'] = 'SystemButtonText'
count = self.__total(x, y)
button['text'] = count and str(count) or ' '
self.__wondering -= 1
if self.__wondering == self.__mines:
self.after_cancel(self.__after_handle)
self.__after_handle = None
self.__finish_game()
def __finish_game(self):
self.__playing = False
score = self.__secs.get()
for row in self.__buttons:
for button in row:
if button.mine:
button['text'] = 'X'
if self.__scores.eligible(score):
name = askstring('New Record', 'What is your name?')
if name is None:
name = 'Anonymous'
self.__scores.add(name, score)
else:
showinfo('You did not get on the high score table.')
HighScoreView(self, 'High Scores', self.__scores.listing())
def __total(self, x, y):
count = 0
for x_offset in range(-1, 2):
x_index = x + x_offset
for y_offset in range(-1, 2):
y_index = y + y_offset
if 0 <= x_index < self.__width and 0 <= y_index < self.__height:
count += self.__buttons[y_index][x_index].mine
if not count:
self.__propagate(x, y)
return count
def __propagate(self, x, y):
for x_offset in range(-1, 2):
x_index = x + x_offset
for y_offset in range(-1, 2):
y_index = y + y_offset
if 0 <= x_index < self.__width and 0 <= y_index < self.__height:
self.__push(x_index, y_index, False)
def __build_mines(self):
mines = [True] * self.__mines
empty = [False] * (self.__width * self.__height - self.__mines)
total = mines + empty
random.shuffle(total)
iterator = iter(total)
for row in self.__buttons:
for button in row:
button.mine = next(iterator)
button.pushed = False
button.blink_handle = None
################################################################################
class ScoreTable:
def __init__(self, size=10):
self.__data = {999: [''] * size}
def add(self, name, score):
assert self.eligible(score)
if score in self.__data:
self.__data[score].insert(0, name)
else:
self.__data[score] = [name]
if len(self.__data[max(self.__data)]) == 1:
del self.__data[max(self.__data)]
else:
del self.__data[max(self.__data)][-1]
def eligible(self, score):
return score <= max(self.__data)
def listing(self):
for key in sorted(self.__data.keys()):
for name in self.__data[key]:
yield name, key
def load(self, filename):
self.__data = eval(open(filename, 'r').read())
def save(self, filename):
open(filename, 'w').write(repr(self.__data))
################################################################################
class HighScoreView(Dialog):
def __init__(self, parent, title, generator):
self.__scores = generator
super().__init__(parent, title)
def body(self, master):
self.__labels = []
for row, (name, score) in enumerate(self.__scores):
label = tkinter.Label(master, text=name)
self.__labels.append(label)
label.grid(row=row, column=0)
label = tkinter.Label(master, text=str(score))
self.__labels.append(label)
label.grid(row=row, column=1)
self.__okay = tkinter.Button(master, command=self.ok, text='Okay')
self.__okay.grid(ipadx=100, columnspan=2, column=0, row=row+1)
return self.__okay
def buttonbox(self):
pass
################################################################################
if __name__ == '__main__':
MineSweep.main(10, 10, 10, 'scores.txt')