Я пришел в тупик, и после чрезмерного (и неудачного) Googling мне нужна помощь.Неустранимая ошибка Python: невозможно восстановить из переполнения стека. Во время Flood Fill
Я строю простой виджет PyQt4, где он лежит сеткой квадратов 60x80, каждая из которых инициализирована до None
. Если пользователь нажимает на поле он меняет цвет в зависимости от того, сколько раз левой кнопкой мыши, определяется в этом списке:
self.COLORS=[
(0, 0, 255), #WATER
(255, 210, 128), #SAND
(0, 128, 0), #GREEN
(255, 255, 0), #YELLOW
(255, 165, 0), #ORANGE
(255, 0, 0) #RED
]
Если правильных пользователь щелкает, это наводнение заполняет область, используя общий рекурсивный заливки Algo , Это отлично работает для небольших пространств, однако, если пространство достаточно велико, программа выходит из строя с ошибкой Fatal Python error: Cannot recover from stack overflow.
Я понятия не имею, как это исправить, возможно, заливка заливки, которая не является рекурсивной?
Все квадраты и последующие цветовые коды хранятся в self.cells
так, установив self.cells[(y,x)]=1
бы установить ячейку (y,x)
в Sand
цвета.
Описание программы целиком.
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self, cell_size=10, swidth=800, sheight=600):
QtGui.QWidget.__init__(self)
self.resize(swidth,sheight)
self.cell_size = cell_size
self.height = sheight
self.width = swidth
self.columns = self.width // self.cell_size
self.rows = self.height // self.cell_size
self.COLORS=[
(0, 0, 255), #WATER
(255, 210, 128), #SAND
(0, 128, 0), #GREEN
(255, 255, 0), #YELLOW
(255, 165, 0), #ORANGE
(255, 0, 0) #RED
]
self.cells = {(x,y):None for x in range(1,self.columns+1) for y in range(1,self.rows+1)}
def translate(self,pixel_x, pixel_y):
"Translate pixel coordinates (pixel_x,pixel_y), into grid coordinates"
x = pixel_x * self.columns // self.width + 1
y = pixel_y * self.rows // self.height + 1
return x,y
def check_cell(self,x,y):
if self.cells[(x,y)] <= 0:
self.cells[(x,y)]=0
elif self.cells[(x,y)] >= len(self.COLORS)-1:
self.cells[(x,y)]=len(self.COLORS)-1
else:
pass
def draw_cell(self, qp, col, row):
x1,y1 = (col-1) * self.cell_size, (row-1) * self.cell_size
x2,y2 = (col-1) * self.cell_size + self.cell_size, (row-1) * self.cell_size + self.cell_size
qp.drawRect(x1, y1, x2-x1, y2-y1)
def color_cell(self, qp, col, row):
qp.setBrush(QtGui.QColor(*self.COLORS[self.cells[(col,row)]]))
self.draw_cell(qp, col, row)
def draw_grid(self, qp):
qp.setPen(QtGui.QColor(128,128,128)) # gray
# Horizontal lines
for i in range(self.rows):
qp.drawLine(0, i * self.cell_size, self.width, i * self.cell_size)
# Vertical lines
for j in range(self.columns):
qp.drawLine(j * self.cell_size, 0, j * self.cell_size, self.height)
def set_all(self, type):
self.cells = {(x,y):type for x in range(1,self.columns+1) for y in range(1,self.rows+1)}
self.repaint()
def fill(self, x, y, type):
print(x,y)
if x < 1 or x >= self.columns+1 or y < 1 or y >= self.rows+1:
return
if self.cells[(x,y)] != None:
return
self.cells[(x,y)] = type
self.repaint()
self.fill(x+1, y, type)
self.fill(x-1, y, type)
self.fill(x, y+1, type)
self.fill(x, y-1, type)
def paintEvent(self, e):
qp = QtGui.QPainter()
qp.begin(self)
self.draw_grid(qp)
for row in range(1, self.rows+1):
for col in range(1, self.columns+1):
if self.cells[(col,row)] != None:
self.color_cell(qp, col, row)
qp.end()
def drawPoints(self, qp):
size = self.size()
for i in range(1000):
x = random.randint(1, size.width()-1)
y = random.randint(1, size.height()-1)
qp.drawPoint(x, y)
def mousePressEvent(self, e):
x,y = self.translate(e.pos().x(),e.pos().y())
if e.button() == QtCore.Qt.LeftButton:
if self.cells[(x,y)] == None:
self.cells[(x,y)]=0
else:
self.cells[(x,y)]+=1
self.check_cell(x,y)
elif e.button() == QtCore.Qt.RightButton:
self.fill(x,y,0)
'''
if self.cells[(x,y)] == None:
self.cells[(x,y)]=0
else:
self.cells[(x,y)]-=1
self.check_cell(x,y)
'''
else: pass
self.repaint()
def save(self):
return self.cells
def open(self, new_cells):
self.cells=new_cells
self.repaint()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Может ли кто-нибудь помочь диагностировать проблему или, возможно, указать направление ее исправить? Если я не объясню что-то достаточно подробно, дайте мне знать, и я это исправлю.
Спасибо всем!
заливка с использованием рекурсии имеет эту проблему. Я бы рекомендовал «алгоритм лесного пожара» (не рекурсивный) для этой задачи. Простой и выполняет эту работу. –
Кстати, почему ячейка (y, x) не является опечаткой для ячейки (x, y)? –
Я загляну в «лесной пожар», и нет, это не опечатка. К сожалению, когда я впервые написал это, я сделал это в обратном порядке и вместо того, чтобы исправить мою ошибку в начале, я просто пробежал с ней всю дорогу ... – aseylys