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 の数字と対になっています。影響を受ける部分に応じて、3 つの出力メッセージが考えられます。私の問題は、特定の部分ではなく、値のリスト全体が返されることです。ここで何が間違っていますか?

はい、私はこれが超オタクであることを知っています。はい、出力が不十分なのはわかっていますが、それはすべてプレースホルダーです。

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

dict のすべての値をループします。

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

接線...

dice クラスのより単純なバージョンは次のようになります。

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

startオプションと属性を追加して、学生への演習として左incrementを生成する D20 を持つことができるようにします。5, 10, ..., 95, 100

于 2013-01-19T00:32:29.783 に答える
2

これは、Python を学習するための楽しいプログラムのようです。他の答えはあなたが必要とするものをほとんどカバーしていますが、私はただ一つのことを指摘したかったのです:

サイコロを使って実生活で何かを選択しようとしている場合、その方法は、物に数字を割り当ててからサイコロを転がし、サイコロからの数字を使用して、どのものが選択されたかを把握することです. しかし、Python では、それよりも簡単に行うことができます。Python に「ここにはたくさんのものがあります。ランダムに 1 つの項目を選択したい」と伝えることができます。この関数は次のとおりです。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()、およびその他の気の利いたものが見つかります。

Pythonを楽しんでください!

PS これは楽しいサンプル プログラムです。ただし、これはクラスの最良の例ではありません。ここでは、関連する関数をグループ化する名前空間を取得するためだけにクラスを使用していますが、これは間違いではありませんが、いくつかのデータと一緒に機能するいくつかの関数をカプセル化すると、クラスはさらに便利になります。ここに提案があります:Person()というメンバー変数を持つクラスを作成し、別のインスタンスを攻撃hit_pointsするメソッド関数を記述します。次に、2 つのインスタンスを作成し、それらを互いに戦わせるプログラムを作成します。.attack()PersonPerson()

次のように動作することをお勧めします。

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」、「Holy Hand Grenade of Antioch」など) などの在庫を持つことができます。

実際、Person追跡するものやメソッド関数をさらに追加し続けることができます。それを続ければ、すべてを実際のゲームに変えることができます。

于 2013-01-19T01:30:44.013 に答える
1

別の質問がある場合は、別の質問を投稿しても問題ないと思います。複数のサイコロを行う方法について質問するように質問を更新したので、別の答えを出しています。(これで点数が取れるとは思えませんが、点数はあまり気にしません。)

一部のゲームでは、サイコロがどのように出たかを知る必要があります。たとえば、スーパー ヒーロー ゲームのChampionsでは、6 面ダイスの出目数を数える必要がある場合があります。(私がプレイするのは久しぶりだと思います。)

とにかく、サイコロを合計して合計を返す代わりに、サイコロ クラスはサイコロの結果のリストまたはタプルを返す必要があります。両方見せます。タプルが紛らわしい場合は、Python について詳しく知るまで無視してください。あなたは今これを学ぶ必要はありません。

Python には、「リスト内包表記」と呼ばれるリストを作成する非常に便利な方法があります。「リストの理解」をグーグルで検索すると、多くの説明ページが見つかります。(これが、私がこれについて何のポイントも得ていない理由です... StackOverflowは、別のリスト内包表記の説明を本当に必要としません!)基本的に、それは次のように機能します:

[for変数inの順序if条件]

真ん中の「for」部分を見始めます。これは、「シーケンスの各メンバーに変数を設定します。条件を確認し、真であれば式を評価し、結果を新しいリストに追加する」ことを意味します。

簡単な例: 1 から 10 までの奇数の 2 乗のリストを作成します。

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)]

これにより、最初はすべて0に設定された10個の整数のリストが生成されます。その後、それらをカウンターなどとして使用できます。

とにかく、リストを返すサイコロを振るクラスを作成する方法は次のとおりです。

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引数を取るようにしました。あなたのやり方が必ずしも間違っているわけではありませんが、この方法の方が少し簡単だと思います。

通常、クラス名には大文字を使用することをお勧めします。「PEP 8」と呼ばれる、ほとんどの Python 関係者が好んで使用する規則のリストがあり、クラス名を大文字にすることはその規則の 1 つです。

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

(ちなみに、Learning Python book では、すべての例が適切な PEP 8 スタイルで提供されています。したがって、その本から学べば、PEP 8 の方法を学ぶことができます。これは、この本が Python についてすべてを教えてくれる方法の 1 つです。)

_ループ変数としてアンダースコア ( ) を 1 つ使用しました。これは合法であり、その値を使用しないという意図を示す方法として行われることがあります。countersループ変数が必要ですが、上記の例のように実際には使用しません。

Python には「リスト内包表記」がありますが、「タプル内包表記」はありません。そこで、タプルを作成する 1 つの方法を次に示します。最初にリストを作成し、次にリストからタプルを作成します。

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 は、リスト内包表記のような「ジェネレーター式」と呼ばれるものを提供します。重要な 2 つの違い: 0) 角括弧ではなく括弧を使用します。1) 何も構築せず、一連の値を生成できる「反復子」オブジェクトを返します。(Python が一連の値を引き出すとき、Python がこのオブジェクトを「反復」していると言います。) この「反復子」を に渡すとtuple()、最初にリストを作成してからリストを破棄することなく、直接タプルを作成できます。ここでのクールなトリック: を呼び出すtuple()には括弧を使用する必要があり、それらの括弧をジェネレータ式に必要なものとして使用できます。

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

繰り返しますが、ジェネレータ式が今、奇妙で難しいと思われる場合は、無視してください。リスト内包表記は、非常に多くのものに必要なすべてです。

于 2013-01-21T06:06:44.060 に答える
1

hit_loc.values() に対する for ループの代わりに、単に set loc=hit_loc.

コードには他にも多くの問題があります。ここにいくつかあります:

  • サイコロのクラスの代わりに関数定義を使用する
  • main()の呼び出しをインデントする
  • 数字キーを持つ辞書は、リストまたはタプルに置き換えることができます

コードの最初の部分の可能なリファクタリングの 1 つを次に示します。

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 に答える
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 に答える