首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >绞死一个人的正确方法

绞死一个人的正确方法
EN

Code Review用户
提问于 2016-06-07 11:26:38
回答 1查看 3.7K关注 0票数 48

问题:

我在绞刑架附近见过几个问题。通常情况下,这是一种非常草率的方式,这通常不能进一步推广。我的想法或问题是关于礼服的创造,这是任何绞刑游戏的核心部分。

我想创建下面的ASCII图像

代码语言:javascript
复制
 _____
 |   |
 O   |
/|\  |
/ \  |
     |          
 ---------- 

每当提示函数时,棒形的一个“肢体”就会出现。

我也希望能够指定礼服的高度和宽度。然而,相对于礼服的尺寸,我无法缩放棍子的形状。下面提供了代码,我有两个关于它=的简单问题。

问题:

  • 有更干净的方法来吊死那个人吗?我觉得我的方法很野蛮(我用了一些黑色的毕业数学让它看起来正确)。
  • 有什么方法可以使棍子的数字比例尺与礼服的大小吗?(实质上提供了更多的猜测)。

代码:

代码语言:javascript
复制
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)
EN

回答 1

Code Review用户

回答已采纳

发布于 2016-06-07 13:22:33

重复

所有的elif都有相同的结构。您只需要确保插入的模式总是3宽,并且可以删除偏移调整。逻辑的下一步是使用字典来存储每次尝试的模式和行:

代码语言:javascript
复制
_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

Calculus

您不需要ceilint来执行整数除法2。在Python2中,/已经是您需要的运算符。您还可以使用//,这也是相同的操作。与前者相比,后者的优点是在Python3中的行为是相同的,而/将在Python3中执行十进制除法。

代码语言:javascript
复制
_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

创建与修改

您知道可以使用seq(element) * count创建重复元素的序列。您可以使用它来创建gown变量,方法是重复极点,然后修改前两行和最后一行;由于存储列表所需的空间将一次分配给您,所以内存应该更友好:

代码语言:javascript
复制
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

修改位置并返回值

和一些关于打印太

的事情

您的wrong_answer既修改了礼服的位置,又返回了修改后的值。这是不必要的,因为调用方仍然应该保存对值的引用(该值已被修改)。调用代码时,您可以拥有:

代码语言:javascript
复制
gown2 = wrong_answer(gown, attempt=3)

代码语言:javascript
复制
>>> gown2 is gown
True

因此,复制对同一个对象的引用是没有意义的。相反,您可以做的是对打印作业进行预处理,因此您实际上不需要print_gown函数:

代码语言:javascript
复制
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)

用法:

代码语言:javascript
复制
print(wrong_answer(gown, attempt=3))

例外

引发通用用途Exception是一种糟糕的做法,因为它使试图处理代码的except子句能够捕获比它们更多的代码。您至少应该使用更通用的异常(如ValueError)或定义您自己的异常:

代码语言:javascript
复制
class AlreadyHangedError(ValueError):
    pass

def wrong_answer(gown, attempt):
    ...
    raise AlreadyHangedError('...')
    ...

但是,您使用wrong_answer的方式有一些奇怪之处:期望调用方使用增加的attempts来调用这个函数。这是发电机的工作。通过将wrong_answer转换为生成器,您可以调用它来创建生成器实例,然后在这个实例上调用next (或者让for循环为您完成),以获得要打印的下一个礼服:

代码语言:javascript
复制
def wrong_answer(width, height):
    gown = create_gown(width, height)
    offset1 = (23 - width) // 2 + 1
    offset3 = (width - 6) // 2

    yield '\n'.join(gown)
    for attempt in range(1, 7):
        pattern, row = _GOWN_MODIFIER[attempt]
        gown[row] = '{:>{}s} {:>{}s}'.format(pattern, offset1, '|', offset3)
        yield '\n'.join(gown)

用法:

代码语言:javascript
复制
for gown in wrong_answer(10, 7):
    print(gown)

或者,在更真实的情况下:

代码语言:javascript
复制
def hangman_game():
    for gown in wrong_answer(10, 7):
        while True:
            status = manage_user_input()
            if status == 'FAILED':  # Whatever
                break
            if status == 'COMPLETED':  # Whatever
                return
        print gown
    print 'You lose'

幻数

create_gown似乎把礼服集中在20条线上,但如果width比那更大呢?首先,您应该定义这个值,并给它一个有意义的名称,对由此派生出来的所有值都是相同的;然后,您可能希望将max(20, width)作为微积分的基础。

票数 35
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/131314

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档