# include <cmath>
# include <cstdio>
# include <iostream>
using namespace std ;
typedef double Float ;
typedef long long Int ;
// Set initial data
# define Character_InitialLevel 1
# define Character_InitialTotalXp 0
# define Challenge_InitialExpectedXpReward 10
// Set equation to solve (find challenge relative power expoent in xp reward formula)
Float Equation_LeftSide( Float XpRewardFormula_ChallengeRelativePower_Expoent ){
return XpRewardFormula_ChallengeRelativePower_Expoent ;
}
Float Equation_RightSide( Float XpRewardFormula_ChallengeRelativePower_Expoent ){
return 1 ;
}
// Set character total xp rounding method
# define Rounding_MinimalDigits(Character_LevelUpXp) 0 /* integer with no rounded integer digit */
# define Rounding_MaximalDigits(Character_LevelUpXp) log10(Character_LevelUpXp)-1.4 /* modify less than 2% */
// Set table with cells data {
// Challenge Expected Relative Power ,
// Character Expected Rewards To Level Up ,
// Expected Xp Reward Bonus (%)
// } at Character_InitialLevel, Character_InitialLevel+1, ..., Character_FinalLevel-2 and Character_FinalLevel-1
const Float LevelInputData[][3] = {
{ 1.00000 , 1.0 , 0.0 } ,
{ 2.48832 , 5.0 , 0.0 } ,
{ 5.37824 , 20.0 , 0.0 } ,
{ 10.48576 , 60.0 , 5.0 } ,
{ 18.89568 , 120.0 , 10.0 } ,
{ 32.00000 , 180.0 , 15.0 } ,
{ 51.53632 , 240.0 , 20.0 } ,
{ 79.62624 , 300.0 , 25.0 } ,
{ 118.81376 , 300.0 , 25.0 }
} ;
# define LevelUps Int( sizeof(LevelInputData) / sizeof(*LevelInputData) )
Float RoundLevelUp( const Float *TotalXp , Float *Factors , Int Index , Int RoundIndex=0 , Int Factor=1 ){
Index = min(max(Index,0LL),LevelUps-1) ;
Float Temporary1 = ( Index == RoundIndex ?
Factors[ Index ]*Factor : Factors[ Index ] ) ;
Temporary1 = round( TotalXp[ Index++ ]/Temporary1 )*Temporary1 ;
Float Temporary2 = ( Index == RoundIndex ?
Factors[ Index ]*Factor : Factors[ Index ] ) ;
return round( TotalXp[ Index ]/Temporary2 )*Temporary2 - Temporary1 ;
}
Int Character_FinalLevel = Character_InitialLevel + LevelUps ;
struct SolutionData {
Float XpRewardFormula_ChallengeRelativePower_Expoent , XpRewardFormula_Factor ;
Float Challenge_ExpectedXpReward[ LevelUps ] ;
Float Character_LevelUpXp[ 1 + LevelUps ] , Character_TotalXp[ 1 + LevelUps ] ;
SolutionData( Float Expoent ){
Character_LevelUpXp[ LevelUps ] = 1e400 ;
XpRewardFormula_ChallengeRelativePower_Expoent = Expoent ;
XpRewardFormula_Factor = Challenge_InitialExpectedXpReward ;
XpRewardFormula_Factor /= ( 100+LevelInputData[0][2] )*pow( LevelInputData[0][0] , Expoent ) ;
Character_TotalXp[ 0 ] = Character_InitialTotalXp ;
for( Int Index=0 ; Index < LevelUps ; Index++ ){
Challenge_ExpectedXpReward[ Index ] = XpRewardFormula_Factor ;
Challenge_ExpectedXpReward[ Index ] *= 100+LevelInputData[ Index ][2] ;
Challenge_ExpectedXpReward[ Index ] *= pow( LevelInputData[ Index ][0] , Expoent ) ;
Character_TotalXp[ Index+1 ] = LevelInputData[ Index ][1]*Challenge_ExpectedXpReward[ Index ] ;
Character_TotalXp[ Index+1 ] += Character_TotalXp[ Index ] ;
Character_LevelUpXp[ Index ] = Character_TotalXp[ Index+1 ]-Character_TotalXp[ Index ] ;
}
}
} ;
int main() {
Float RoundingFactors[ LevelUps + 1 ] , MaximalRoundingFactors[ LevelUps + 1 ] ;
for( Int Index=1 ; Index < sizeof(LevelInputData)/sizeof(*LevelInputData) ; Index++ ){
if( LevelInputData[Index-1][0] > LevelInputData[Index][0] ){
if( LevelInputData[Index-1][1] > LevelInputData[Index][1] ){
cout << "Warning: challenge mean relative power and character" ;
cout << " expected rewards to level up decreases.\n Level " ;
cout << (Character_InitialLevel+Index-1) << " --> " ;
cout << (Character_InitialLevel+Index) << "\n CMRPW " ;
cout << LevelInputData[Index-1][0] << " --> " ;
cout << LevelInputData[Index][0] << "\n CERLU " ;
cout << LevelInputData[Index-1][1] << " --> " << LevelInputData[Index][1] << "\n\n" ;
} else {
cout << "Warning: challenge mean relative power decreases.\n Level " ;
cout << (Character_InitialLevel+Index-1) << " --> " ;
cout << (Character_InitialLevel+Index) << "\n CMRPW " ;
cout << LevelInputData[Index-1][0] << " --> " << LevelInputData[Index][0] << "\n\n" ;
}
} else if( LevelInputData[Index-1][1] > LevelInputData[Index][1] ){
cout << "Warning: character expected rewards to level up decreases.\n Level " ;
cout << (Character_InitialLevel+Index-1) << " --> " ;
cout << (Character_InitialLevel+Index) << "\n CERLU " ;
cout << LevelInputData[Index-1][1] << " --> " << LevelInputData[Index][1] << "\n\n" ;
}
}
cout << "Initial Level = " << Character_InitialLevel << "\nFinal Level = " ;
cout << Character_FinalLevel << "\nExpected Xp Reward = " ;
// Solve Equation (continue...)
SolutionData Solution=1 ;
if(!( abs(Solution.XpRewardFormula_Factor-1) < 1e-13 )){
cout << Solution.XpRewardFormula_Factor << '*' ;
}
cout << "( 100 + Xp Reward Bonus Percent )*( Challenge Relative Power" ;
if( Solution.XpRewardFormula_ChallengeRelativePower_Expoent != 1 ){
cout << " ^ " << Solution.XpRewardFormula_ChallengeRelativePower_Expoent ;
}
cout << " )\nCharacter Total Xp = " ;
for( Int Index=0 ; Index <= LevelUps ; Index++ ){
Float Temporary1 = Solution.Character_LevelUpXp[ max(Index,1LL)-1 ] ;
Temporary1 = round(pow(10, Rounding_MinimalDigits( Temporary1 ) )) ;
Float Temporary2 = Solution.Character_LevelUpXp[ max(Index,1LL)-1 ] ;
Temporary2 = round(pow(10, Rounding_MaximalDigits( Temporary2 ) )) ;
RoundingFactors[ Index ] = ( Temporary1 > 1 ? Temporary1 : 1 ) ;
MaximalRoundingFactors[ Index ] = ( Temporary2 > Temporary1 ? Temporary2 : Temporary1 ) ;
}
for( Float RoundingFactor_Factor=19 ; (RoundingFactor_Factor=Int(RoundingFactor_Factor*0.6)-1) ; ){
bool DidRound ;
do {
DidRound = false ;
for( Int Index=0 ; Index <= LevelUps ; Index++ ){
if(!( RoundingFactors[ Index ]*RoundingFactor_Factor <= MaximalRoundingFactors[ Index ] ))
continue ;
Float RluXp_Pre0 = RoundLevelUp( Solution.Character_TotalXp , RoundingFactors , Index-3 ) ;
Float RluXp_Pos0 = RoundLevelUp( Solution.Character_TotalXp ,
RoundingFactors , Index-3 , Index , RoundingFactor_Factor ) ;
if( (!(RluXp_Pos0 > 0)) && (RluXp_Pre0 > 0) ) continue ;
Float RluXp_Pre1 = RoundLevelUp( Solution.Character_TotalXp , RoundingFactors , Index-2 ) ;
Float RluXp_Pos1 = RoundLevelUp( Solution.Character_TotalXp ,
RoundingFactors , Index-2 , Index , RoundingFactor_Factor ) ;
if( (!(RluXp_Pos1 > RluXp_Pos0)) && (RluXp_Pre1 > RluXp_Pre0) ) continue ;
if( (!(RluXp_Pos1 >= RluXp_Pos0)) && (RluXp_Pre1 >= RluXp_Pre0) ) continue ;
Float RluXp_Pre2 = RoundLevelUp( Solution.Character_TotalXp , RoundingFactors , Index-1 ) ;
Float RluXp_Pos2 = RoundLevelUp( Solution.Character_TotalXp ,
RoundingFactors , Index-1 , Index , RoundingFactor_Factor ) ;
if( (!(RluXp_Pos2 > RluXp_Pos1)) && (RluXp_Pre2 > RluXp_Pre1) ) continue ;
if( (!(RluXp_Pos2 >= RluXp_Pos1)) && (RluXp_Pre2 >= RluXp_Pre1) ) continue ;
Float RluXp_Pre3 = RoundLevelUp( Solution.Character_TotalXp , RoundingFactors , Index ) ;
Float RluXp_Pos3 = RoundLevelUp( Solution.Character_TotalXp ,
RoundingFactors , Index , Index , RoundingFactor_Factor ) ;
if( (!(RluXp_Pos3 > RluXp_Pos2)) && (RluXp_Pre3 > RluXp_Pre2) ) continue ;
if( (!(RluXp_Pos3 >= RluXp_Pos2)) && (RluXp_Pre3 >= RluXp_Pre2) ) continue ;
Float RluXp_Pre4 = RoundLevelUp( Solution.Character_TotalXp , RoundingFactors , Index+1 ) ;
Float RluXp_Pos4 = RoundLevelUp( Solution.Character_TotalXp ,
RoundingFactors , Index+1 , Index , RoundingFactor_Factor ) ;
if( (!(RluXp_Pos4 > RluXp_Pos3)) && (RluXp_Pre4 > RluXp_Pre3) ) continue ;
if( (!(RluXp_Pos4 >= RluXp_Pos3)) && (RluXp_Pre4 >= RluXp_Pre3) ) continue ;
Float RluXp_Pre5 = RoundLevelUp( Solution.Character_TotalXp , RoundingFactors , Index+2 ) ;
Float RluXp_Pos5 = RoundLevelUp( Solution.Character_TotalXp ,
RoundingFactors , Index+2 , Index , RoundingFactor_Factor ) ;
if( (!(RluXp_Pos5 > RluXp_Pos4)) && (RluXp_Pre5 > RluXp_Pre4) ) continue ;
if( (!(RluXp_Pos5 >= RluXp_Pos4)) && (RluXp_Pre5 >= RluXp_Pre4) ) continue ;
RoundingFactors[ Index ] *= RoundingFactor_Factor ;
DidRound = true ;
}
} while( DidRound ) ;
}
for( Int Index=0 ; Index <= LevelUps ; Index++ ){
Solution.Character_TotalXp[ Index ] /= RoundingFactors[ Index ] ;
Solution.Character_TotalXp[ Index ] = round( Solution.Character_TotalXp[ Index ] ) ;
Solution.Character_TotalXp[ Index ] *= RoundingFactors[ Index ] ;
}
for( Int Index=0 ; Index < LevelUps ; Index++ ){
printf( "%.0lf, " , Solution.Character_TotalXp[ Index ] ) ;
Solution.Character_LevelUpXp[ Index ] = Solution.Character_TotalXp[ Index+1 ] ;
Solution.Character_LevelUpXp[ Index ] -= Solution.Character_TotalXp[ Index ] ;
}
printf( "%.0lf\n\n" , Solution.Character_TotalXp[ LevelUps ] ) ;
cout << "Level TotalXp LevelUpXp " ;
cout << "LevelUpXpGrow ExXpRew ExRewToLvUp" ;
for( Int Index=0 ; Index <= LevelUps ; Index++ ){
printf( "\n%5llu %18.0lf" , Character_InitialLevel+Index , Solution.Character_TotalXp[ Index ] ) ;
printf( " %18.0lf" , Solution.Character_LevelUpXp[ Index ] ) ;
if( Index != LevelUps ){
Float Character_LevelUpXp = Solution.Character_LevelUpXp[ Index ] ;
printf( " %+17.2lf%%" , 100*Solution.Character_LevelUpXp[ Index+1 ]/Character_LevelUpXp-100 ) ;
printf( " %18.2lf" , Solution.Challenge_ExpectedXpReward[ Index ] ) ;
printf( " %18.2lf" , Character_LevelUpXp/Solution.Challenge_ExpectedXpReward[ Index ] ) ;
}
}
return 0 ;
}