一些背景知识:
我正在学习基于代理的建模,并且刚刚使用 Mesa 包实现了康威的生命游戏。我读过该模型的初始配置,这些配置产生了有趣的现象,并且想要重新创建它们(即 Gosper 滑翔机枪、R-pentomino 等)
我认为一个有趣的学习项目是创建一个显示网格的 GUI 应用程序,并允许用户选择他们想要用来实例化模型的单元格。
问题:
我希望显示一个包含网格的 GUI,如下所示:
然后用户可以单击他们想要填充的单元格,它将显示如下:
然后,当用户单击“保存状态”按钮(或按指定的结束键)时,他们的选择将保存到 numpy 数组中以实例化模型。
我不知道从哪里开始。如果有人能指出我正确的方向,我将不胜感激。
差不多 5 年后,我有同样的想法并使用 tkinter 解决了。只是在这里留下一个(未优化的)演示,以防其他人经过:
import tkinter
from tkinter import *
class Universe:
def __init__(self, w: int, h: int, seed: [(int, int)]):
self.max_row = h
self.max_col = w
self.board = []
for _ in range(h):
self.board.append([0] * w)
self.seed(seed)
def seed(self, positions: [(int, int)]):
for x, y in positions:
self.board[y][x] = 1
def update(self):
temp = [[0]*self.max_col for _ in range(self.max_row)]
for r in range(self.max_row):
for c in range(self.max_col):
neighbors = self.count_neighbors(r, c)
# underpopulation
if self.board[r][c] == 1 and neighbors < 2:
temp[r][c] = 0
# next generation
elif self.board[r][c] == 1 and neighbors == 2 or neighbors == 3:
temp[r][c] = 1
# overpopulation
elif self.board[r][c] == 1 and neighbors > 3:
temp[r][c] = 0
# reproduction
elif self.board[r][c] == 0 and neighbors == 3:
temp[r][c] = 1
else:
temp[r][c] = self.board[r][c]
self.board = temp
def count_neighbors(self, y: int, x: int) -> int:
n = 0
n += self.board[y - 1][x - 1] if (y - 1 >= 0) and (x - 1 >= 0) else 0
n += self.board[y - 1][x] if (y - 1 >= 0) else 0
n += self.board[y - 1][x + 1] if (y - 1 >= 0) and (x + 1 < self.max_col) else 0
n += self.board[y][x - 1] if (x - 1 >= 0) else 0
n += self.board[y][x + 1] if (x + 1 < self.max_col) else 0
n += self.board[y + 1][x - 1] if (y + 1 < self.max_row) and (x - 1 >= 0) else 0
n += self.board[y + 1][x] if (y + 1 < self.max_row) and (x + 1 < self.max_col) else 0
n += self.board[y + 1][x + 1] if (y + 1 < self.max_row) and (x + 1 < self.max_col) else 0
return n
class UI:
def __init__(self, universe:Universe):
self.cells = [[]]
self.universe = universe
window = Tk()
window.minsize(width=500, height=500)
canvas = Canvas(width=500, height=500)
self.fill_canvas(canvas)
canvas.pack()
button = Button(text='go', command=self.button_clicked, width=5, height=2)
button.pack()
window.mainloop()
def button_clicked(self):
self.universe.update()
for i in range(self.universe.max_row):
for j in range(self.universe.max_col):
self.cells[i][j].configure(background='white' if self.universe.board[i][j] == 0 else 'black')
def fill_canvas(self, canvas: tkinter.Canvas):
for i in range(self.universe.max_row):
self.cells.append([])
for j in range(self.universe.max_col):
e = Entry(canvas, width=2, background='white' if self.universe.board[i][j] == 0 else 'black')
e.grid(row=i, column=j)
self.cells[i].append(e)
# test with penta-decathlon oscillator
ui = UI(
Universe(20, 20,
[(4, 6), (4, 11), (5, 4), (5, 5), (5, 7), (5, 8), (5, 9), (5, 10), (5, 12), (5, 13), (6, 6), (6, 11)]))