smgstudio / risk-dice

Dice code used in RISK: Global Domination
21 stars 8 forks source link

New Balanced Blitz Solution #3

Open xOuchx0x opened 4 months ago

xOuchx0x commented 4 months ago

Here is a solution to the balanced blitz dice that runs in O(N) time. Note this is not really a fix to the current BB dice code for two reasons. The first reason is the balanced blitz dice currently relies on finding the true random probablilty first which is super slow and inaccurate. Secondly this is method moduler and can easily be expanded to say 4 dice defenders or attackers easily. Another thing I did with this is allowed all rolls to have a chance to win or lose rather than capping anything less than 10% and because I hate when people just use 3 troops to get a card. I wanted an attacker to lose less troops rolling 1000 into a 1 than only rolling 4.

Here is a graph of the win percentages for several example battles. https://prnt.sc/Ot1RF5rDk1pQ A zoomed in version https://prnt.sc/BXkJAZ4LSz1R Here is an example of troops remianing after a 90v100 battle https://prnt.sc/NVvp5ihjKZ7q Example of 9v8 https://prnt.sc/gGH-_JyyCWYH Example of rolling stacks into 1 troop https://prnt.sc/UeewmCeRG8rq

FYI I only sent the part of the code that does attacker troop loss. Reach out to me if your intested in using this solution to fix the balanced blitz issue I'll add the defender troop loss as well as the cap troop loss and win percentage calculator. Also note this part of the code only gives an array of all possible loss values for attackers it doesnt actually select the outcome. Also note I used Int and float. The code is way more accurate using doubles.

_____Code

include

include

include

include

double floorToZero(double value);

int main() { srand(time(NULL));

int Attackers = 100; //Attackers in the battle int Defenders = 100; //Defenders in the battle int iscap =0; //0 if not a cap int AttackersOutcome[Attackers+Defenders+1][4]; int FinalOutcome[Attackers+Defenders+1][2];

//Calculate attackers left
for (int Attackersleft = -Defenders; Attackersleft <= Attackers; Attackersleft++) //Make the array extend into negatives so if a negative value is selected than count that as attacker losing all troops
{ 

//Attackers left at this troop count
AttackersOutcome[Attackersleft+Defenders][0] = Attackersleft;
float WL = .85; //Odds of killing a troop note I used rough odds rather than exact odds cause I was lazy
float TroopPercent = 1;
float ScaleFactor = (10*WL*WL*pow(Defenders,-1*WL))*0.7+0.15; //Just here to make the equation for TroopPercentleft simpler
TroopPercent = 33*(ScaleFactor)/(    (ScaleFactor*Attackersleft-((Attackers-((Defenders-WL)*0.8)))*ScaleFactor)*(ScaleFactor*Attackersleft-((Attackers-((Defenders-WL)*0.8)))*ScaleFactor)+1 );                        
AttackersOutcome[Attackersleft+100][1] = TroopPercent*(Attackers-3)/Attackers;    //Percent Chance of having this many attackers left * wieght of this being a factor in battle

//Attackers left at this troop count except this time account for situations where the attacker is attacking 1 troop
WL = .51; //Odds of killing a troop
TroopPercent = 1;
ScaleFactor = (10*WL*WL*pow(Defenders,-1*WL))*0.7+0.15;
TroopPercent = 33*(ScaleFactor)/(    (ScaleFactor*Attackersleft-((Attackers-((Defenders-WL)*0.8)))*ScaleFactor)*(ScaleFactor*Attackersleft-((Attackers-((Defenders-WL)*0.8)))*ScaleFactor)+1 );                        
AttackersOutcome[Attackersleft+Defenders][2] = TroopPercent*(2)/Attackers;    //Percent Chance of having this many attackers left * wieght of this being a factor in battle

//Attackers left at this troop count except this time account for situations where the attacker is attacking with 2 troops not 3
WL = .27; //Odds of killing a troop
TroopPercent = 1;
ScaleFactor = (10*WL*WL*pow(Defenders,-1*WL))*0.7+0.15;
TroopPercent = 33*(ScaleFactor)/(    (ScaleFactor*Attackersleft-((Attackers-((Defenders-WL+1)*0.8)))*ScaleFactor)*(ScaleFactor*Attackersleft-((Attackers-((Defenders-WL+1)*0.8)))*ScaleFactor)+1 );              //The 33 is just in their cause I converted float to INT and didnt want to lose more than 1 decimal          
AttackersOutcome[Attackersleft+Defenders][3] = TroopPercent*(1)/Attackers;    //Percent Chance of having this many attackers left * wieght of this being a factor in battle

FinalOutcome[Attackersleft+Defenders][0] = Attackersleft;
FinalOutcome[Attackersleft+Defenders][1] = floorToZero(AttackersOutcome[Attackersleft+Defenders][1])+floorToZero(AttackersOutcome[Attackersleft+Defenders][2])+floorToZero(AttackersOutcome[Attackersleft+Defenders][3]);

} return 0; }

//This removes odds for battles that cant possibly happen. like -1v2 double floorToZero(double value) { return value < 0.0 ? 0.0 : value; }

_____Code end

Please leave some feedback. Is this method worth implementing? Would you like to see it more efficent or like some more info? Maybe a demo? Find me in the discord as Acid_Ibis

fortuna commented 3 months ago

I don't know if this is how it's implemented, but you can calculate chances of winning for any (n, m) pair of troops in O(n * m) using dynamic programming and real dice probability. That is not slow and imprecise given the numbers in a game.

It's as simple as two for loops to build a P[a][b] matrix for the probability of attacker winning with a troops against b defender troops.

stevemer commented 2 weeks ago

I agree that this is an easy solve. Maybe @AikenParkerSMG can help make contact here?