我已经走到了死胡同,在过度(和不成功)谷歌搜索之后,我需要帮助。
我正在构建一个简单的 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
]
如果用户单击鼠标右键,它会使用常见的递归洪水填充算法对一个区域进行洪水填充。这非常适用于小空间,但是如果空间足够大,程序将失败并显示错误 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()
任何人都可以帮助诊断问题或者指出解决问题的方向吗?
最佳答案
您正在使用基于堆栈的森林火灾算法,已知会消耗大量堆栈,因此最好避免使用它。
我的避免递归的建议:alternate forest fire algorithm
我什至使用您的类对象实现了它。用一些 ASCII-art 和您的实际代码对其进行了测试,即使在大区域上也能正常工作:
def fill(self, x, y, t):
if self.cells[(x,y)] == None: # cannot use not: there are 0 values
to_fill = [(x,y)]
while to_fill:
# pick a point from the queue
x,y = to_fill.pop()
# change color if possible
self.cells[(x,y)] = t
# now the neighbours x,y +- 1
for delta_x in range(-1,2):
xdx = x+delta_x
if xdx > 0 and xdx < self.columns+1:
for delta_y in range(-1,2):
ydy = y+delta_y
# avoid diagonals
if (delta_x == 0) ^ (delta_y == 0):
if ydy > 0 and ydy < self.rows+1:
# valid x+delta_x,y+delta_y
# push in queue if no color
if self.cells[(xdx,ydy)] == None:
to_fill.append((xdx,ydy))
self.repaint()
当您通过一个点时,它会检查是否必须填充。 如果必须填充,则将其插入队列并运行循环。
循环只是从队列中弹出一个项目,改变它的颜色,并尝试对它的邻居做同样的事情:如果仍在图片中(x,y 边界检查)而不是对角线,并且没有定义颜色邻居,只需将坐标插入队列即可。
当所有项目都被处理后,循环停止:一段时间后,要么到达边缘,要么只遇到填充点,因此没有额外的点排队。
这种方法只依赖于可用内存,而不是堆栈。
证明它有效:成功填充了一个巨大的蓝色区域而没有堆栈溢出。
关于python - 洪水填充期间的致命 Python 错误 : Cannot recover from stack overflow.,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40963288/
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe
在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
我有一个驼峰式字符串,例如:JustAString。我想按照以下规则形成长度为4的字符串:抓取所有大写字母;如果超过4个大写字母,只保留前4个;如果少于4个大写字母,则将最后大写字母后的字母大写并添加字母,直到长度变为4。以下是可能发生的3种情况:ThisIsMyString将产生TIMS(大写字母);ThisIsOneVeryLongString将产生TIOV(前4个大写字母);MyString将生成MSTR(大写字母+tr大写)。我设法用这个片段解决了前两种情况:str.scan(/[A-Z]/).first(4).join但是,我不太确定如何最好地修改上面的代码片段以处理最后一种