Pythonic的百分比方式

时间:2015-12-10 15:37:39

标签: python

我目前正在尝试创建一种随机获得某个项目(在游戏中表示)的方法,例如一个项目的20%,或50%的百分比甚至1%。我尝试使用下面描述的代码执行此操作:

from random import randint

def Break():
    print(".")

def Treasure():

    Gen = randint(1,100)
    if Gen <= 10:
        print("10%")
        Break()

    Gen = randint(1,100)
    if Gen <= 10:
        print("10%")
        Break()

    Gen = randint(1,100)
    if Gen <= 10:
        print("10%")
        Break()

    Gen = randint(1,100)
    if Gen <= 10:
        print("10%")
        Break()

    Gen = randint(1,100)
    if Gen <= 10:
        print("10%")
        Break()

这种代码方法很有效,问题是即使选择了这里的百分比并且调用了Break(),仍然有可能列出超过一个百分比 所以,如果它说80%那么Break() 它也可以列出50%然后Break()一段时间。

所以我的问题是,我怎么能做到以下几点:

  • 更高效的代码
  • 使百分比仅调用ONE然后调用Break()
  • 确定百分比的方式,例如50%的一半机会。

测试代码:(已编辑)

if gen <= 10:
    print("10%")
elif gen <= 20:
    print("20%")
elif gen <= 30:
    print("30%")
elif gen <= 40:
    print("30%")
elif gen <= 50:
    print("50%")
elif gen <= 60:
    print("60%")
elif gen <= 70:
    print("70%")
elif gen <= 80:
    print("80%")
elif gen <= 90:
    print("90%")

这不是最有可能的90%,反过来最少10%吗?

2 个答案:

答案 0 :(得分:2)

首先要做的几件事:

  • 资本化很重要; breakBreak是两件不同的事情

  • break是一个关键字,而不是一个函数;称之为break,而不是break()

  • break是退出循环,但不在循环中;也许你的意思是return而不是?

你级联案件的方式是减少百分比:

gen = randint(1,100)
if gen <= 10:
    return "10% (#1)"

gen = randint(1,100)
if gen <= 10:
    return "10% (#2)"        # 10% of 90% == 9%

gen = randint(1,100)
if gen <= 10:
    return "10% (#3)"        # 10% of 81% == 8.1%

对于正确的值,您需要累积测试,例如

gen = randint(1, 100)
if gen <= 10:
    return "10% (#1)"
elif gen <= 20:
    return "10% (#2)"
elif gen <= 30:
    return "10% (#3)"

它可能会节省很多恶化,将其包装在类中,如

from bisect import bisect    # fast binary search
from random import random

class RandomItemGenerator:
    def __init__(self, items=None, probs=None):
        # start with no items
        self.items       = []
        self.total       = 0.
        self.breakpoints = []
        # add any initial items
        if items is not None:
            for item, prob in zip(items, probs):
                self.add_item(item, prob)

    def add_item(self, item, prob):
        self.items.append(item)
        self.total += prob
        self.breakpoints.append(self.total)

    def __call__(self):
        if self.items:
            value = random() * self.total
            index = bisect(self.breakpoints, value)
            return self.items[index]
        else:
            raise ValueError("you haven't got any items yet")

然后您的代码看起来像

make_treasure = RandomItemGenerator()
make_treasure.add_item("sword",    80)
make_treasure.add_item("sword +1", 19)
make_treasure.add_item("ring +2",   1)

我们可以测试

from collections import Counter

# generate 10,000 items
test = Counter(make_treasure() for i in range(10000))

# check number of each item generated
print(test.most_common())

给出类似

的内容
[('sword', 8002), ('sword +1', 1887), ('ring +2', 111)]

编辑:返回函数的示例:

def sword_fn():
    # your stuff goes here

def dagger_fn():
    # your stuff goes here

def wand_fn():
    # your stuff goes here

make_fn = RandomItemGenerator()
make_fn.add_item(sword_fn,  80)
make_fn.add_item(dagger_fn, 19)
make_fn.add_item(wand_fn,    1)

which = make_fn()      # pick a function
which()                # run the function

我的上一条评论使用了等效的简写,例如

make_fn = RandomItemGenerator([sword_fn, dagger_fn, wand_fn], [80, 19, 1])

与上面的四行完全相同,我创建实例然后添加项目。

答案 1 :(得分:0)

你可以尝试这样的事情:

def Break():
    print(".")

def FindAnotherName():
    Gen = randint(1,100)
    if Gen <= 10:
        print("10%")
        Break()
        return True
    else:
        return False

def Treasure():

    i = 0
    finished = False
    while (i < 5 && finished == False):
        finished = FinAnotherName()
        i = i + 1