mathalgebra

Mathmatics to balance "multiple circuits"


I am building a game which allows the player to control "power flow" between 10 circuits.

Each of the 10 circuits is adjusted individually and the total must always equal 100%.

For example a perfectly balanced situation would be all 10 circuits at 10% (10x10=100)

Edit 2: If what I am trying to do here is know as things other than "balancing", please comment and I will research them.

Now the player also has the ability to lock circuits so that the power level cannot be changed by other circuits but it can still be changed directly.

EDIT 3: Sometimes the requested amount may not be possible to achieve (eg: example 3 and 6) in these situations the nearest possible result will be the result

EDIT: Seeing that my post is receiving down votes I will include what I have already tried

  1. Sum of change divided by circuits requesting change adding to circuits requesting change and taken off circuits not changing - The problem with this method was negative and positive changes at the same time could balance and result in "deadlock" situations where no change happens
  2. Looping circuit by circuit adding and taking as needed - The problem with this method is that it rarely balanced correctly
  3. Applying subtractions and additions first and then balance all circuits back into range (so total becomes 100) - the problem with this was power would end where it shouldn't be with circuits that should be at 0 ending up with small amounts of power

To simplify my question we can work with just 5 circuits.

I need assistance to work out the math for calculating the following. After 20 or so attempts I am thinking I am over complicating it as I keep ending up with 200 line scripts or is this actually very complicated?

Example 1: Addition Example

 20  20  20  20  20 Start values
+10 +10   0   0   0 Change
 30  30 3.3 3.3 3.3 After first iteration
 50  50   0   0   0 After x iterations (eg key held down)

Example 2: Subtraction Example

 20  20   20   20   20 Start values
-10 -10    0    0    0 Change
 10  10 26.6 26.6 26.6 After first iteration
  0   0 33.3 33.3 33.3 After x iterations (eg key held down)

Example 3: Lock + Addition (L is locked)

      L          
2.5  90  2.5  2.5  2.5 Start values
  0   0  +50    0    0 Change
  0  90   10    0    0 After first iteration
  0  90   10    0    0 After x iterations (eg key held down)

Example 4: Lock + Subtraction (L is locked)

      L          
2.5  90  2.5  2.5  2.5 Start values
  0 -10    0    0    0 Change
  5  80    5    5    5 After first iteration
 25   0   25   25   25 After x iterations (eg key held down)

Example 5: Multi Lock + Subtraction (L is locked)

      L    L      
 2.5  90  2.5  2.5  2.5 Start values
   0 -10    0    0    0 Change
 5.8  80  2.5  5.8  5.8 After first iteration
32.5   0  2.5 32.5 32.5 After x iterations (eg key held down)

Example 6: Balancing change from unbalanced start (This math may be a bit off)

 2.5   90  2.5  2.5  2.5 Start values
 +10  +10  +10    0    0 Change
16.7 66.6 16.7    0    0 After first iteration
33.3 33.3 33.3    0    0 After x iterations (eg key held down)

Solution

  • Start by retrieving all circuits that may potentially be changed by the runtime:

    Candidates = AllCircuits \ (LockedCircuits u ChangedCircuits)
    

    Here, \ denotes the set minus operator and u is the union operator.

    Calculate the average change per circuit:

    targetTotalChange = totalChange
    averageChange = totalChange / |Candidates|
    

    Now, start to change the candidates. To account for limitations, order the candidates by their current power flow. If averageChange is negative, then order them in ascending order. If it is positive, order them in descending order.

    And remember how many circuits you already have processed:

    processedCircuits = 0
    

    Now iterate all candidates in the specified order:

    for each candidate in Candidates
    

    Check if the the average change can be added to this circuit. Otherwise, adapt the values:

        processedCircuits++
        prevPower = candidate.PowerFlow
        targetPower = prevPower + averageChange
        if(targetPower < 0)
        {
            totalChange += prevPower
            candidate.PowerFlow = 0
            //recalculate average change
        }
        else if(targetPower > 100)
        {
            totalChange -= 100 - prevPower
            candidate.PowerFlow = 100
            //recalculate average change
        }
        else
        {
            totalChange -= averageChange
            candidate.PowerFlow += averageChange
        }
    

    When you need to recalculate the average change, do the following:

    averageChange = totalChange / (|Candidates| - processedCircuits)
    

    Beware of division by zero.

    Now you have adapted all other circuits. What remains is adapting the changed circuits. This is quite easy. We changed all other circuits by targetTotalChange - totalChange. This change can be added to the changed circuits. We can just add the according percentage:

    percentage = (targetTotalChange - totalChange) / targetTotalChange
    for each circuit in ChangedCircuits
        circuit.PowerFlow += percentage * targetChange[circuit]
    next