Advertisement
aaaaaa123456789

firefight's Runescape winning odds calculator

May 28th, 2013
148
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <stdlib.h>
  2. #include <string.h>
  3.  
  4. typedef struct {
  5.   unsigned char HP;
  6.   unsigned char attack;
  7.   unsigned char defense;
  8.   unsigned char strength;
  9. } PlayerStats;
  10.  
  11. typedef struct {
  12.   long double hitChance;
  13.   unsigned char maxDamage;
  14.   unsigned char hitPoints;
  15. } PlayerInfo;
  16.  
  17. typedef struct {
  18.   long double win;
  19.   long double lose;
  20.   long double draw;
  21. } Odds;
  22.  
  23. const Odds error = {0, 0, 0};
  24.  
  25. static long double getHitChance(unsigned char, unsigned char);
  26. static unsigned char getMaxDamage(unsigned char);
  27.  
  28. static Odds calculateOdds(PlayerInfo, PlayerInfo, long double);
  29.  
  30. static void turnsOdds(unsigned char, long double *, long double **, unsigned *, long double);
  31. static void hitsOdds(unsigned char, long double, long double *);
  32. static void multiplyVector(long double *, long double *, long double);
  33. static void addVector(long double *, long double *);
  34. static long double totalOdds(long double *);
  35. static long double currentError(long double *, unsigned char);
  36. static void expand(long double **, unsigned, unsigned);
  37. static Odds calculateFor(long double *, long double *, unsigned);
  38.  
  39. long double winningOdds (PlayerStats player1, PlayerStats player2, unsigned char firstMove, long double threshold) {
  40.   PlayerInfo p1, p2;
  41.   if (player1.HP > 99) return 0;
  42.   if (player2.HP > 99) return 0;
  43.   if (player1.strength > 102) return 0;
  44.   if (player2.strength > 102) return 0;
  45.   if (threshold <= 0) return 0;
  46.   if (threshold >= 1) return 0;
  47.   if (firstMove > 2) return 0;
  48.   p1.hitChance = getHitChance(player1.attack, player2.defense);
  49.   p2.hitChance = getHitChance(player2.attack, player1.defense);
  50.   p1.maxDamage = getMaxDamage(player1.strength);
  51.   p2.maxDamage = getMaxDamage(player2.strength);
  52.   p1.hitPoints = player1.HP;
  53.   p2.hitPoints = player2.HP;
  54.   Odds odds = calculateOdds(p1, p2, threshold);
  55.   switch (firstMove) {
  56.     case 1:
  57.       return odds.win + odds.draw;
  58.     case 2:
  59.       return odds.win;
  60.     default:
  61.       return odds.win + (odds.draw / 2);
  62.   }
  63. }
  64.  
  65. static long double getHitChance (unsigned char attack, unsigned char defense) {
  66.   long double adjustedAttack = attack + 8;
  67.   long double adjustedDefense = defense + 8;
  68.   if (attack <= defense)
  69.     return (adjustedAttack - 1) / (2 * adjustedDefense);
  70.   else
  71.     return 1.0L - ((adjustedDefense + 1) / (2 * adjustedAttack));
  72. }
  73.  
  74. static unsigned char getMaxDamage (unsigned char strength) {
  75.   return (strength + 13) / 10;
  76. }
  77.  
  78. static Odds calculateOdds (PlayerInfo p1, PlayerInfo p2, long double threshold) {
  79.   unsigned t1, t2;
  80.   long double * odds1;
  81.   long double * odds2;
  82.   long double hitodds1[12];
  83.   long double hitodds2[12];
  84.   unsigned turns;
  85.   if ((p1.hitChance < 0) || (p1.hitChance > 1)) return error;
  86.   if ((p2.hitChance < 0) || (p2.hitChance > 1)) return error;
  87.   if ((!p1.maxDamage) || (p1.maxDamage > 11)) return error;
  88.   if ((!p2.maxDamage) || (p2.maxDamage > 11)) return error;
  89.   if (p1.hitPoints > 99) return error;
  90.   if (p2.hitPoints > 99) return error;
  91.   if ((threshold <= 0) || (threshold >= 1)) return error;
  92.   hitsOdds(p1.maxDamage, p1.hitChance, hitodds1);
  93.   hitsOdds(p2.maxDamage, p2.hitChance, hitodds2);
  94.   turnsOdds(p2.hitPoints, hitodds1, &odds1, &t1, threshold);
  95.   turnsOdds(p1.hitPoints, hitodds2, &odds2, &t2, threshold);
  96.   if (t1 < t2) {
  97.     expand(&odds1, t1, t2);
  98.     turns = t2;
  99.   } else if (t2 < t1) {
  100.     expand(&odds2, t2, t1);
  101.     turns = t1;
  102.   } else
  103.     turns = t1;
  104.   Odds result = calculateFor(odds1, odds2, turns);
  105.   free(odds1);
  106.   free(odds2);
  107.   long double totalError = 1;
  108.   totalError -= result.win;
  109.   totalError -= result.lose;
  110.   totalError -= result.draw;
  111.   if ((totalError * totalError) > (threshold * threshold * 10)) return calculateOdds(p1, p2, threshold / 10);
  112.   result.draw += totalError;
  113.   return result;
  114. }
  115.  
  116. static void turnsOdds (unsigned char opponentHP, long double * hitOdds, long double ** result, unsigned * resultSize, long double threshold) {
  117.   unsigned turns = 0;
  118.   long double * turnOdds = malloc(sizeof(long double));
  119.   *turnOdds = 1;
  120.   long double damageDealtA[111];
  121.   long double damageDealtB[111];
  122.   unsigned char current = 0;
  123.   long double * damageDealt;
  124.   long double * damageDealtPrev;
  125.   memset(damageDealtA, 0, 111 * sizeof(long double));
  126.   *damageDealtA = 1;
  127.   unsigned currentTurn;
  128.   long double curDamage[12];
  129.   unsigned char curHP;
  130.   do {
  131.     currentTurn = turns;
  132.     turns += 20;
  133.     turnOdds = realloc(turnOdds, sizeof(long double) * (turns + 1));
  134.     for (currentTurn ++; currentTurn <= turns; currentTurn ++) {
  135.       damageDealtPrev = current ? damageDealtB : damageDealtA;
  136.       damageDealt = current ? damageDealtA : damageDealtB;
  137.       memset(damageDealt, 0, 111 * sizeof(long double));
  138.       for (curHP = 0; curHP < opponentHP; curHP ++) {
  139.         multiplyVector(curDamage, hitOdds, damageDealtPrev[curHP]);
  140.         addVector(damageDealt + curHP, curDamage);
  141.       }
  142.       turnOdds[currentTurn] = totalOdds(damageDealt + opponentHP);
  143.       current = !current;
  144.     }
  145.     damageDealt = current ? damageDealtA : damageDealtB;
  146.     *turnOdds = currentError(damageDealt, opponentHP);
  147.   } while (*turnOdds >= threshold);
  148.   *result = turnOdds;
  149.   *resultSize = turns;
  150. }
  151.  
  152. static void hitsOdds (unsigned char maxDamage, long double hitChance, long double * result) {
  153.   *result = 1 - hitChance;
  154.   long double x = hitChance / maxDamage;
  155.   unsigned char pos;
  156.   for (pos = 1; pos <= maxDamage; pos ++) result[pos] = x;
  157.   for (; pos <= 11; pos ++) result[pos] = 0;
  158. }
  159.  
  160. static void multiplyVector (long double * result, long double * src, long double value) {
  161.   unsigned char pos;
  162.   for (pos = 0; pos < 12; pos ++)
  163.     result[pos] = src[pos] * value;
  164. }
  165.  
  166. static void addVector (long double * dst, long double * src) {
  167.   unsigned char pos;
  168.   for (pos = 0; pos < 12; pos ++)
  169.     dst[pos] += src[pos];
  170. }
  171.  
  172. static long double totalOdds (long double * damageOdds) {
  173.   long double total = 0;
  174.   unsigned char pos;
  175.   for (pos = 0; pos < 12; pos ++)
  176.     total += damageOdds[pos];
  177.   return total;
  178. }
  179.  
  180. static long double currentError (long double * damageOdds, unsigned char maxDamage) {
  181.   long double total = 0;
  182.   unsigned char pos;
  183.   for (pos = 0; pos < maxDamage; pos ++)
  184.     total += damageOdds[pos];
  185.   return total;
  186. }
  187.  
  188. static void expand (long double ** turnOdds, unsigned from, unsigned to) {
  189.   *turnOdds = realloc(*turnOdds, sizeof(long double) * (to + 1));
  190.   unsigned pos;
  191.   for (pos = from + 1; pos <= to; pos ++)
  192.     (*turnOdds)[pos] = 0;
  193. }
  194.  
  195. static Odds calculateFor (long double * turnOdds1, long double * turnOdds2, unsigned turns) {
  196.   long double r0 = 0, r1 = 0, r2 = 0;
  197.   unsigned turn1, turn2;
  198.   for (turn1 = 1; turn1 <= turns; turn1 ++) {
  199.     for (turn2 = 1; turn2 < turn1; turn2 ++)
  200.       r2 += turnOdds1[turn1] * turnOdds2[turn2];
  201.     r0 += turnOdds1[turn1] * turnOdds2[turn1];
  202.     for (turn2 = turn1 + 1; turn2 <= turns; turn2 ++)
  203.       r1 += turnOdds1[turn1] * turnOdds2[turn2];
  204.     r1 += turnOdds1[turn1] * (*turnOdds2);
  205.   }
  206.   for (turn2 = 1; turn2 <= turns; turn2 ++)
  207.     r2 += turnOdds2[turn2] * (*turnOdds1);
  208.   r0 += (*turnOdds1) * (*turnOdds2);
  209.   return (Odds) {.win = r1, .lose = r2, .draw = r0};
  210. }
Advertisement
RAW Paste Data Copied
Advertisement