如何在Python中为游戏制作选择性RNG?

时间:2010-08-20 21:34:12

标签: python random

这几乎肯定是一个非常新手的问题,但由于我是一个完整的新手,我对此很好。

简单地说,我想知道如何在一个简单的游戏中制作一个战利品系统,当你达到某个目标时,你有机会获得某些物体比其他物体更多。如果有任何开源python游戏有这个,请转介给我们。

以下是我知道该怎么做:给出样本[A,B,C,D,E,F],选择3项。

这非常简单易行,但是,当我希望从样本中选择某些东西时,我会做什么比其他人更频繁地选择,即:给定样本[A,B,C,D,E,F]选择3,没有重复,但在30%的时间选择A,B 25%,C 20%,D 15%,E 5%,F 5%。

或者,甚至可能更好,对所选数量没有限制(或范围限制,例如3-5项),但是样本中的每个项目都以不同的速率选择而不重复,这样我可以做20%,B 20%,C 15%,D 10%,E 2%,F 1%。

希望这是有道理的。

5 个答案:

答案 0 :(得分:1)

这是一种简单,懒惰的方式。

给出(item,weight)对的列表。

loot = [ (A,20), (B,20), (C,15), (D,10), (E,2), (F,1) ]

注意,权重不必特别添加到任何内容,它们只需要是整数。

一次性准备步骤。

choices = []
for item, weight in loot:
    choices.extend( [item]*weight )

现在它只是random.choice( choices )

答案 1 :(得分:1)

当你把这个问题描述为“非常新手”时,你把我扔了一点。它不像看起来那么简单,取决于你想要的行为类型。如果你不介意一个幸运的玩家可以赢得所有物品而且一个不幸的玩家可以一无所获,那么BarsMonster的回答是很好的。

如果你想总是选择一定数量的物品,那么我会选择S.Lott选择一个物品的方法,但是反复使用它。如果您不想允许多次选择相同的项目,则必须从loot中删除所选项目,然后在选择之间重建choices。例如(非常粗糙的伪代码):

items_won = random.randint(3, 5)
for i in range(items_won):
    item_won = s_lott_weighted_selection()
    inventory.add(item_won)
    loot.remove(item_won)

答案 2 :(得分:0)

伪代码:

if(random()<0.2)addloot(a);
if(random()<0.15)addloot(b);
if(random()<0.1)addloot(c);
if(random()<0.02)addloot(d);
if(random()<0.01)addloot(e);

其中random是从0到1的随机数。这就是它在所有MMORPG中的工作方式。

答案 3 :(得分:0)

如果你想要一个平滑的可能性渐变而没有制作一个庞大的样本列表,这是一个很好的配方:

class WeightedRandom(random.Random):
    """All numbers are random, but some are more random than others.

    Initialise with a weighting curve gamma. gamma=1 is unweighted, >1 returns
    the lower numbers more often, <1 prefers the higher numbers. 
    """
    def __init__(self, gamma):
        self.gamma= gamma # 1 is unweighted, >1 pushes values downwards
        random.Random.__init__(self)
    def random(self):
        return random.Random.random(self)**self.gamma

    # Override the standard sample method, whose pool-based 'optimisation' cocks
    # up weighted sampling. We know result set is small, so no need for dict
    # lookup either.
    #
    def sample(self, population, k):
        if k>=len(population):
            return population
        indexes= []
        for _ in range(k):
            while True:
                index= int(self.random()*len(population))
                if index not in indexes:
                    break
            indexes.append(index)
        return [population[index] for index in indexes]

>>> r= WeightedRandom(0.5)
>>> r.sample(range(100), 3)
[86, 98, 81]

答案 4 :(得分:0)

S.Lott加权选择的替代方案。

警告 - 未经测试的代码。

import random

def weighted_selection(weights):    
    """returns an index corresponding to the weight of the item chosen"""
    total_sum = sum(weights)
    rnd = random.uniform(0, total_sum)
    cumulative_sum = 0
    for (idx, weight) in enumerate(weights):
        if rnd <= cumulative_sum + weight:
            return idx
        cumulative_sum += weight
    assert(0) # should never get here

weights = [30, 25, 20, 15, 5, 5]
# example of choosing 1 - will return value from 0 to 5
choice = weighted_selection(weights)

# example of choosing 3 such values without repeats
choices = []
for n in range(3):
    new_choice = weighted_selection(weights)
    del weights[new_choice]
    choices.append(new_choice)

您可能希望在某种包装中包含选择 - 不替换代码,以确保您所做的唯一选择的数量永远不会超过可用选项的数量。