from random import randrange
import time
# Snow animation
# Snow is simply the `#` symbol here. Half of the snow moves at 1 char
# per frame, while the other half moves at 0.5 chars per frame. The
# program ends when all the snow reaches the bottom of the screen.
# The viewing area is 80x25. It puts 100 snow flakes to output, half
# fast, and half slow. Every frame it dispenses 4 flakes, 2 fast and
# 2 slow ones, at random locations at the top of the viewing area.
screen = {'x': 80, 'y': 20}
drops = []
def createRainDrop(x, y, speed):
return {'x': x, 'y': y, 'speed': speed}
def createRandomDrops():
dropCount = 4
for i in range(dropCount):
yield createRainDrop(randrange(0, screen['x']), 0, min((i % 2) + 0.5, 1))
def moveDrops():
for drop in drops:
speed = drop['speed']
drop['y'] = drop['y']+speed
def drawDrops():
out = [''] * screen['y']
for y in range(screen['y']):
for x in range(screen['x']):
out[y] += '#' if any([drop['x'] == x and int(drop['y']) == y for drop in drops]) else ' '
return '\n'.join(out)
def dropsOnScreen():
return any([drop['y'] < screen['y'] for drop in drops])
drops += createRandomDrops()
while dropsOnScreen():
if len(drops) < 100:
drops += createRandomDrops()
print(drawDrops())
moveDrops()
time.sleep(0.100)
例如,我不知道如何删除重复的行
drops += createRandomDrops()
和drawDrops()
有点像黑客。我承认!写这篇文章的时候是下雨,不是下雪!
#1 楼
让我们看一下代码。from random import randrange
import time
您的导入非常少!好。
# Snow animation
# Snow is simply the `#` symbol here. Half of the snow moves at 1 char
# per frame, while the other half moves at 0.5 chars per frame. The
# program ends when all the snow reaches the bottom of the screen.
# The viewing area is 80x25. It puts 100 snow flakes to output, half
# fast, and half slow. Every frame it dispenses 4 flakes, 2 fast and
# 2 slow ones, at random locations at the top of the viewing area.
对我来说,这看起来像是文档字符串。这样渲染它会很好。您可以通过删除
#
符号并将其括在"""
引号中来实现此目的。但这是一个简单的文件,所以也许我们现在就可以像这样保留它了吗? screen = {'x': 80, 'y': 20}
drops = []
我认为类似类的东西对此更好。让我们尝试一下
def createRainDrop(x, y, speed):
return {'x': x, 'y': y, 'speed': speed}
当然,现在我们需要用
createRainDrop(...)
替换RainDrop(...)
,并用drop['...']
替换drop....
。 br />更好。class RainDrop(object):
def __init__(self, x, y, speed):
self.x = x
self.y = y
self.speed = speed
我们在这里修改
drop
,而不是要求它修改自己。我们应该在此处编写类似drop.moveDown()
或drop.tick()
(“ tick”是通常用来通知事件有关时间提前的事件)的内容。对于屏幕上的所有位置,您正在遍历所有滴。理想情况下,我们应该解决以下问题:
def createRandomDrops():
dropCount = 4
for i in range(dropCount):
yield RainDrop(randrange(0, screen['x']), 0, min((i % 2) + 0.5, 1))
现在,它更快更干净了。说得通。除非我建议不要使用
[...]
,它会创建一个列表。更好地使用def moveDrops():
for drop in drops:
drop.y = drop.y + drop.speed
行为相同,但不必创建中间列表。
def drawDrops():
out = [''] * screen['y']
for y in range(screen['y']):
for x in range(screen['x']):
out[y] += '#' if any([drop.x == x and drop.y == y for drop in drops]) else ' '
return '\n'.join(out)
您想摆脱对
drops += createRandomDrops()
的重复调用。评论
\ $ \ begingroup \ $
感谢您的回答!看起来确实比我的原始代码好得多。一个小问题:在createRandomDrops中,您指出min((i%2)+ 0.5,1)并将其更改为min(int(i%2 + 0.5),1),原始对象实际上打算使用浮点数,将数字更改为1或0.5,这样我就可以得到半步的雪花,尽管很难分辨...
\ $ \ endgroup \ $
– J阿特金
16年2月1日在16:30
\ $ \ begingroup \ $
@JAtkin:蛇壳,但应该是PascalCase的类除外。
\ $ \ endgroup \ $
– Sjoerd Job Postmus
16年1月1日在20:00
\ $ \ begingroup \ $
@SjoerdJobPostmus我不确定OP的意图是关于速度。看起来应该是0.5或1,所以也许(1.0,0.5)[i%2]
\ $ \ endgroup \ $
– njzk2
16-2-1在23:31
\ $ \ begingroup \ $
@ njzk2:重新读取后,语句为min((i%2)+ 0.5,1)。这取值为(1.0,1.5)[i%2]。它可能不是预期的,但它是当前值。
\ $ \ endgroup \ $
– Sjoerd Job Postmus
16年2月1日在23:41
\ $ \ begingroup \ $
@Schmuddi:请考虑out = [[''] * 7] * 5,然后考虑out [3] [4] ='X'。然后,out [2] [4]也将设置为X,因为out [0] .. out [4]都引用相同的列表。一个有效的替代方法可能是out = [[''] * screen [x'] for _ in range(screen ['y'])]。
\ $ \ endgroup \ $
– Sjoerd Job Postmus
19年1月28日在15:26
#2 楼
很棒的动画!让我们摆脱烦恼。根据PEP 8,您应该一致地使用4个缩进空间,并且函数名称应为
snake_case
。设计的主要缺点是可伸缩性。如果将循环扩展为无限期运行,则最终会遇到性能问题。一个问题是
drops
列表随每次迭代而增长,并且永远不会被修剪。水滴在掉落到地面后不会消失。他们会永远消失在屏幕外。解决方案是让moveDrops()
跌落到最低点以上时删除它们。 (与让dropsOnScreen()
重新检查每个动画帧上的每个液滴相比,这是一种更明智的策略。)此外,要将液滴放置在网格上,您还需要对每个液滴进行O(n)扫描屏幕与
'#' if any([drop['x'] == x and int(drop['y']) == y for drop in drops])
。我将重写drawDrops()
,以便使用字典或2-D数组将每个放置位置放置。与重复的追加操作相比,我也更喜欢使用理解,但这主要是样式首选项。但您的代码显示为screen = {'x': 80, 'y': 20}
。理想情况下,应使用curses
库在运行时检测尺寸。由于screen
用作全局变量,因此我希望看到它名为SCREEN
并使其不可变。 namedtuple
将使其不可变,具有允许点访问器而不是笨拙的[]
表示法的其他好处。我认为width
和height
比x
和y
更合适。类似地,为雨滴定义类将避免使用
drop['x']
表示法。此外,createRainDrop()
函数强烈要求它是一个构造函数。创建拖放并循环
其余的代码是Python迭代中的一个练习。一切都可以通过自由使用迭代器来处理。
在
createRandomDrops()
中,使用min((i % 2) + 0.5, 1)
代替神秘的公式itertools.cycle([0.5, 1])
。我将把createRandomDrops()
变成无限生成器。 在下面的解决方案中,可以通过修改
drop_params
和precipitation
集中调整速度,强度和持续时间等参数。例如,precipitation = drop_generator(**drop_params)
将导致无限循环,每帧仅出现一个新的下降。评论
\ $ \ begingroup \ $
非常好!显然我的密码公式非常糟糕,因为它返回0.5和1 ... codereview.stackexchange.com/questions/118538 / ...我个人非常不喜欢snake_case(我来自Java / Scala),这就是为什么我使用骆驼香烟盒。编辑,哇,我几乎看不懂您的解决方案。我要去找我的Python书...
\ $ \ endgroup \ $
– J阿特金
16-2-2在13:35
\ $ \ begingroup \ $
@JAtkin,因为您使用的是Python3,为什么不只使用内置的终端大小?
\ $ \ endgroup \ $
–Wayne Werner
16年3月3日在22:07
\ $ \ begingroup \ $
2个原因。 1)我不知道。 2)我通过反复试验得出了当前数字,以使机器上的闪烁最少。
\ $ \ endgroup \ $
– J阿特金
16年2月3日在22:54
\ $ \ begingroup \ $
好的答案。也许还使用if __name__ ==“ __main__”卫队包装代码?
\ $ \ endgroup \ $
–omgimanerd
17年7月19日在0:36
#3 楼
你没有下雪!显然应该是 for flake in flurry:
评论
\ $ \ begingroup \ $
对于为什么(在我看来)学步鞋是这个问题的第二个最不满意的答案,我有点困惑。诚然,英语词汇差异对下一个代码维护者很重要,关于2个变量名的100个字符的答案似乎没有这里的其他答案有价值。 CR社区,您让我感到困惑。
\ $ \ endgroup \ $
–克里斯·西里菲斯(Chris Cirefice)
16年3月3日,在2:38
\ $ \ begingroup \ $
@ChrisCirefice您不是唯一对此感到困惑的人。如果您愿意,请随时在我们的meta上发布问题。不幸的是(?),挑剔变量名是一个有效的答案。至于为什么它被这么大的批评,我不能说。
\ $ \ endgroup \ $
–西蒙·福斯伯格
16-2-3在13:29
\ $ \ begingroup \ $
@ChrisCirefice和Simon很好,最初的问题是在脚本中询问一些顽皮,这些脚本会在屏幕上画雪。大多数人可能都没有看到那种严重的气氛
\ $ \ endgroup \ $
–我很困惑
16-2-3在13:47
\ $ \ begingroup \ $
事物的命名是计算机科学中的两个难题之一,因此“选择尼特”的名字非常重要。作为参考,困难的问题是1)命名事物2)缓存过期3)一次出错。我认为这次提名也增加了一两个。
\ $ \ endgroup \ $
–低音扬声器
16-2-3在13:49
\ $ \ begingroup \ $
@SimonForsberg我在Meta上发布了一个问题。我不认为应该删除此答案或进行任何其他操作,但是我认为这样的答案似乎很有趣,应该是真正的评论,而不是其他完整答案。
\ $ \ endgroup \ $
–克里斯·西里菲斯(Chris Cirefice)
16年3月3日在17:19
#4 楼
我很惊讶没有人谈论您的角色选择!他们的一堆标签为什么掉下来?不,我在说,这是可以选择的角色,但我们可以做得更好!如何将#
更改为unicode(Python 3支持!)❄
。现在看起来真的像雪! 此外,您当前的代码与Python 2向后兼容。更改字符会破坏这一点。如果要修复该问题,请添加:
# -*- coding: utf8 -*-
到文件顶部。
评论
\ $ \ begingroup \ $
如果您不确定如何键入或不想搜索,可以使用print('\ N {SNOWFLAKE}')帮助。如果您使u'\ N {SNOWFLAKE}';)也可以在Python2上使用
\ $ \ endgroup \ $
–Wayne Werner
16-2-3在22:11
\ $ \ begingroup \ $
很好,我不知道utf-8有雪的符号。
\ $ \ endgroup \ $
– J阿特金
16年2月4日在16:37
#5 楼
def createRandomDrops():
dropCount = 4
for i in range(dropCount):
代码中间的魔术数字4
def drawDrops():
我希望这种方法实际上会绘制液滴,而不是将字符串返回打印
#6 楼
from random import randrange
我建议使用
import random
然后在您的代码中使用
random.randrange
。在您的特定情况下,也许并不重要,但是我自己发现,在可能的情况下,导入模块而不是从模块中导入名称是一个好规则。 google.github.io/styleguide/pyguide.html#Imports 仅对软件包和模块使用
import
。导入模块有时会有所帮助您可以防止循环导入错误。
它有助于在模块扩展时导入太多名称。
它可以帮助您解决名称冲突。例如,几个模块具有
ValidationError
类(mongoengine
,wtforms
等),并且您的代码使用所有这些模块。
评论
createRainDrop您确定要下雪吗?不幸的是。写这篇文章的时候是下雨,不是下雪。
我很想看动画。我需要遵循什么才能在Windows 7计算机上“加载”代码?我可以只安装Python并让文件运行它吗,还是需要一个IDE在其中运行它?任何关于tut的链接都将很不错。目前这里是“下雪”,半雪半雨。
只需安装python 3.x,进入控制台并输入python C:\ path \ to \ snow.py。您可能需要缩小控制台窗口以使动画更流畅。