6

更新 有人可能会因为我以这种方式发帖而对我下手,但评论中没有足够的空间来涵盖这一点,他们特别告诉你不要通过后续回答来回答你自己的问题,所以这里......

我已经创建了你们所说的骰子类。

class dice():
    def __init__(self, sides, number):
        self.sides = sides
        self.number = number

    def roll(self):
        return random.randint(1, self.sides)

number争论没有做任何事情。

def att():
    d = dice(20, 2)
    base = d.roll()
    if base == 1:
        print 'Miss!'
    elif base == 20:
        crit = d.roll()
        if crit < 10:
            print 'Hit!'
        else:
            print 'Critical hit!\n'
            effect = super_crit()               
    else:
        print base

我得到不止一个死的唯一方法是如果我做这样的事情:

def initiative():
    d = dice(10, 1)
    ini = d.roll(), d.roll()
    print ini

我也试过:

def initiative():
    d = dice(10, 2)
    d.sides = 10
    d.number = 2
    ini = d.roll()
    print ini

这对我来说看起来是多余的,但我得到了一个Type Error:因为没有dice(10, 2). 无论我使用哪种方法,我都会得到相同的结果——一个死。我错过了什么吗?

原帖

我正在学习如何在 Python 2.7 中使用类,作为练习,我正在为基于文本的 RPG 编写战斗模块。它使用老式的掷骰子方法来确定结果和效果。掷骰决定命中或未命中。如果掷出自然 20,则另一个掷骰确定它是否是重击。如果重击 = TRUE,则掷另一个骰子以确定受影响的身体部位。每个身体部位都与字典中的数字 1-12 配对。根据受影响的部分,有三种可能的输出消息。我的问题是返回整个值列表而不是特定部分。我在这里做错了什么?

是的,我知道这是超级书呆子。是的,我知道输出很蹩脚,但它都是占位符。

import sys, random

#dice generator
class dice():
    def d4(self):
        number = random.randint(1, 4)
        return number

    def d6(self):
        number = random.randint(1, 6)
        return number

    def d10(self):
        number = random.randint(0, 9)
        return number

    def d12(self):
        number = random.randint(1, 12)
        return number

    def d20(self):
        number = random.randint(1, 20)
        return number

    def d100(self):
        number = random.randint(0, 99)
        return number 

#critical hit effect generator        
class super_crit(dice):
    def __init__(self):
        roll = dice()
        loc = roll.d12()
        hit_loc = {1 : 'Head',
                   2 : 'Left Arm',
                   3 : 'Right Arm',
                   4 : 'Left Leg',
                   5 : 'Right Leg',
                   6 : 'Left Hand',
                   7 : 'Right Hand',
                   8 : 'Left Foot',
                   9 : 'Right Foot',
                   10 : 'Chest',
                   11 : 'Stomach',
                   12 : 'Body'}
        part = hit_loc.values()
        for w in part:
            if loc <= 9:
                print w, "has been severed!"
            elif loc == 10:
                print "You sink your blade into his", w, "and pierce the heart!"
            elif loc == 11:
                print "You slash him across the", w, "and eviscerate him!"
            elif loc == 12:
                print "You shred the enemy's", w, "to ribbons!"

class attackRoll(dice):
        pass

#Attack function        
def att():
    roll = attackRoll()
    base = roll.d20()
    if base == 1:
        print 'Miss!'
    elif base == 20:
        crit = roll.d20()
        if crit < 10:
            print 'Hit!'
        else:
            effect = super_crit()               
    else:
        print base

def main():
    att()


if __name__ == '__main__':

main()
4

7 回答 7

5

你循环遍历字典的所有值:

part = hit_loc.values()
for w in part:
    # loop over each part, so print a damage message for all 12 bodyparts

也许您打算选择受影响的那个?

part = hit_loc[loc]  # assign *one* body part to `part`
if loc <= 9:
    print part, "has been severed!"
elif loc == 10:
    print "You sink your blade into his", part, "and pierce the heart!"
elif loc == 11:
    print "You slash him across the", part, "and eviscerate him!"
elif loc == 12:
    print "You shred the enemy's", part, "to ribbons!"

换句话说,这里根本不需要循环。

请注意,每当您发现自己使用一系列连续的数字作为字典的键时,您也可以将其设为列表:

hit_loc = [
    'Head', 'Left Arm', 'Right Arm', 'Left Leg', 
    'Right Leg', 'Left Hand', 'Right Hand', 'Left Foot', 'Right Foot',
    'Chest', 'Stomach', 'Body'
]

除了现在索引从 0 到 11,所以用它loc - 1来找到正确的身体部位:

part = hit_loc[loc - 1]
于 2013-01-19T00:09:39.170 回答
3

相切...

骰子类的更简单版本可能类似于:

class Die(object):
    def __init__(self, sides = 6):
        self.sides = sides

    def roll(self):
        return randint(1, self.sides)

您现在有了一个通用的骰子对象,它不需要您在每次提出新的掷骰模式时都添加新方法。例如

d = Die(10);
d.roll() # ---> some value between 1 and 10

添加可选startincrement属性,以便您可以拥有一个 D20,5, 10, ..., 95, 100作为学生的练习。

于 2013-01-19T00:32:29.783 回答
2

这看起来像是一个有趣的 Python 学习程序。其他答案主要涵盖了您的需求,但我只想指出一件事:

如果你想在现实生活中用骰子选择某样东西,方法是给这些东西分配数字,然后掷骰子,并使用骰子中的数字来确定选择了哪个东西。但是,在 Python 中,您可以做的事情比这更简单:您可以告诉 Python “这里有一堆东西,我想要随机选择一个项目”。这样做的功能是:random.choice()

所以对于重击的东西,你可以替换它:

hit_loc = {1 : 'Head',
           2 : 'Left Arm',
           3 : 'Right Arm',
           4 : 'Left Leg',
           5 : 'Right Leg',
           6 : 'Left Hand',
           7 : 'Right Hand',
           8 : 'Left Foot',
           9 : 'Right Foot',
          10 : 'Chest',
          11 : 'Stomach',
          12 : 'Body'}

# two steps to randomly choose a hit location
loc = roll.d12()
part = hit_loc[loc]

有了这个:

locations = ('Head', 'Left Arm', 'Right Arm', 'Left Leg', 'Right Leg',
         'Left Hand', 'Right Hand', 'Left Foot', 'Right Foot',
         'Chest', 'Stomach', 'Body')

# one step to randomly choose a hit location
part = random.choice(locations)

通常,当您想弄清楚如何使用类似 的模块random时,阅读文档确实值得。在 Python 中,总是有一些随代码提供的简洁文档;在 Python 提示符下,您可以这样做:

>> import random
>> help(random)

help()命令将打印出简洁的文档,如果您通读它,您会发现random.choice()random.shuffle()和其他漂亮的东西。

玩得开心!

PS 这是一个有趣的示例程序。不过,这不是类的最佳示例。您在这里使用一个类只是为了获得一个将相关函数组合在一起的命名空间,这没有错,但是当一个类封装一些数据和一些组合在一起的函数时,它会更加有用。这里有一个建议:创建一个Person()类,它有一个名为 的成员变量hit_points,并编写一个.attack()攻击另一个Person实例的方法函数。然后编写一个程序,创建两个Person()实例并让它们互相争斗!

我建议它应该像这样工作:

black_knight = Person()
king_arthur = Person()

while True:
    king_arthur.attack(black_knight)
    if black_knight.hit_points <= 0:
        print "Victory is mine!"
        break
    black_knight.attack(king_arthur)
    if king_arthur.hit_points <= 0:
        print "None shall pass!"
        break

在这个例子中,一个Person实例将关于一个人的信息(命中点)和与一个人一起工作的功能(一个人可以attack另一个人)捆绑在一起。

您可以扩展模型以包括关键命中;实例可以跟踪它收到了Person哪些致命一击;aPerson可能有库存,包括总是会造成致命一击的武器(例如“Vorpal Bunny Teeth”、“Antioch 的圣手榴弹”)等。

事实上,你可以继续添加更多的东西Person来跟踪,以及更多的方法函数,如果你坚持下去,你可能会把整个事情变成一个真正的游戏。

于 2013-01-19T01:30:44.013 回答
1

而不是 hit_loc.values() 上的 for 循环,只需设置loc=hit_loc.

代码还有许多其他问题。这里有几个:

  • 使用函数定义而不是骰子类
  • 缩进对main()的调用
  • 带有数字键的字典可以替换为列表元组

这是对代码第一部分的一种可能的重构:

from functools import partial
from random import randint

d4 = partial(randint, 1, 4)
d6 = partial(randint, 1, 6)
d10 = partial(randint, 0, 10)
d12 = partial(randint, 1, 12)
d20 = partial(randint, 1, 20)
d100 = partial(randint, 0, 99)

def critical_hit_effect():
    locations = ('Head', 'Left Arm', 'Right Arm', 'Left Leg', 'Right Leg',
                 'Left Hand', 'Right Hand', 'Left Foot', 'Right Foot',
                 'Chest', 'Stomach', 'Body')
    roll = d12()
    if roll == 10:
        msg = "You sink your blade into his %s and pierce the heart!"
    elif roll == 11:
        msg = "You slash him across the %s and eviscerate him!"
    elif roll == 12:
        msg = "You shred the enemy's %s to ribbons!"
    else:
        msg = "%s has been severed!"
    print msg % locations[roll-1]
于 2013-01-19T00:27:14.060 回答
1

我认为当您有其他问题时,可以发布另一个问题。由于您更新了您的问题以询问如何做多个骰子,因此我提出了另一个答案。(我怀疑我会为此获得任何积分,但我并不真正关心这些积分。)

有些游戏需要知道骰子是如何产生的。例如,在超级英雄游戏Champions中,有时您需要计算掷出多少个六面骰子。(我想……我已经很久没有玩了。)

无论如何,你的骰子类应该返回骰子掷骰结果的列表或元组,而不是对骰子求和并返回总和。我会告诉你两个。如果元组一令人困惑,请忽略它,直到您对 Python 有更多了解;你现在不需要学习这个。

Python 有一种非常方便的方法来制作列表,称为“列表推导”。如果你用谷歌搜索“列表理解”,你会发现很多页的解释。(这就是为什么我没有得到任何分数的原因...... StackOverflow 并不需要另一个列表推导解释!)基本上,它的工作原理是这样的:

[表达式for变量in序列if条件]

开始寻找中间的“for”部分。这意味着“为序列的每个成员设置一个变量。检查条件,如果为真,则评估表达式并将结果附加到新列表中。”

一个简单的例子:制作一个从 1 到 10 的奇数平方的列表。这将做到:

lst_odd_squares = [x**2 for x in range(10) if (x % 2) == 1]
print(lst_odd_squares) # prints: [1, 9, 25, 49, 81]

以下是如何使用for循环执行此操作:

lst_odd_squares = []  # start with an empty list
for x in range(10):  # just like the for part
    if (x % 2) == 1:  # just like the condition part
        lst_odd_squares.append(x**2)  # append the expression part

“条件”部分是可选的,这个特定的例子可以这样完成:

lst_odd_squares = [x**2 for x in range(1, 10, 2)]

在这里,我们从 1 开始范围,并以 2 为单位,所以我们直接生成我们想要的数字。

表达式中通常包含for变量,但它不必:

counters = [0 for x in range(10)]

这将产生一个包含 10 个整数的列表,最初都设置为 0。然后您可以将它们用作计数器或其他东西。

无论如何,这是制作一个返回列表的骰子滚动类的方法:

import random

class Dice():
    def __init__(self, sides):
        self.sides = sides

    def roll(self, number):
        """return a list of length number, with random values from 1 to self.sides"""
        return [random.randint(1, self.sides) for _ in range(number)]

    def roll_one(self):
        """return a single value from 1 to self.sides"""
        return random.randint(1, self.sides)

d6 = Dice(6)
d10 = Dice(10)

print d6.roll(3)  # roll 3d6
print d10.roll(2)  # roll 2d10

print d10.roll(1)  # roll 1d10 -- returns a list of length 1
print d10.roll_one() # roll a single d10 -- returns a single integer

我稍微改变了你的代码。每次你需要掷不同数量的骰子时,我没有创建一个不同的类实例,而是让.roll()方法函数接受一个number参数。你的方式不一定是错的,但我认为这种方式更容易一些。

通常最好对类名使用大写字母。有一个大多数 Python 人喜欢使用的规则列表,称为“PEP 8”,类名的大写是规则之一:

http://www.python.org/dev/peps/pep-0008/#class-names

(顺便说一句,Learning Python这本书会以良好的 PEP 8 风格为您提供所有示例。因此,如果您从那本书中学习,您将学习 PEP 8 方式。这是该书教给您所有有关 Python 的方式之一。)

我使用单个下划线 ( _) 作为循环变量。这是合法的,有时这样做是为了表明您打算不使用该值。我们需要一个循环变量,但我们实际上并没有使用它,就像counters上面的例子一样。

Python 具有“列表理解”,但没有“元组理解”。所以这里有一种创建元组的方法:首先创建列表,然后从列表中构建一个元组。

lst = [random.randint(1, self.sides) for _ in range(number)]
return tuple(lst)

您可以一口气完成所有操作,而列表没有明确的变量名称:

return tuple([random.randint(1, self.sides) for _ in range(number)])

这有点丑。如果我们要建立列表,为什么不直接返回呢?为什么用了那一次就喂进去tuple()再销毁呢?

Python 提供了一种称为“生成器表达式”的东西,有点像列表推导式。重要的两个区别: 0)您使用括号,而不是方括号;1)它不构建任何东西,它返回一个可以产生一系列值的“迭代器”对象。(当 Python 拉出一系列值时,我们说 Python 正在“迭代”这个对象。)如果你然后将这个“迭代器”传递给tuple(),你可以直接构建一个元组,而无需先构建一个列表,然后再销毁该列表。这里有一个很酷的技巧:您需要使用括号来调用tuple(),并且您可以将这些括号用作生成器表达式所需的括号。

return tuple(random.randint(1, self.sides) for _ in range(number))

同样,如果生成器表达式的东西现在看起来很奇怪或很难,请忽略它。对于很多东西,列表理解是你所需要的。

于 2013-01-21T06:06:44.060 回答
0

这就是我在为我 DM 的 Pathfinder 游戏构建的工具包中处理多个骰子的方式:

import random

def rolldice(number,sides):
    Result = []
    for dice in range(0, number):
        Result.append(random.randint(1,sides))
    return Result

class Dice():
    def __init__(self, number, sides):
        self.sides = sides
        self.number = number

    def roll(self):
        return rolldice(self.number, self.sides)

# 10th level fireball
fireball = Dice(10,6)
damage = fireball.roll()
# all of the rolls (for 4d6 drop lowest, 2d20 take highest, etc)
print (damage)
# total damage
print (sum(damage))
# a d20 roll
d20 = Dice(1,20)
print (sum(d20.roll()))

输出:

[2, 3, 1, 4, 2, 1, 5, 4, 5, 4]
31
13
于 2013-07-14T21:08:38.963 回答
0

我将在这里留下一些我写的漂亮的 Python 元类魔法。这是给你的,未来的代码考古学家,他们有足够的决心从深埋在这个线程中挖掘它。

from random import randint
class MetaRoll(type):
    def __getattr__(cls, dice):
        n,n_faces = [int(part) if part else 1 for part in
                     dice.lower().strip('a').strip('_').split('d')]
        return sum( randint(1,n_faces) for i in range(n) )
class Roll(metaclass=MetaRoll):
    """ A handy RPG styled dice roller.

    The implementation has been enchanted using Python __getattr__ and metaclass
    magic. Beyond that, only the random module is used.
    enchanted using Python __getattr__ and metaclass magic. 

    As a result, any roll is exposed as a public attribute and the dice
    roller that can be used like this:

    ``Roll.a_2D6 + 2``

    Note that the ``a_`` is needed to allow names starting with numbers, and, 
    e.g. ``2D10`` is written as ``a_2D10`` or ``a2D10``.

    Attributes:
        a_3D6 (int): Rolls three six sided dice and returns the sum. This is
                      most boring example with a nice probability distribution.
        D6 (int): If there is just one die, the attribute name does not start
                   with a number. Hence, the ``a_`` prefix can be omitted.
    """
    pass


print(Roll.D6) # Outputs an integer between [1,6]
print(Roll.D20+2) # Note how easy it is to add modifiers
print(Roll.a_3d6-2) # Outputs a sum of random integers from a range [1,16].

附言。当描述你所做的事情比编写代码需要更长的时间时,你知道你是一个向导。

于 2021-01-26T11:28:18.123 回答