EOSERV Forum > EOSERV > How to use the '?' operand in RPN; Converting RPN to infix.
Page: << 1 >>
How to use the '?' operand in RPN; Converting RPN to infix.
Author Message
Post #200454 How to use the '?' operand in RPN; Converting RPN to infix.

So what are the official eo damage and hitrate formulas?

I'd figure this out myself from http://svn.eoserv.net/eoserv/trunk/data/formulas.ini but I can't find any documentation on how to use the ? , >= operands in RPN; because if I try calculating it myself I run out of operands.

Does anyone have the original formula with brackets on hand (infix formula not RPN?), or know how to use the ? , >= operands in RPN? Thanks! :)

I'm trying to figure out the best stat combinations for killing monsters.

---
I not hacker

“Everybody is a genius. But if you judge a fish by its ability to climb a tree, it will live its
whole life believing that it is stupid.” - Albert Einstein : Really Great Quote Ramy!
7 years, 43 weeks ago
Post #200461 Re: So what are the official eo damage and hitrate formulas?

I'm a little confused on what exactly you need help with but here is a few links that might help.

https://en.wikipedia.org/wiki/Reverse_Polish_notation

From the way back machine

https://tehsausage.com/paste/formulas-ini

https://eoserv.net/forum/topic/17506   

https://tehsausage.com/paste/reclasstats


7 years, 43 weeks ago
Post #200463 Re: So what are the official eo damage and hitrate formulas?

I must've posted this in the wrong section, sorry about that. I was asking for a much less technical response, explaining how to use the '?' and '>=' operands in RPN. I can't find that info online, in wikipedia, or searching eoserv forums? :(

and I use the stack method to calculate RPN, not the work from the middle method, if that makes a difference.

Also the eoserv 6.2 -> 7 changes are

The order of arguments 2 and 3 to the RPN '?' (if) operator were flipped.


..Meaning I guess when you have the '?' operator it automatically pops 3 numbers off the stack instead of 2? Just wondering how I'm supposed to parse the '?' ;)

BTW I finally understand how RPN works and is useful ever since I read

"Every time you enter a number, it is pushed onto the stack. When you eventually start using arithmetic operators, numbers start "popping" off the stack as needed. You can also push more numbers onto the stack. At the end of the calculation you will have "used up" all the numbers and the stack will be empty."
http://www.calculator.org/rpn.aspx

Thanks non-technical website giving a technical explanation xD



2 2 target_armor * damage / pow damage * damage 2 target_armor * damage >= ? 1 max  1 1.5 critical ? *

                                                                                                  
                                                                                                  

                                                                                                  *                                          >=
                                                                                                   target_armor                        damage                                    
                                                          *                                       2                                         2(target_armor)                        
*                         /                           damage                                 damage                                damage                                    
target_armor        damage                   pow                                     damage(pow)                       damage(pow)                            
2                        2(target_armor)       
2(target_armor)/damage        2(target_armor)/damage        2(target_armor)/damage             
2                         2                           2                                         2                                        2                                                           



?
2(target_armor) >= damage
damage
damage(pow)
2(target_armor)/damage
2                                 


Logically it makes sense to... but aren't I suppsoed to take the lowest number from the stack first? And Sausage's update saying it's an inverted if so we're actually evaluating the opposite so is that correctly switching the arguments?

                                                                                         *
                                                                                         ?
                                                                                        critical
                                                                                         1.5
                                                                                         1
                                                                                         max
                                                                                         1
2(target_armor) >= damage ? damage : damage(pow)             2(target_armor) >= damage ? damage : damage(pow)
2(target_armor)/damage                                                       2(target_armor)/damage
2                                                                                        2

At this point even if '?' takes 3 arguments, there's not enough operands to finish calculating so I must've calculated something wrong.

---
I not hacker

“Everybody is a genius. But if you judge a fish by its ability to climb a tree, it will live its
whole life believing that it is stupid.” - Albert Einstein : Really Great Quote Ramy!
7 years, 43 weeks ago
Post #200469 Re: How to use the '?' operand in RPN; Converting RPN to infix.

"z y x ?" means "if x: then y; otherwise z". The string is read left to right and any non-operator arguments are pushed on to a stack, and an operator pops the values back off of the stack in order.

The basic formulas are (D = damage, A = armor or accuracy, and E = evade, all assumed to be >= 0):

Damage (original):

if (D >= 2A) // The conditional protects from dividing by zero and caps the damage scaling's upper bound
D
else
D * (D/2A)^2

Then that number is capped to a lower bound of 1, multiplied by 1.5 if the hit is critical (npc target at max hp, or back/side-hit), and rounded down.

Hit rate (original):

if (E+A == 0) // Again, prevents dividing by zero
50%
else
A/2E

Then that number is capped between 20% and 80%, or set to 100% if the target was sitting down.

But these do not match the official server at every point because EO had severe rounding errors that caused the numbers to jump up in discrete amounts which I couldn't (and didn't want to) model.

Just for completeness, the changes I made on the clone were to change the formulas to...:

Damage (clone):

if (A < D)  // The conditional protects from dividing by zero and caps the damage scaling's upper bound
D - (A/2)
else
D * (D/2A)^2

Then that number is capped to a lower bound of 1, multiplied by 1.5 if the hit is critical (npc target at max hp, or back/side-hit), and rounded down.

The change from (D >= 2A) to (A < D) means the damage curve no longer has a part where the growth increases higher than 1:1 (on main, when damage was higher than your armour rating but less than twice your armour rating, each point of additional damage adds more than 1 point of calculated damage, before suddenly changing back to 1:1 for hits more than twice your armour rating). The change from D to (D-A/2) means that half of the armour rating is always applied in damage reduction (i.e. with 40 armour, 20 damage is always cut from an opponent's attack no matter how hard - on main if someone's damage was more than twice your armour rating there would be 0 reduction).

Hit Rate (clone):

1 / (1 + exp(0 - 2((2+A)-(1+E))/(1+E))) // exp() is the natural exponential function: e^x

The number is uncapped as the formula's range is [~12%,100%]. Set to 100% if the target was sitting down.

Basically this is just a slightly different curve that roughly matches the curve of EO main, but has more gradual tail ends to allow the hit rate range cap to be expanded, rather than capping between [20%,80%], meaning accuracy/evade doesn't become useless to train too high (on main, an opponent with 4 accuracy could be dodged 80% of the time at 10 evade, and training evade any higher had no benefit). It also adds constants to the accuracy/evade numbers to give higher accuracy rates at lower levels (~88% hit rate punching a 0 evade target with 0 accuracy), to make the low level game less of a miss-fest.

7 years, 43 weeks ago
Post #200474 Re: How to use the '?' operand in RPN; Converting RPN to infix.
Sausage posted: (5th Jul 2016, 03:25 pm)

"z y x ?" means "if x: then y; otherwise z". The string is read left to right and any non-operator arguments are pushed on to a stack, and an operator pops the values back off of the stack in order.

The basic formulas are (D = damage, A = armor or accuracy, and E = evade, all assumed to be >= 0):

Damage (original):

if (D >= 2A) // The conditional protects from dividing by zero and caps the damage scaling's upper bound
D
else
D * (D/2A)^2

Then that number is capped to a lower bound of 1, multiplied by 1.5 if the hit is critical (npc target at max hp, or back/side-hit), and rounded down.

Hit rate (original):

if (E+A == 0) // Again, prevents dividing by zero
50%
else
A/2E

Then that number is capped between 20% and 80%, or set to 100% if the target was sitting down.

But these do not match the official server at every point because EO had severe rounding errors that caused the numbers to jump up in discrete amounts which I couldn't (and didn't want to) model.

Just for completeness, the changes I made on the clone were to change the formulas to...:

Damage (clone):

if (A < D)  // The conditional protects from dividing by zero and caps the damage scaling's upper bound
D - (A/2)
else
D * (D/2A)^2

Then that number is capped to a lower bound of 1, multiplied by 1.5 if the hit is critical (npc target at max hp, or back/side-hit), and rounded down.

The change from (D >= 2A) to (A < D) means the damage curve no longer has a part where the growth increases higher than 1:1 (on main, when damage was higher than your armour rating but less than twice your armour rating, each point of additional damage adds more than 1 point of calculated damage, before suddenly changing back to 1:1 for hits more than twice your armour rating). The change from D to (D-A/2) means that half of the armour rating is always applied in damage reduction (i.e. with 40 armour, 20 damage is always cut from an opponent's attack no matter how hard - on main if someone's damage was more than twice your armour rating there would be 0 reduction).

Hit Rate (clone):

1 / (1 + exp(0 - 2((2+A)-(1+E))/(1+E))) // exp() is the natural exponential function: e^x

The number is uncapped as the formula's range is [~12%,100%]. Set to 100% if the target was sitting down.

Basically this is just a slightly different curve that roughly matches the curve of EO main, but has more gradual tail ends to allow the hit rate range cap to be expanded, rather than capping between [20%,80%], meaning accuracy/evade doesn't become useless to train too high (on main, an opponent with 4 accuracy could be dodged 80% of the time at 10 evade, and training evade any higher had no benefit). It also adds constants to the accuracy/evade numbers to give higher accuracy rates at lower levels (~88% hit rate punching a 0 evade target with 0 accuracy), to make the low level game less of a miss-fest.


Thanks for the very detailed response Sausage! :) Is pow supposed to be exponent then? hehe
http://svn.eoserv.net/eoserv?op=comp&compare[]=/@507&compare[]=/@508

Hit rate (original):

if (E+A == 0) // Again, prevents dividing by zero
50%
else
A/2E

What if E = 0 and A >= 1 , then you're dividing by 0. So basically if I punch a 0 evade target and
I have some accuracy, eoserv will die? xD
(not being technical or examining the source here, I assume with your good programming
knowledge it doesnt die)

And oh I see you pop off the first number from the stack and do first number operator pop off next
number, evaluate, but on wikipedia they do, pop off 2 numbers,
the number that was lower in the stack comes first.

5 1 2 + -
evaluates as
1+2 = 3
5 3 -
5 - 3 = 2

(not 3 - 5)

https://en.wikipedia.org/wiki/Reverse_Polish_notation#Example


Is EOSERV's implementation of RPN different? I find your implementation to be easier
anyways to the human reader.

According to wikipedia

2 target_evade * accuracy /

would be evaluated as (2 * target_evade) / accuracy

or am I sadly mistaken


---
I not hacker

“Everybody is a genius. But if you judge a fish by its ability to climb a tree, it will live its
whole life believing that it is stupid.” - Albert Einstein : Really Great Quote Ramy!
7 years, 42 weeks ago
Post #200477 Re: How to use the '?' operand in RPN; Converting RPN to infix.

You're right, it doesn't prevent dividing by zero, but the result is 1/0 = infinity, capped to 100%, which is correct. It prevents 0/0 = NaN which is the actual fail case in floating point arithmetic.

And yeah, looks like it's gets the operands backwards compared to traditional RPN. It seems way more natural for computation the way I did it, since it fills out the arguments for f(x, y, z) in the order they're popped.

7 years, 42 weeks ago
Page: << 1 >>

EOSERV Forum > EOSERV > How to use the '?' operand in RPN; Converting RPN to infix.