Simulating 1 Battleship vs. 10 Rocket Launchers

    • Simulating 1 Battleship vs. 10 Rocket Launchers

      Hello,

      I am currently coding my own combat simulator. How thrilling really! Unfortunately, there's something I must have misunderstood. If we consider 1 attacking Battleship (techs: 0/0/0) against 10 Rocket Launchers (also 0/0/0), both SpeedSim and TrashSim say the combat is over after either 4 or 5 rounds, and the defender wins. However that's not what I get with my current simulator ;(

      So let's sit down and see where my mistake is.

      A Battleship has a weapon power of 1.000, a shield power of 200 and an armour of 6.000. Rocket Launchers have a weapon power of 80, a shield power of 20 and an armor of 200. So when a Battleship hits a Rocket Launcher, it will be dead at the end of the round with a 100% chance.

      At the first round, the attacking Battleship hits a Rocket Launcher, that will die as a result at the end of the round.

      The first 2 defending Rocket Launchers will weaken the Battleship's shield (decreasing it from 200 to 200 - 80 - 80 = 40), the 3rd Rocket Launcher will destroy the shield and cause 40 (80 minus the remaining 40) damage to the Battleship's armor. And then the last 7 Rocket Launchers will cause 560 = 7 x 80 damage to the Battleship. At the end of the first round, the Battleship took 560 + 40 = 600 damage to its armor, which is exactly 10% of its total armor, so it survives while one of the 10 Rocket Launchers dies.

      • At the second round, the Battleship takes 9 x 80 - 200 (shield) = 520 additional damage to its armor, which is now damaged 18.7%. It survives, while another Rocket Launcher has died (8 remaining).
      • At the third round, the the Battleship takes 8 x 80 - 200 (shield) = 440 additional damage to its armor, which is now damaged 26%. It survives, while another Rocket Launcher has died (7 remaining).
      • At the fourth round, the the Battleship takes 7 x 80 - 200 (shield) = 360 additional damage to its armor, which is now damaged 32%. It may survive, while another Rocket Launcher has died (6 remaining).
      • At the fifth round, the the Battleship takes 6 x 80 - 200 (shield) = 280 additional damage to its armor, which is now damaged 36.7%. It may survive, while another Rocket Launcher has died (5 remaining).
      • At the sixth round, the the Battleship takes 5 x 80 - 200 (shield) = 200 additional damage to its armor, which is now damaged 40%. It may survive, while another Rocket Launcher has died (4 remaining).


      So you see, there's a 68% x 63.3% x 60% = 25,84% chance that the Battleship survives the entire combat according to my (likely wrong) calculations. TrashSim and SpeedSim say the Battleship never reaches the sixth round, so I'm confused. Could somebody see what's wrong ?

      Thanks a lot...
    • As i know, the mistake stays in the fact that every time the battleship is hit and his armor goes under 70%, she has chance to explode (even if will be removed at the end of the round anyways). So it's much more probabile that the RLs will destroy it.

      Check if this helps you here. Now i'm at bed and i don't want to do the calculations. If you need i'll show it tomorrow.
      #6 Retro server - Fra [N O X]
      #5 Andromeda.us - Fra.. [Dynamic]
    • NoMoreAngel wrote:

      Haven't calculated it, but it might be because the destroyed ships/defences get removed after the round, not in the round. So in Round 1 there are firing 10 RL, in 2 9, in 3 8 and so on.
      Hello, thank you for your reply. I think I took that into account already, the Battleship is hit 10 times in the first round in my calculations, 9 in round 2, etc.

      Canarefr wrote:

      As i know, the mistake stays in the fact that every time the battleship is hit and his armor goes under 70%, she has chance to explode (even if will be removed at the end of the round anyways). So it's much more probabile that the RLs will destroy it.

      Check if this helps you here. Now i'm at bed and i don't want to do the calculations. If you need i'll show it tomorrow.
      Hello, thank you for your reply. Are you saying that, after round 5 for example, the Battleship will go through six explosion checks, and not just one ? And 5 more after round 6 ?
    • Uhm after some calcs i'm not very sure about what i said. The BS in that way should explode too early. I'm going to do some researches and find out the problem. Sorry for the mistake.

      EDIT:
      Well, with this example it seems to work.

      With your method, the chance to survive the 4th round is 70%, then 49% for the 5th round and 34,4% for the last one.

      Instead with my theory we have the following chances:
      49% to survive the 4th round. (2 RL have 30% chance to destroy the BS)
      5,7% to survive the 5th round. (6 more RL have 30% chance to destroy the BS, for a total of 8 )
      0,96% to survive the fight.

      This is a lot more in line with the results that you have from the simulators.

      For now check if these calcs have sense.

      Anyways it's weird because i'm pretty sure that I can create another situation, with bigger number of ships, where it's clear that all this is wrong.
      #6 Retro server - Fra [N O X]
      #5 Andromeda.us - Fra.. [Dynamic]

      The post was edited 2 times, last by Canarefr ().

    • Canarefr wrote:

      Canarefr wrote:

      Anyways it's weird because i'm pretty sure that I can create another situation, with bigger number of ships, where it's clear that all this is wrong.
      Forget this, my idea was not good. The battle basically works like i said above.
      Thank you very much for your input. I gave it some thought and everything makes sense. It's funny because my problem was essentially covered by the English FAQ, but since I come from the French community, I read the French FAQ. And this piece of information (= for every hit that is absorbed by the shield or the hull, make an explosion check) is entirely missing there.

      Anyways, problem solved. :)
    • True, today i wanted to check my remembrances but honestly i couldn't find it anywhere. So don't take all i say like the Bible, it's very long time that i don't afford such technical discussions and my memory is not the best.
      But if you ever need tips feel free to PM (i don't check this board very intensively); when i can, i'm glad to help. For example common mistakes with the creation of simulators come from bouncing effect or changes in the firing order using the ACS.

      Anyways i wish you good luck with your project.
      #6 Retro server - Fra [N O X]
      #5 Andromeda.us - Fra.. [Dynamic]
    • Unfortunately, my C++ code still doesn't always agree with TrashSim. I looked it over and over and I can't seem to find the problem, so I'm going to copy/paste my little implementation here. Could anyone find out what's wrong?

      First the for loop for the 6 rounds of the combat. Pretty straightforward.

      C Source Code

      1. for (quint8 j = 0; j < 6; ++j)
      2. {
      3. p1->attack(p2);
      4. p2->attack(p1);
      5. p1->repare();
      6. p2->repare();
      7. if (p1->fleet.size() < 1u || p2->fleet.size() < 1u)
      8. break;
      9. }
      Display All

      Here p1 and p2 are two smart pointers of class Player. Here's what Player::attack does:

      C Source Code

      1. void Player::attack(const std::unique_ptr<Player>& opponent) const
      2. {
      3. const auto size = opponent->fleet.size();
      4. quint16 rf = 0;
      5. for (const auto& unit : fleet)
      6. {
      7. do
      8. {
      9. auto& o_unit = opponent->fleet[Player::rand() % size];
      10. const float hit = unit_weapon[unit.id];
      11. if (o_unit.damage != -1.f && hit >= o_unit.shield/100.f)
      12. {
      13. if (hit <= o_unit.shield)
      14. o_unit.shield -= hit;
      15. else
      16. {
      17. o_unit.damage += hit - o_unit.shield;
      18. o_unit.shield = 0.f;
      19. }
      20. const float explosion_chance = o_unit.damage/opponent->unit_armour[o_unit.id];
      21. if (explosion_chance > .3f && (Player::rand() % 1'000'000u)/1'000'000.f < explosion_chance)
      22. o_unit.damage = -1.f;
      23. }
      24. rf = Player::rapid_fires_enabled ? Player::rapid_fires[unit.id][o_unit.id] : 0;
      25. }
      26. while (rf != 0 && Player::rand() % rf != 0);
      27. }
      28. }
      Display All
      I think most variables are explicit enough, but if something is too obscure feel free to ask. A Unit object has three member variables: a quint8 for its id (each vessel/defense has its number), a float for its current damage to the hull, and a float for its current shield value. A dead unit has a damage value of -1.

      And here's what Player::repare does:


      C Source Code

      1. void Player::repare(void)
      2. {
      3. std::vector<Unit> new_fleet;
      4. new_fleet.reserve(fleet.size());
      5. for (const auto& unit : fleet)
      6. {
      7. if (unit.damage != -1.f)
      8. new_fleet.emplace_back(unit.id, unit_shield[unit.id], unit.damage);
      9. else
      10. ++dead_fleet[unit.id];
      11. }
      12. fleet.swap(new_fleet);
      13. }
      Display All
      dead_fleet is an array that stores how many units died for every different kind of units.

      Sorry for dropping all this stuff like that, but I've reached a state of despair and surrender. Do you guys find something odd in the above? Thanks for any help.

      The post was edited 1 time, last by Chaussette ().

    • I don't know exactly the c++ then maybe i could misunderstand something. Anyways it seems to me that there are 2 things wrong in Player::attack.

      1) If "dmg" is bigger than "shield/100", you do "shield-damage" and go on. This is usually not true because the shield destroyed is the maximum "X%" of the shield so that X is integer AND "shield/100*X" is < than the attack damage. (This is the deep reason behind the bouncing effect, this X is zero if the dmg is not at least 1% of the shield)

      2) About the explosion chance, i remember that this is:
      0% if the damaged armor is 0%-30%
      30% if dmg is 30%-60% (30 included, 60 not included)
      60% if dmg is 60%-80% (60 included, 80 not included, and so on)
      80% if dmg is 80%-100%
      100% if the dmg is >= 100%
      #6 Retro server - Fra [N O X]
      #5 Andromeda.us - Fra.. [Dynamic]
    • Canarefr wrote:

      I don't know exactly the c++ then maybe i could misunderstand something. Anyways it seems to me that there are 2 things wrong in Player::attack.

      1) If "dmg" is bigger than "shield/100", you do "shield-damage" and go on. This is usually not true because the shield destroyed is the maximum "X%" of the shield so that X is integer AND "shield/100*X" is < than the attack damage. (This is the deep reason behind the bouncing effect, this X is zero if the dmg is not at least 1% of the shield)

      2) About the explosion chance, i remember that this is:
      0% if the damaged armor is 0%-30%
      30% if dmg is 30%-60% (30 included, 60 not included)
      60% if dmg is 60%-80% (60 included, 80 not included, and so on)
      80% if dmg is 80%-100%
      100% if the dmg is >= 100%
      Thank you for replying once again.

      1. I actually noticed that but I figured I should fix it later, once I found out what the real problem was.

      2. And that must be the real problem then. I didn't know that, and that's not even covered by the English FAQ, which reads: "A hit that hightens the damage up to 40% creates therefore a chance of 40% the ship explodes." Although I'm trusting you here and am going to adjust my code right away, might I know where this piece of information comes from? In case somebody asks me.

      Thanks a lot for your help so far ^^
    • Sincerely I can't find a confirmation..

      Some years ago (5, 6, more? i don't know) an allymate was programming a simulator and i remember these things since that time. We tested a lot about shields and we learnt many things about this subject by searching in different boards.
      My replies are based on memory and parts of excel sheets that i reused for other things, like i said above don't take it as pure truth.
      #6 Retro server - Fra [N O X]
      #5 Andromeda.us - Fra.. [Dynamic]

      The post was edited 1 time, last by Canarefr ().

    • Canarefr wrote:

      Sincerely I can't find a confirmation..

      Some years ago (5, 6, more? i don't know) an allymate was programming a simulator and i remember these things since that time. We tested a lot about shields and we learnt many things about this subject by searching in different boards.
      My replies are based on memory and parts of excel sheets that i reused for other things, like i said above don't take it as pure truth.
      Hello, well I sent a ticket to my community's operators, and they told me I should ask my questions on our board... But if "official" people won't answer my questions, how can I know for sure how things work ? I'm stuck here I'm afraid :(


      Also I don't find the following very consistent:

      https://board.en.ogame.gameforge.com/index.php/Thread/151317-How-a-fight-works/ wrote:

      1 LF fires 50 weapon power. 100% * 50 / 2000 = 2.5%. Rounded down becomes 2%. In the instance of having 25 LF, 25 LF * 2% = 50% damage to the shield. Actually, 2%*2000 = 40. 25 LF * 40 = 1000 damage to shield.

      After the first LF hit, the shield value has changed, so the second LF hit should be ROUND_DOWN(50*100/1.960) = 2% of 1.960, which is 39,2. Something's wrong :S

      The post was edited 5 times, last by Chaussette ().

    • No, that seems correct to me. The LFs loss of firepower happens also in game (and you should consider it in your simulator).
      But keep in mind that the percentages of shield are alway calculated on the full strenght shield.
      You can see this when 49 BS and let's say 50k colony ships fire to a deathstar. Even if the colony ships have half the firepower than the shield left to the deathstar, they'll still never hit. (50 BS + the colony ships will win in one round).

      If you prefer a more practical example, you shouldn't think do the shield as an unique entity but as something consisted of 100 "Boxes", each one with 1% of the shield value.
      During each round, for every single shot that hits the shield, you check how many times bigger is the dmg compared to the box. The integer part of this check will say you how many boxes have gone down.

      So if even one box is alive and the shot can't reach the entire value of one box (remember that's always 1% of the total shield power), the shield will just bounce that shot.

      When in the FAQ's example a LF fires to that shield, the boxes have a value of 20, 2 are destroyed and 5 attack damage (10% of the total) is wasted.



      P.S.: I'd cut off that [Solved] from the title. It could stop new competent people to come and join the party :3
      #6 Retro server - Fra [N O X]
      #5 Andromeda.us - Fra.. [Dynamic]
    • Canarefr wrote:

      No, that seems correct to me. The LFs loss of firepower happens also in game (and you should consider it in your simulator).
      But keep in mind that the percentages of shield are alway calculated on the full strenght shield.
      You can see this when 49 BS and let's say 50k colony ships fire to a deathstar. Even if the colony ships have half the firepower than the shield left to the deathstar, they'll still never hit. (50 BS + the colony ships will win in one round).

      If you prefer a more practical example, you shouldn't think do the shield as an unique entity but as something consisted of 100 "Boxes", each one with 1% of the shield value.
      During each round, for every single shot that hits the shield, you check how many times bigger is the dmg compared to the box. The integer part of this check will say you how many boxes have gone down.

      So if even one box is alive and the shot can't reach the entire value of one box (remember that's always 1% of the total shield power), the shield will just bounce that shot.

      When in the FAQ's example a LF fires to that shield, the boxes have a value of 20, 2 are destroyed and 5 attack damage (10% of the total) is wasted.



      P.S.: I'd cut off that [Solved] from the title. It could stop new competent people to come and join the party :3
      Thanks a lot for your reply, I get it now. I think I have correctly implemented the shield stuff now. Unfortunately I still don't get accurate simulations ;(

      Here's my current Player::attack code:

      C Source Code

      1. void Player::attack(const std::unique_ptr<Player>& opponent) const
      2. {
      3. const auto size = opponent->fleet.size();
      4. quint16 rf = 0;
      5. for (const auto& unit : fleet)
      6. {
      7. do
      8. {
      9. auto& o_unit = opponent->fleet[Player::rand() % size];
      10. if (o_unit.damage != -1.f)
      11. {
      12. const float hit = unit_weapon[unit.id];
      13. if (hit >= o_unit.shield)
      14. {
      15. o_unit.damage += hit - o_unit.shield;
      16. o_unit.shield = 0.f;
      17. }
      18. else
      19. {
      20. const float shield_base = opponent->unit_shield[o_unit.id];
      21. const float shield_hit = std::floor(hit*100.f/shield_base)*shield_base/100.f;
      22. if (shield_hit == 0.f)
      23. continue;
      24. o_unit.shield -= shield_hit;
      25. }
      26. const auto explosion_chance = Player::explosion_factor(o_unit.damage/opponent->unit_armour[o_unit.id]);
      27. if (Player::rand() % 10u < explosion_chance)
      28. o_unit.damage = -1.f;
      29. }
      30. rf = Player::rapid_fires_enabled ? Player::rapid_fires[unit.id][o_unit.id] : 0;
      31. }
      32. while (rf != 0 && Player::rand() % rf != 0);
      33. }
      34. }
      Display All

      And here's the explosion chance function that you described:

      C Source Code

      1. quint8 Player::explosion_factor(float x)
      2. {
      3. if (x < .3f)
      4. return 0;
      5. if (x < .6f)
      6. return 3;
      7. if (x < .8f)
      8. return 6;
      9. if (x < 1.f)
      10. return 8;
      11. return 10;
      12. }
      Display All
      So if you find another mistake in the above, by all means share it ^^ Many thanks for your input so far!
    • Sadly i can't help you much here because of my poor knowledge of C ++. But for what i can understand, this time i do not see things that i recognize as wrong.
      What simulations are you trying for now? In which way are inaccurate?


      And how does rapid fire work in your code? That could cause a lot of changes in the results.
      #6 Retro server - Fra [N O X]
      #5 Andromeda.us - Fra.. [Dynamic]
    • Rapidfires are simple here, I have an array of arrays (or a 2D array if you will). The value of rapid_fires[first_ship][second_ship] is the rapid fire the first ship gets when it hits the second ship. So for example, rapid_fires[Deathstar][SmallCargo] has a value of 250. Whenever a ship attacks, I generate a random number mod. the rapid fire, and if the result isn't 0, the ship is allowed an additional attack.

      My simulations seem quite better, though, if I drop the explosion chance you mentioned, and revert to the more classic total_damage/total_hull probability. Are you really sure?