context (skip if know)
gielinor games is a “reality tv show” filmed in old school runescape, an mmorpg with silly graphics in which you can do a whole lot of stuff; kind of like roblox but not really (not sure how helpful that is). beyond just fighting monsters and leveling up there is a whole host of activities, exploration, and depth to the game. what better setting than this to run a survivor-style gameshow with the game’s most popular content creators?
this particular challenge is a 1v1 slugfest-to-the-death where contestants take turns hitting each other, kind of like the back of the bus in elementary school. you can also skip your attack to eat food (recovering health); although you have a limited supply and the jeering crowd will make fun of you. winner gets the glory, loser gets booted off the island and the show.
this seemingly straightforward situation has a catch: both players are wearing dharok’s armor, an equipment set that notoriously deals more damage the lower your own hitpoints, which incentivizes risks and often leads to sudden shifts in momentum. for perspective, when you’re at 1% hp with this setup you can potentially deal over 90% of the opponent’s health bar in one hit. it’s a test of sheer nerve, akin to blackjack or the pocky game or starting a blog post right before work.
beating each other up: smarter
as skilled as the combatants are at the game (v the victim actually won the previous season!), my roommate and i felt like they did not play this challenge very well. and so, like any sane persons, we Did The Math. first we needed to program in the base stats for both players, their inventory, and their equipment.
actually, first we asked chatgpt to generate some boilerplate class structure for us to work in, but that kills the magic a little bit lol
we also needed to program a copy of the game’s combat engine for our calculations to work, which required some research using the runescape wiki.
attack and defense rolls, augmented by equipment
hit chance calculator
damage calculator
i spent some time making the functions somewhat extensible in case we wanted to include other actions, setups, or scenarios.
def hit_success(self, attack_roll, defense_roll):
if attack_roll > defense_roll:
hit_chance = 1 - (defense_roll + 2) / (2 * (attack_roll + 1))
else:
hit_chance = attack_roll / (2 * (defense_roll + 1))
did_hit = random.random() < hit_chance
return did_hit
finally, we came up with some differing strategies; mostly based on what the contestants did, mixed with our own intuition. these included:
always attack, no matter what
random behavior
only eating 38 hp food, and not eating after running out
eating until healthy (80% health)
eating only when there is risk of death
attacking whenever at a health advantage
we then pitted these strategies against each other, across thousands of bouts, in a round-robin fashion. but first, let’s try to go viral on reddit..
making a reddit post ???
i wanted to post this on /r/2007scape to receive the most exhilarating form of validation, which is from anonymous gamers. in order to survive there, a post either has to include: a disgustingly sweaty grind of some sort, or to have yellow text on a black background. our content certainly favors the latter.
since i no longer pay for an adobe subscription, we had to go for the tried-and-true next best tech stack: dingboard and google slides. slides is a bit finicky with custom fonts, so i used a “runescape font” generator and pasted images of our text in manually. i then installed the transmogrification plugin on runelite and visited the makeover mage to get some character screenshots. we also came up with funny names for each strategy obviously.
results / findings
the results were surprising yet not that interesting. eating until healthy won, shortly followed by eating at risk of death and attacking with an advantage. turns out the real contestants roughly did a loose version of the winning strategy.
i believe this is because:
attacking while at low hp is higher value, as long as you don’t go down immediately the next turn
eating at risk of death can get stuck eating when opponent has a large kill range
if you're right at the top of the opponent's kill range, the chance of getting KOed is quite low
in these situations, it might be advantageous to use your lower health to do some extra damage since they are also probably low as well.
attacking only while at an advantage means eating whenever at a disadvantage; this is kind of useless when both players are relatively healthy
the lower tier of food available heals 20hp. the average damage per attack is way lower than that due to how rarely attacks land
these bots are still better than us
this challenge also involves a lot of nerves, and even the suboptimal strategies made some assumptions about optimal play that neither contestant did properly. for example, players could choose their attack style and prayer style (basically which buff to use), and each situation (hitting, throwing knife, getting hit by axe, getting hit by knife) had an optimal option that was often missed on the show. i even calculated a very slight advantage towards using the accurate attack style instead of the aggressive one by running a bunch of simulations (it’s better by like 0.2%)
i didnt do that good of a job tbh
i very naively chose strategies here. for example, eating to 80% hp is entirely arbitrary. a more complex strategy that’s aware of the opponent’s kill range and makes calculated risks to maximize damage. we could even use reinforcement learning on these agents, although i feel like an analytical math solution exists based on how simple this system is.
as for the challenge itself, i was brainstorming with soup (host of the show) and we both agreed that this iteration felt like it had a great balance between strategy and volatility for viewing pleasure. one interesting twist i suggested was to allow players to use vengeance, a spell that reflects damage, to keep each other guessing at their next move.