Desktop Dungeons Shops

Calculate probabilities for item spawns in desktop dungeons shops.

by Phoil

HTML

<label for="shops">Shops:</label>
<input id="shops" type="text" value="8">
<br>
<label for="order">Order:</label>
<select id="order" value="bqe">
  <option value="bqe">Basic Quest Elite</option>
  <option value="qbe">Quest Basic Elite</option>
  <option value="ebq">Elite Basic Quest</option>
  <option value="qeb">Quest Elite Basic</option>
  <option value="eqb">Elite Quest Basic</option>
</select>
<br>
<button id="update">Update</button>
<table id="itemlist"></table>

JavaScript

function p_one(i, n) {
  return (2 * (n - 1 - i) + 1) / n / n;
}

function p_range(i1, i2, n) {
  var l1 = (n - i1);
  var l2 = (n - i2 - 1);
  return (l1 * l1 - l2 * l2) / n / n;
}

function p_multi(i, n, s) {
  var p = p_one(i, n);
  if (s > 1) {
    if (i > 0) {
      p += p_range(0, i - 1, n) * p_multi(i - 1, n - 1, s - 1);
    }
    if (i < n - 1) {
      p += p_range(i + 1, n - 1, n) * p_multi(i, n - 1, s - 1)
    }
  }
  return p;
}

var items = [
  "HealthPendantItem",
  "ManaPendant",
  "BloodySigil",
  "FineSword",
  "TrollHeart",
  "BadgeOfHonour",
  "TowerShield",
  "Spoon",
  "FireHeart",
  "HeroHelmet",
  "BattleMage",
  "VenomSword",
  "WhurrSword",
  "VampireSword",
  "Platemail",
  "CorrosiveGlove",
  "Agnostic",
  "StoneSigil",
  "MidasGlove",
  "BlueBead",
  "BalancedSword",
  "TriSword",
  "MagePlate",
  "SoulOrb",
  "ViperWard",
  "DragonSoul",
  "RockHeart",
  "PierceWand",
  "CrystalBall",
  "WitchPendant",
  "DwarvenGauntlets",
  "ElvenBoots",
  "KegOHealth",
  "KegOMana",
  "AlchemistsScroll",
  "WickedGuitar",
  "YendorAmulet",
  "ZotOrb"
];
var itemrange = {
  "b": {
    "first": 0,
    "last": 7
  },
  "q": {
    "first": 8,
    "last": 29
  },
  "e": {
    "first": 30,
    "last": 37
  }
};

var itemlist = [];
for (var i = 0; i < items.length; i++) {
  var row = [];
  row.push('<input id="enable' + i + '" type="checkbox" checked=1"></input>')
  row.push(items[i]);
  row.push('<span id="prob' + i + '"></span>')
  itemlist.push('<td>' + row.join('</td><td>') + '</td>');
}
document.getElementById('itemlist').innerHTML = '<tr>' + itemlist.join('</tr><tr>') + '</tr>';

function updateRange(r, i, n, s) {
  for (var j = r.first; j <= r.last; j++) {
    var prob = 0;
    if (document.getElementById('enable' + j).checked) {
      prob = p_multi(i, n, s) * 100;
      i++;
    }
    document.getElementById('prob' + j).textContent = prob;
  }
  return i;
};

document.getElementById('update').onclick = function() {
  var shops =...