模拟一场大战

时间:2013-06-05 08:04:10

标签: c# algorithm

我必须模拟两个玩家之间的战斗。它可以持续一到六轮。攻击者可以拥有13种不同类型的宇宙飞船,后卫 - 另外9种类型的防御结构。事情是我要将模拟限制在每侧1kk单位,所以它会变得非常大。

每个单位都将成为以下类的实例

class Unit()
{
    UInt16 id; // unit type
    Int32 structuralIntegrity;
    Int16 shieldPower;

    public Unit(UInt16 unitType, Int16 playerId)
    {
        id = unitType;
        switch (playerId)
            {
                case 0: {structuralIntegrity = player0BaseStructuralIntegrity[id]; shieldPower = player0BaseshieldPower[id];}
                case 1: {structuralIntegrity = player1BaseStructuralIntegrity[id]; shieldPower = player1BaseshieldPower[id];}
            }
    }
};

不变数值的数组。

player1technolgies

  • 盔甲技术
  • shield tech
  • 武器技术

player2technolgies

  • 盔甲技术
  • shield tech
  • 武器技术

player1BaseStructuralIntegrity

等于默认* armor tech

等等......

然后我会用每个玩家单位传播两个列表。

一轮就是这样:

  1. 选择随机单元//实际上,如果它是随机的,我认为不重要
  2. 选择随机目标
  3. 如果武器威力低于目标护盾的1%,则不会造成伤害
  4. 目标盾牌吸收伤害,其余部分达到目标结构完整性
  5. 如果目标的结构完整性低于其初始值的30%,则其具有1-structuralIntegrity / baseStructuralIntegrity爆炸的可能性
  6. 检查快速火灾的概率,如果碰到第2步
  7. 转到第1步,直到所有单位攻击|注意!被毁坏的船只 - 结构完整性低于1仍然可以受到攻击。编辑:他们也可以攻击这一轮
  8. 对对手重复步骤1-7。
  9. 移除被毁坏的船只
  10. 恢复盾牌
  11. 战斗持续六轮或直到一方被击败。

    让我们考虑一支由100架轰炸机和200枚火箭发射器组成的攻击舰队。轰炸机在攻击火箭发射器后有95%的几率再次射击。所以每个轰炸机平均会攻击96次,给我们9600次攻击。假设后卫很幸运,一个火箭发射器幸免于难。他还摧毁了10架轰炸机。现在我们有90架轰炸机攻击一个火箭发射器,给我们另外8640次射击。想想10万轰炸机和200k火箭发射器。

    您对如何改进此模拟(性能)有任何建议吗?我应该多少次运行它以获得可信的平均结果?

    更新

    我想我可能会坚持我的模拟,因为即使你找到了一个数学解决方案,由于我目前的教育水平,我也不会理解它。

    有人要求提供更多细节。

    对应技术的每个级别都将初始值提高了10%,但它对于模拟并不重要,因此假设两个玩家都拥有0技术。让我们来看看1艘巡洋舰与2枚导弹发射器+ 1枚重型激光器的攻击舰队。 Cruiser拥有2700个结构完整性,50个盾牌和400个武器。我会把它写成2700:50:400

    • Cruiser 2700:50:400 x1
      vs
    • Missile Launcher 200:20:80 x2
    • 重型激光800:100:250 x1

    导弹发射器和重型激光器没有快速射击。巡洋舰对重型激光器有0次快速射击,10次对抗导弹发射器,在攻击导弹发射器后再次发射(10-1)/ 10 = 0.90 概率。

    可能的结果如下:

    第1轮

    攻击者向后卫开火

    巡洋舰以27:50:400的速度向Missile Laucher发射200:20:80;结果是导弹Laucher与-180:0:80

    快速射击:

    • 巡洋舰对导弹发射器迅速射击。
    • 骰子为0.62,与0.90相比:Cruiser再次出手。

    巡洋舰以27:50:400的速度向Missile Laucher发射200:20:80;结果是导弹启动器-180:0:80

    快速射击:

    • 巡洋舰对导弹发射器迅速射击。
    • 骰子为0.09,与0.90相比:巡洋舰得到了另一次射门。

    巡洋舰以2700:50:400向导弹发射器发射-180:0:80;结果是导弹发射器与-580:0:80

    快速射击:

    • 巡洋舰对导弹发射器迅速射击。
    • 骰子为0.83,与0.90相比:巡洋舰得到了另一次射门。

    Cruiser 2700:50:400在重激光下发射800:100:250;结果是重激光,500:0:250

    快速射击:

    • Cruiser并没有对重型激光器进行快速射击。

    后卫向攻击者开火

    导弹Laucher以-580:0:80的速度在Cruiser以2700:50:400发射;结果是Cruiser与2670:0:400

    导弹Laucher -180:0:80在Cruiser以2670:0:400发射;结果是Cruiser与2590:0:400

    500:0:250的重型激光在Cruiser以2590:0:400发射;结果是巡洋舰2340:0:400

    移除船只并恢复盾牌

    巡洋舰仍然具有完整性,恢复其盾牌。

    导弹Laucher失去了所有的完整性,将其从战斗中移除。

    导弹Laucher失去了所有的完整性,将其从战斗中移除。

    重型激光仍然具有完整性,可以恢复其盾牌。

    第2轮

    攻击者向后卫开火

    Cruiser 2340:50:400在重激光下发射500:100:250;结果是重激光,200:0:250

    • 爆炸概率为75.00%(1-200 / 800):骰子值为0.30,而0.75:单位爆炸。

    结果是重激光,9:0:250

    快速射击:

    • Cruiser并没有对重型激光器进行快速射击。

    后卫向攻击者开火

    重型激光9:0:250在巡洋舰上以2340:50:400发射;结果是巡洋舰2140:0:400

    移除船只并恢复盾牌。

    巡洋舰仍然具有完整性,恢复其盾牌。

    重激光失去了所有的完整性,将其从战斗中移除。

    战斗结束后,攻击者赢了两轮。

2 个答案:

答案 0 :(得分:3)

对于这样的单位数量,我认为采用(某种)统计的,一般化的方法是有效的。

只需总结给定类型的所有单位数量,保持计数,然后计算总伤害,总防御,移除被伤害所摧毁的对手单位数量作为总防御的百分比。

我相信这是Travian或其他在线策略游戏所使用的方法。对于这么大的数字,没有有效的方法。

特殊情况

  

如果目标的结构完整性低于其初始值的30%   价值,它有概率   1-structuralIntegrity / baseStructuralIntegrity爆炸

我相信您可以使用高斯分布来确定额外爆炸单位的数量。 σ值越大,破坏概率越大。

其他方法可能是破坏剩余容器的百分比。百分之几?你的选择。

  

快速射击

既然你没有定义快速射击,我真的不能建议。但我建议增加一个特殊的战斗阶段,考虑到这一点。您还可以通过快速射击概率确定的因子简​​单地增加伤害。

答案 1 :(得分:1)

我认为你的模拟应该试图代表每个单独独立和同时行动。如果是这样,您将需要非常小心地实现每轮的模拟。你不希望玩家1能够通过削弱或摧毁对手的单位来获得优势,这样他们就不会因为他们的回合是第二次而进行报复。因此,在两个玩家完成行动后,需要存储和应用所有盾牌的更新以及完整性和爆炸。

当您运行模拟时,您将得到一个或另一个玩家赢得该战斗的结果。通过运行任意次数,并为玩家1计算胜利/(胜利+损失),您将得到玩家1在起始情况下获胜的百分比。这类似于掷硬币来确定它是否是一个公平的硬币(见维基百科)。

您还可以计算错误的估算值,并使用它来确定置信区间。这将为您提供值范围,其中包含玩家1以任意百分比的时间赢得场景的真实概率(例如95%)。如果你想非常自信范围包含真正的值并且误差很小,那么你将需要进行很长时间的模拟。如果战斗是均匀匹配而不是更片面的话,你还需要更多的模拟。

根据维基百科关于抛硬币的文章,我做了一些粗略的计算。 如果您对95%置信区间感到满意,并希望最大误差为0.01,那么如果获胜概率为50%,则需要10000次测试。如果它只有25%,那么你将需要大约1350.如果它只有10%那么你只需要312.如果你想要99%的置信区间,那么你将需要大约3倍的测试。

修改

我认为解决这个问题的解决方案将非常困难。我打算建议你简化规则,使其更容易处理。

规则3 - 要求最小武器力量攻击特定盾牌不太可能对是否对单位造成任何结构性伤害产生太大影响,除非一方超过另一方100:1。如果没有这个规则,任何少量的伤害都会在这一轮结束时恢复盾牌时得到治愈。我建议无视这条规则。

规则6 - 我认为如果你有100个爆破,有10%的快速射击几率,这是相同的(从对敌人的观点来说是平均伤害)到拥有110个没有快速射击的爆破。因此,要计算快速射击的效果,只需增加快速射击百分比的平均伤害。

规则5--这使情况变得非常复杂,因为现在结构完整性值的方差显着影响了有多少单位存活到下一轮。如果没有这个规则,你可以使用每个单位的平均伤害来估计对敌人造成的伤害量,这与给出的其他建议相似。如果你想简化这个,我认为它类似于85%的时间内结构完整性降低30%的建模单元,这可以将所有单元的完整性降低25.5%。

通过这样做,你将基本上遵循Dariusz的方法

Eg if you have 
Side A: 100k bombers and 200k rocket launchers 
Side B: 130k bombers and 150k rocket launchers

Expected total damage side A (ETDa)
ETDa = 100k*BomberDamage*(1+rapidfire%bomber) + 200k*RLDamage*(1+rapidfire%rocketlauncher)

This will be spread evenly between the units in side B based upon their percentage of the total number of units present.

Expected total damage to bombers on side B (ETDBombersB)
ETDBombersB = 130k/280k*ETDa
Similarly ETDRocketLaunchersB = 150k/280k*ETDa

Structural damage to bombers on side B is reduced by the amount of the bombers shields
ESDBombersB = ETDBombersB - 130k*BombersShields
Similarly ESDRocketLaunchersB = ETDRocketLaunchersB - 150k*RocketLaunchersShields

Rather than have partly damaged units at the end of a round, I suggest you treat all existing units as fully healed, and apply the damage to units in turn until it is all used up. As above I am reducing the  structural integrity by 25.5% to model the average chance of explosion.
% of bombers destroyed = ESDBombersB / StructuralIntegrityBombers*(1-0.255)*130k
% of rocket launchers destroyed = ESDRocketLauncherB / StructuralIntegrityRL*(1-0.255)*150k

另请注意,通过中心极限定理,当您在模拟中拥有更多单位时,您更有可能获得平均结果,一个单位所造成的极端伤害将倾向于被低额抵消别人做的。即当滚动一次时,它更有可能在骰子上获得极值1或6,而在滚动3次时总共获得3或18。因此,这可能使统计学上的捏造分析仍然相当有用。

但是如果你试图模拟现有游戏中的情况,那么就会指定规则,你需要花时间去处理最初描述的蒙特卡罗模拟,以获得最准确的结果。