【问题标题】:Designing a probability table设计概率表
【发布时间】:2013-04-07 16:54:29
【问题描述】:

我正在制作一个游戏原型,其中用户点击一个按钮并随机出现一个项目。

    Object A = 10% chance of discovery
    Object B = 15% chance of discovery
    Object C = 12% chance of discovery etc... totalling 100%

随着游戏的进行,用户可能会增加找到某些对象的几率,例如增加Object A's probability from 10% to 15%

我想知道是否有人可以建议一种有效的设计或函数来运行概率并返回一个对象。

起初我考虑只是随机生成一个从 1 到 100 的数字,然后使用一系列 if/else if 语句,但这似乎很乏味并且对于更新项目概率不是很有可塑性。另外,我应该将概率存储在 NSDictionary 中吗?

任何建议表示赞赏。我正在用Objective-C编写。谢谢

【问题讨论】:

    标签: objective-c probability


    【解决方案1】:

    最简单的设计是以这种方式拥有NSMutableDictionary(可变,因为您需要更新它)

    NSMutableDictionary * probabilityTable = @{
        @"objectA" : @0.10, // the @ converts the number to a `NSNumber` (NSDictionary accepts only objects)
        @"objectB" : @0.15,
        @"objectC" : @0.12
    };
    

    等等。

    然后为了检索一个概率

    probabilityTable[@"objectA"];
    

    为了更新它

    probabilityTable[@"objectA"] = @0.16;
    

    编辑

    为了额外的乐趣,您可以将对象本身用作字典键。为此,请使这些对象成为 MyObject 类的子类(我假设您将为不同的对象类别提供不同的类)。此类必须符合NSCopying 协议并实现isEqualhash 方法。

    有关如何遵守NSCopying 的更多信息:Implementing NSCopying

    有关如何实现isEqualhash 的更多信息:Best practices for overriding isEqual: and hash

    完成后,您使用对象本身来检索其概率并更新它,将上述代码转换为类似

    // initializing 
    NSMutableDictionary * probabilityTable = @{
        objectA : @0.10,
        objectB : @0.15,
        objectC : @0.12
    };
    
    // retrieving
    probabilityTable[objectA];
    
    // updating
    probabilityTable[objectA] = @0.16;
    

    编辑 2

    如果你想变得花哨,你也可以写一个断言来检查概率之和是否总是 1。检查看起来像

    float sum = 0;
    for (NSNumber * n in probabilityTable.allValues) {
        sum += n.floatValue;
    }
    NSAssert(sum == 1.0, @"Sum of probabilities must be 1.0");
    

    你可以很容易地想到将这个检查捆绑在一个方法中,每次修改概率表时调用它

    【讨论】:

    • 以编程方式有意义,我看到的唯一问题是更新,这还需要您更新所有其他对象的概率,以便总数仍然等于 100%,并且这些对象的概率变化是加权的正确。
    • 这是问题的内在原因,除非您提供一些智能默认值来更新其他值,否则“系统”将不知道如何平衡更新。您可能决定有一些自动行为(重新分配所有其他对象之间的差异)并包装提供此类行为的 update 调用。
    【解决方案2】:

    这些对象是唯一的吗?如果是这样,请创建一个包含所有对象的袋子

    NSArray *legendarySwords=....
    

    然后从该数组中删除任意元素。

    如果对象不是唯一的——你有一台自动售货机,可以根据玩家的承受能力分发每个对象——带上你的数组

    @[ 0.10, 0.15, 0.12 ...]
    

    并构造累积概率

    @[ 0.10, 0.25, 0.37 .... 1]
    

    现在,生成一个随机数 [0,1];数组中的第一个元素

    但这将是维护的痛苦。更好的解决方案是用相对概率填充一堆对象:

    NSThing *canteen=[[NSThing alloc] initWithCost: 10 abundance: kCommon];
    
    NSThing *magicArrow=[[NSThing alloc] initWithCost: 100 abundance: kRare];
    
    NSInventory *inventory=[NSInventory inventoryFor: @[canteen, magicArrow, ...];
    

    然后从库存中构建您的概率数组。需要制作箭头 kVeryRare 以保持游戏平衡?您只需要更改magicArrow,您的概率数组就会自动更新。否则,你最终肯定会遇到问题。

    【讨论】:

      【解决方案3】:

      我遇到了和你一样的问题,偶然发现了这个很有帮助的link

      链接中的代码是用 ActionScript 3 编写的,所以这是我的 Objective-c 转换代码。我

      - (MyObject *)getWeightedRandomObject
      {
          int weightsCounter =  0; // sum of the current weights added
      
          // get the total weight of all the obstacles
          for (MyObject* object in objectsArray)
          {
              weightsCounter += object.spawnWeight;
          }
      
          int random = arc4random_uniform(weightsCounter) + 1; // random int from 1 to total weight inclusive.
          weightsCounter = 0;
      
          // pick the weighted object
          for (MyObject* object in objectsArray)
          {
              weightsCounter += object.spawnWeight;
      
              if (random < weightsCounter)
              {
                  return object;
              }
          }
      
          return [objectsArray lastObject]; // only the last object will be remaining at this point
      }
      

      为了确定该算法有效,我创建了 spawnWeight 分别为 60、30 和 10 的三个对象,并调用了该方法 1000 次。我进行了大约六次测试,每次生成百分比几乎都是正确的。您可能希望稍微自定义上述代码以满足您的需求,但算法的逻辑已经过测试并且可以正常工作。

      享受吧!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-11
        • 1970-01-01
        • 1970-01-01
        • 2011-09-30
        • 1970-01-01
        相关资源
        最近更新 更多