Преобразование набранных очков в сыгранные часы (математика) - PullRequest
0 голосов
/ 04 ноября 2018

Мне нужно использовать простой JavaScript, чтобы преобразовать количество очков опыта в количество часов, сыгранных по ряду фиксированных ставок.

Например:

Игрок имеет 1,129,518 очков опыта.

Количество очков опыта, получаемых за час, зависит от количества очков опыта, которое уже есть. Они бы устроились примерно так:

выше 0 xp: 8000 xp / h

выше 2,107 xp: 20 000 xp / h

выше 101,333 xp: 45 000 xp / h

выше 1,210,421 xp: 68 500 xp / h

выше 13 034 431 xp: 75 000 xp / h

Я изо всех сил пытаюсь найти способ использовать эти xp ставки для преобразования заданного количества очков опыта в часы игры, используя хотя бы несколько изящный Javascript.

Я просто получаю странный беспорядок в операторах if / else, который заканчивается неудачей из-за математических ошибок.

Есть какие-нибудь математические волшебники, которые могут мне помочь? Спасибо.

Пример кода: я бы пошел отсюда

 if(xp === 0){
    return 0;
}else if( 2107 >= xp > 0){
    const result = (xp/8000).toFixed(1);
    return result;
}else if(101333 >= xp > 2107){
    const result = ((2107/8000) + ((xp-2107)/20000)).toFixed(1);
    return result;
}else if(1210421 >= xp > 101333){
    ...
}

Как вы можете видеть, это быстро вышло бы из-под контроля, если бы было много разных уровней.

Ответы [ 3 ]

0 голосов
/ 04 ноября 2018

Вот что я придумал:

const steps = [{
    min: 0,
    val: 8000
  },
  {
    min: 2107,
    val: 20000
  },
  {
    min: 101333,
    val: 45000
  },
  {
    min: 1210421,
    val: 68500
  },
  {
    min: 13034431,
    val: 75000
  },
].sort((a, b) => b.min - a.min);

//using for loop
function xpToHours(xp = 0) {
  let h = 0;
  steps.forEach(s => {
    let amt = Math.max(xp - s.min, 0);
    h += amt * s.val;
    xp -= amt;
  });
  return h;
}

//using reduce
function xpToHours2(xp = 0) {
  return steps.reduce((h, s) => {
    let amt = Math.max(xp - s.min, 0);
    xp -= amt;
    return h + amt * s.val;
  }, 0)
}


[0, 1000, 2000, 3000, 1000000].forEach(xp => console.log(xp, xpToHours(xp)));
[0, 1000, 2000, 3000, 1000000].forEach(xp => console.log(xp, xpToHours2(xp)));

Объяснить:

steps это просто массив, содержащий ваши различные этапы. Сортируется по минимальному xp от наивысшего к низшему.

Затем мы просто перебираем этот массив, вычисляя amt, который представляет собой xp, использованный самой высокой на данный момент стадией. Следовательно, необходимое время составляет amt * currentstep.val, а xp уменьшается на рассчитанную сумму для следующего этапа.

0 голосов
/ 04 ноября 2018

Самый простой способ сделать это - отсортированный массив диапазонов и Array.prototype.find

// Make sure this is sorted desc
const expRanges = [{
    above: 101333,
    xph: 45000
  },
  {
    above: 2107,
    xph: 20000
  },
  {
    above: 0,
    xph: 8000
  }
];

function findExpPerHour(xp) {
  return expRanges.find(range => range.above < xp).xph;
}

// TESTS
const playerExpTests = [{
  name: "P1",
  xp: 12
}, {
  name: "P2",
  xp: 12000
}, {
  name: "P3",
  xp: 200000
}, {
  name: "P4",
  xp: 99999999
}];

playerExpTests.forEach(p => {
  console.log(p.name, "Exp per hour:", findExpPerHour(p.xp));
});
0 голосов
/ 04 ноября 2018

Прежде всего, вы должны написать свои операторы if следующим образом:

if( 2107 >= xp && xp > 0){
    ...
}

Далее, попробуйте представить XP как корзины XP, и каждая корзина имеет разную стоимость / цену. Перейдите от самого ценного сегмента к наименее ценному, и для каждого сегмента рассчитайте часы и вычтите количество XP, использованное для расчета этих часов.

Вы можете сделать это в цикле while:

let hours = 0;
while(XP > 0)
{
  // figure out bucket you are in, your if statements are fine for that.
  let value = 0;
  let lowerBoundary = 0;
  if( 101333 >= xp && xp > 2107){
    value = 20000;
    lowerBoundary = 2107;
    // you need lower boundary to figure out how many XP you used in this bucket.
  }
  // else if...
  const usedInBucket = XP - lowerBoundary;
  hours += usedInBucket / value; // simply calculate hours needed
  XP -= usedInBucket;
}
...