我已经看到了一些关于man子手的问题。通常,这是通过非常骇人听闻的方式完成的,通常无法进一步推广。我的想法或问题是关于礼服的创建,这是任何子手游戏的核心部分。
我想在下面创建ASCII图像
_____
| |
O |
/|\ |
/ \ |
|
----------
每次提示该功能时,棒形图应出现。
我还希望能够指定礼服的高度和宽度。但是,我无法相对于礼服尺寸来缩放简笔画。下面提供了代码,对此我有两个简单的问题=)
问题:
是否有更干净的方法来吊人?我觉得我的方法很野蛮(我使用了一些黑色voodo研究生数学来使它看起来正确)。 (本质上是提供更多的猜测)。
代码:
from math import ceil
def create_gown(width, height):
gown = []
gown.append('{:>{}s}'.format('_'*int(width/2), 10))
gown.append('{:>{}s} {:>{}s}'.format(
'|', 11 - int(width/2), '|', int(width/2)-2))
for i in range(height-3):
gown.append('{:^{}s}'.format('|', 20))
gown.append('{:^{}s}'.format('-'*width, 20))
return gown
def wrong_answer(gown, attempt=0):
height, width = len(gown), len(gown[-1].strip())
offset1 = int((-width+23)*0.5)+1
offset3 = int(ceil(0.5*(width-7)))
if attempt == 0:
return gown
elif attempt == 1:
new_line = '{:>{}s} {:>{}s}'.format('O', offset1-1, '|', offset3+1)
row = 2
elif attempt == 2:
new_line = '{:>{}s} {:>{}s}'.format('|', offset1-1, '|', offset3+1)
row = 3
elif attempt == 3:
new_line = '{:>{}s} {:>{}s}'.format('/| ', offset1, '|', offset3)
row = 3
elif attempt == 4:
new_line = '{:>{}s} {:>{}s}'.format('/|\', offset1, '|', offset3)
row = 3
elif attempt == 5:
new_line = '{:>{}s} {:>{}s}'.format('/ ', offset1, '|', offset3)
row = 4
elif attempt == 6:
new_line = '{:>{}s} {:>{}s}'.format('/ \', offset1, '|', offset3)
row = 4
else:
raise Exception("Ops! The number of attempts must be an integer from 0 to 6.")
gown[row] = new_line
return gown
def print_gown(gown):
for line in gown:
print line
if __name__ == '__main__':
gown = create_gown(10, 7)
print len(gown)
for i in range(7):
gown = wrong_answer(gown, i)
print_gown(gown)
#1 楼
重复所有的
elif
都具有相同的结构。您只需要确保插入的花样始终为3宽,就可以放下偏移调整。合理的下一步是使用字典来存储每次尝试的模式和行:_GOWN_MODIFIER = {
1: (' O ', 2),
2: (' | ', 3),
3: ('/| ', 3),
4: ('/|\', 3),
5: ('/ ', 4),
6: ('/ \', 4),
}
def wrong_answer(gown, attempt=0):
height, width = len(gown), len(gown[-1].strip())
offset1 = int((-width+23)*0.5)+1
offset3 = int(ceil(0.5*(width-7)))
if not attempt:
return gown
try:
pattern, row = _GOWN_MODIFIER[attempt]
except KeyError:
raise Exception("Ops! The number of attempts must be an integer from 0 to 6.")
else:
gown[row] = '{:>{}s} {:>{}s}'.format(pattern, offset1, '|', offset3)
return gown
微积分
您不需要
ceil
或int
也不能执行2的整数除法。在Python 2中,/
已经是您需要的运算符。您也可以使用//
,这也是相同的操作。后者优于前者的优势在于,Python 3中的行为相同,而/
将在Python 3中执行小数除法。您知道可以使用
seq(element) * count
创建重复元素的序列。您可以通过重复极点,然后修改顶部的两行和最后一行来创建gown
变量。它应该更便于存储,因为存储列表所需的空间将一口气分配:_GOWN_MODIFIER = {
1: (' O ', 2),
2: (' | ', 3),
3: ('/| ', 3),
4: ('/|\', 3),
5: ('/ ', 4),
6: ('/ \', 4),
}
def wrong_answer(gown, attempt=0):
if not attempt:
return gown
height, width = len(gown), len(gown[-1].strip())
offset1 = (23 - width) // 2 + 1
offset3 = (width - 6) // 2
try:
pattern, row = _GOWN_MODIFIER[attempt]
except KeyError:
raise Exception("Ops! The number of attempts must be an integer from 0 to 6.")
else:
gown[row] = '{:>{}s} {:>{}s}'.format(pattern, offset1, '|', offset3)
return gown
def create_gown(width, height):
half_width = width // 2
gown = []
gown.append('{:>{}s}'.format('_'*half_width, 10))
gown.append('{:>{}s} {:>{}s}'.format(
'|', 11 - half_width, '|', half_width-2))
for i in range(height-3):
gown.append('{:^{}s}'.format('|', 20))
gown.append('{:^{}s}'.format('-'*width, 20))
return gown
就地修改并返回值时
还有一点关于打印的信息
您的
wrong_answer
都修改了礼服并返回修改后的值。这是不必要的,因为调用方仍应保留对该值的引用(已被修改)。调用代码时,您可以拥有:复制对同一对象的引用。相反,您可以做的是预处理打印作业,因此您实际上不需要print_gown
函数:def create_gown(width, height):
half_width = width // 2
gown = ['{:^{}s}'.format('|', 20)] * height
gown[0] = '{:>{}s}'.format('_' * half_width, 10)
gown[1] = '{:>{}s} {:>{}s}'.format(
'|', 11 - half_width, '|', half_width-2)
gown[-1] = '{:^{}s}'.format('-' * width, 20)
return gown
用法:
gown2 = wrong_answer(gown, attempt=3)
异常
提高通用
Exception
是不好的做法,因为它使试图处理您的代码的except
子句能够捕获比应有的更多的代码。您至少应该使用更通用的异常(例如ValueError
)或定义自己的异常:调用者应通过增加wrong_answer
来调用此函数。这是发电机的工作。通过将attempts
变成生成器,可以调用它来创建生成器实例,然后在此实例上调用wrong_answer
(或让next
循环为您完成)以获取下一件要打印的礼服: >>> gown2 is gown
True
用法:
def wrong_answer(gown, attempt=0):
height, width = len(gown), len(gown[-1].strip())
offset1 = (23 - width) // 2 + 1
offset3 = (width - 6) // 2
if attempt:
try:
pattern, row = _GOWN_MODIFIER[attempt]
except KeyError:
raise Exception("Ops! The number of attempts must be an integer from 0 to 6.")
else:
gown[row] = '{:>{}s} {:>{}s}'.format(pattern, offset1, '|', offset3)
return '\n'.join(gown)
,或者在更实际的情况下:
print(wrong_answer(gown, attempt=3))
魔术数字
for
似乎将礼服放在20个大小的字符串中居中,但是,如果create_gown
大于该值怎么办?首先,您应该定义此值并为其赋予一个有意义的名称,并且所有衍生自该值的值都应相同。然后,您可能希望以width
作为微积分的基础。评论
\ $ \ begingroup \ $
可爱的答案!您是否确定`try:pattern,row = _GOWN_MODIFIER [attempt]`部分?似乎捕获了所有错误,而不仅仅是数字不在范围内。关于您对魔术数字的评论,我完全同意。我似乎将礼服摆在20根大小的琴弦中。有办法避免这种情况吗?我试图以高度和宽度为基础,但是遇到了一些问题。如果您有避免微积分的任何技巧,那就太好了(因为尚不清楚它的作用,并且其中包含幻数)。再次在其他部分上提供了很好的建议!
\ $ \ endgroup \ $
– N3buchadnezzar
16年6月7日在13:33
\ $ \ begingroup \ $
try部分与一个KeyError除外配对,因此只有未在_GOWN_MODIFIER词典中定义的尝试才会触发您的自定义异常。仅当尝试运行没有问题时,才会执行else部分。
\ $ \ endgroup \ $
–301_Moved_Permanently
16年6月7日在13:39
\ $ \ begingroup \ $
谢谢!我也完全同意发电机。我尝试将其制作为发电机,但未能做到。感谢您向我展示正确的方法
\ $ \ endgroup \ $
– N3buchadnezzar
16年6月7日在13:41
\ $ \ begingroup \ $
对于宽度部分,应尽量不要将'|'居中在您的中间字符串中。类似于''* half_width +'|'应该会给你杆子和图案+''*(half_width-3)+'|'对于中间零件就足够了。使用格式也可以使其更清洁。
\ $ \ endgroup \ $
–301_Moved_Permanently
16年6月7日在13:44
评论
您说“礼服”时,您是说“绞架”吗?吊死男人最常见但不一定正确的方法是吊死他的正确方法;)
我回滚了最后的编辑,因为它使Mathias的答案无效。请查看当有人回答时该怎么办。
该问题已被选为“ 2016年最佳代码评论”(Best of Code Review)“最佳标题”的得主。
oo!