SOLVED Randomize total damage between several enemies.

flyinian

Member
I'm trying to get the damage value to randomly split its number between several enemy's health.

I've attempted to use choose and random functions but, wasn't successful.
I've also tried storing the unit's variables into another variable and using that in code.

I am trying to take the value that results from "Ptotalkill - Etotaldefense = "answer"" and subtract it from enemy unit 1 and enemy unit 2 randomly. If the "answer" was 10, unit 1 could be a 3 - unit 1 and unit 2 could be a 7 - unit 2. not going over the "answer" number and not using less of it. Keeping it random(how the "answer" is split between the units.). I also plan on having more than the two units.

GML:
if(Etotalunits > 0 && Ptotalkill > Etotaldefense)
        {
            Etotalunits -= Ptotalkill - Etotaldefense;  // original line of code that takes away from the enemy's total units
           

   //      " enemyunit1 & unit2" -= Ptotalkill - Etotaldefense; // The "new" line of code that I want it to take away from the enemy's unit 1 & unit 2. The   " enemyunit1 & unit2" are a visual representation for demonstration.
        };
Thank you.
 

chamaeleon

Member
I'm trying to get the damage value to randomly split its number between several enemy's health.

I've attempted to use choose and random functions but, wasn't successful.
I've also tried storing the unit's variables into another variable and using that in code.

I am trying to take the value that results from "Ptotalkill - Etotaldefense = "answer"" and subtract it from enemy unit 1 and enemy unit 2 randomly. If the "answer" was 10, unit 1 could be a 3 - unit 1 and unit 2 could be a 7 - unit 2. not going over the "answer" number and not using less of it. Keeping it random(how the "answer" is split between the units.). I also plan on having more than the two units.

GML:
if(Etotalunits > 0 && Ptotalkill > Etotaldefense)
        {
            Etotalunits -= Ptotalkill - Etotaldefense;  // original line of code that takes away from the enemy's total units
          

   //      " enemyunit1 & unit2" -= Ptotalkill - Etotaldefense; // The "new" line of code that I want it to take away from the enemy's unit 1 & unit 2. The   " enemyunit1 & unit2" are a visual representation for demonstration.
        };
Thank you.
One possibility, create an array of size equal to the number of units you wish to spread the damage over.
Assign the average value per unit to each position (if not evenly divisible, distribute the remainder to as many units as required).
Looping some number of times, pick two positions in the array, and subtract some amount from one and add the same amount to the other.
 

flyinian

Member
One possibility, create an array of size equal to the number of units you wish to spread the damage over.
Assign the average value per unit to each position (if not evenly divisible, distribute the remainder to as many units as required).
Looping some number of times, pick two positions in the array, and subtract some amount from one and add the same amount to the other.
I'm looking into arrays now and trying to figure them out. I'll be back to this post at a later date.

Thanks.
 

flyinian

Member
One possibility, create an array of size equal to the number of units you wish to spread the damage over.
Assign the average value per unit to each position (if not evenly divisible, distribute the remainder to as many units as required).
Looping some number of times, pick two positions in the array, and subtract some amount from one and add the same amount to the other.
If you don't mind, what would a code sample look like for this?
 

chamaeleon

Member
If you don't mind, what would a code sample look like for this?
As a starting point, but doubtless in need of tweaking for your needs
GML:
var enemy_count = 5;
var total_damage = 23;
var enemy_damage = [];

for (var i = 0; i < 5; ++i) {
    enemy_damage[i] = floor(total_damage/enemy_count);
    if (i < total_damage % enemy_count)
        ++enemy_damage[i];
}

if (total_damage > 0) {
    repeat 2*enemy_count {
        do { var from = irandom(enemy_count-1); } until enemy_damage[from] != 0;
        var to = irandom(enemy_count-1);
    
        --enemy_damage[from];
        ++enemy_damage[to];
    }
}
Array content before and after repeat statement
Code:
Damage = 5 5 5 4 4
Damage = 6 6 4 7 0
 

flyinian

Member
As a starting point, but doubtless in need of tweaking for your needs
GML:
var enemy_count = 5;
var total_damage = 23;
var enemy_damage = [];

for (var i = 0; i < 5; ++i) {
    enemy_damage[i] = floor(total_damage/enemy_count);
    if (i < total_damage % enemy_count)
        ++enemy_damage[i];
}

if (total_damage > 0) {
    repeat 2*enemy_count {
        do { var from = irandom(enemy_count-1); } until enemy_damage[from] != 0;
        var to = irandom(enemy_count-1);
   
        --enemy_damage[from];
        ++enemy_damage[to];
    }
}
Array content before and after repeat statement
Code:
Damage = 5 5 5 4 4
Damage = 6 6 4 7 0
Thank you for the code, I attempted to understand what is going on...

Here is my awful attempt to break your code down so, I can try and understand what is going on.

I want to know what is happening with the code before I use/continue with it.

If you could, let me know what I have wrong and correct it?

GML:
var enemy_count = 5;        //    Creates the temproary variable and assigns it the given value(5)
var total_damage = 23;        //    Creates the temproary variable and assigns it the given value(23)
var enemy_damage = [];        //    Creates the temproary variable and assigns it the given value(nothing), this variable is also the damage to be spread across the multiple enemies.

for (var i = 0; i < 5; ++i) {                                                            // sets i to 0; as long as i is less than 5; plus 1 to i
    enemy_damage[i] = floor(total_damage/enemy_count);                                    //    determines the damage to be applied across the enemy count. Rounding the damage down.
    if (i < total_damage % enemy_count)                                                    //    if i is less than total_damage % enemy_count, do the following
        ++enemy_damage[i];                                                                // adds 1 to the enemy_damage or is this the enemy selected to apply the damage to?
}



/// The below code applies the current total_damage to random enemies until total_damage reaches 0
if (total_damage > 0) {                                                                // if total_damage is greater than 0, do the following code.
    repeat 2*enemy_count {                                                            //  why times enemy_count twice? why repeat?
        do { var from = irandom(enemy_count-1); } until enemy_damage[from] != 0;    // randomly minus 1 from enemy_count until enemy_damage does not equal to 0 ?...becuase enemy_damage starts at 0?
        var to = irandom(enemy_count-1);                                            //    assign local variable to the value
    
        --enemy_damage[from];                                                        //    minus 1 from enemy_damage[from]
        ++enemy_damage[to];                                                            //    plus 1 to enemy_damage[to]
    }
}

As i'm sure you can see, I hardly know what's going on here.

Thank you.
 

chamaeleon

Member
GML:
if (i < total_damage % enemy_count)
    ++enemy_damage[i];
The % operator gives me the remainder of damage points remaining after accounting for the rounded down divison. By comparing the modulus result with the i loop variable, I avoid having a secondary loop that that iterates exactly total%count times to add one to the number of enemies corresponding to the remainder result of the operation. The first line in my output shows the result after having done this.
GML:
do { var from = irandom(enemy_count-1); } until enemy_damage[from] != 0;
Use random to find a enemy_damage entry value that is not zero (looping until found), so that I can subtract one from it to add to some other cell (and because it will be an addition for it, it doesn't matter if it is zero).
GML:
if (total_damage > 0)
Ensure that the code randomly distributing damage across the enemies does not run if there is no damage available to distribute, as it would mean an infinite loop for sure trying to find an entry with a value greater than zero, leaving you with the game hanging in the do until loop.
GML:
repeat 2*enemy_count
Completely arbitrary decision to distribute one point from one enemy to the next 2*enemy_count times. There's no algorithmic reason at all. Could be a for loop with a fixed number, could be based on enemy count, could be by inspecting the values in the array, or any other means of determining how many times to do it or when to stop. Because I didn't have any specific goal in mind, that is what I picked for the sake of simplicity.
 

flyinian

Member
GML:
if (i < total_damage % enemy_count)
    ++enemy_damage[i];
The % operator gives me the remainder of damage points remaining after accounting for the rounded down divison. By comparing the modulus result with the i loop variable, I avoid having a secondary loop that that iterates exactly total%count times to add one to the number of enemies corresponding to the remainder result of the operation. The first line in my output shows the result after having done this.
GML:
do { var from = irandom(enemy_count-1); } until enemy_damage[from] != 0;
Use random to find a enemy_damage entry value that is not zero (looping until found), so that I can subtract one from it to add to some other cell (and because it will be an addition for it, it doesn't matter if it is zero).
GML:
if (total_damage > 0)
Ensure that the code randomly distributing damage across the enemies does not run if there is no damage available to distribute, as it would mean an infinite loop for sure trying to find an entry with a value greater than zero, leaving you with the game hanging in the do until loop.
GML:
repeat 2*enemy_count
Completely arbitrary decision to distribute one point from one enemy to the next 2*enemy_count times. There's no algorithmic reason at all. Could be a for loop with a fixed number, could be based on enemy count, could be by inspecting the values in the array, or any other means of determining how many times to do it or when to stop. Because I didn't have any specific goal in mind, that is what I picked for the sake of simplicity.
I've been looking at this all day trying to break it down to comprehend it.


what does the enemy_damage relate to? Would this just be the amount of damage the enemy does or would it be the damage done to the enemy? perhaps something else?

edit: enemy_damage is the damage being done to the enemies split between 5 enemies.
 
Last edited:

chamaeleon

Member
I'm trying to get the damage value to randomly split its number between several enemy's health.
My enemy array is simply my interpretation of this requirement. "several enemies health" -> an array with as many entries as enemies to randomly distribute a grand total damage count.
 

flyinian

Member
My enemy array is simply my interpretation of this requirement. "several enemies health" -> an array with as many entries as enemies to randomly distribute a grand total damage count.
I'm slowly understanding this more and more so, please bare with me.

I just did a show_debug_message on enemy_damage at the end of the code.

it gave me five numbers which I assume are the randomized damage amount across 5 enemies.


This is what shows for the debug message:

enemy_damage: { { 6,4,8,1,4 }, }

first enemy will receive 6 damage.
second enemy will receive 4 damage.
third enemy will receive 8 damage.
fourth enemy will receive 1 damage.
fifth enemy will receive 4 damage.

Would this be in correct order. Meaning the first damage be applied to enemy at position 1 then second damage amount be applied to the second enemy at position 2 and so on?
 

flyinian

Member
What would I edit to make the damages more randomized instead of being evenly distributed across the enemies?

From:

enemy_damage: { { 3000,3000,3003,3001,2998,3000,2998,3001,3001,2998 }, } //"evenly" distributed

To:
enemy_damage: { { 60,3,54,867,2,0,98,1,1,98 }, } // appears to be random
 
Last edited:

chamaeleon

Member
What would I edit to make the damages more randomized instead of being evenly distributed across the enemies?
You could choose a random amount from "from" up to its limit to move from "from" to "to", instead of just using a single decrement and increment. Or scrap the whole approach and implement it some other way.
 

flyinian

Member
You could choose a random amount from "from" up to its limit to move from "from" to "to", instead of just using a single decrement and increment. Or scrap the whole approach and implement it some other way.
Thanks for the help, I am going to experiment with it and see where I get.
 
Top