假设我有这个公式,例如:
function getExperience(level) {
let a = 0;
for (let x = 1; x < level; x += 1) {
a += Math.floor(x + (200 * (2 ** (x / 3))));
}
return Math.floor(a / 4);
}
for (var i = 1; i < 100; i++) {
console.log(`Level ${i}: ${getExperience(i)}`);
}Run Code Online (Sandbox Code Playgroud)
要获得50级所需的经验,你可以:getExperience(50).
但是,你会如何扭转这种局面并获得经验所需的水平?所以,getLevel(20010272)会输出50.
Eri*_*nil 42
您可以使用4.328085 * Math.log(0.00519842 * xp + 1.259921045)相应级别的非常好的近似值.
如果您需要精确值,则可以迭代所有级别,直到找到所需的范围,如此答案中所示.
我认为不可能为此函数的反函数找到精确的闭合形式表达式.但是,如果你修改getExperience(level)一下,应该可以.
x增长速度要慢得多2 ** (x / 3).Math.floor对大数字的影响不大.所以让我们删除它们!这是稍微修改过的功能:
function getExperienceEstimate(level) {
let a = 0;
for (let x = 1; x < level; x += 1) {
a += 200 * (2 ** (x / 3));
}
return a / 4;
}
Run Code Online (Sandbox Code Playgroud)
这种方法的优点是它现在是一个几何级数,所以可以直接计算总和,而不需要任何循环:
function getExperienceEstimate(level) {
let a = 50;
let r = 2 ** (1 / 3);
return a * (r**level - r) / (r - 1);
};
Run Code Online (Sandbox Code Playgroud)
getExperienceEstimate(50)返回20011971.993575357,仅比0.0015%小getExperience(50).
根据Wolfram Alpha的说法,这是反函数getExperienceEstimate:
function getLevelEstimate(xp){
let a = 50;
let r = 2 ** (1 / 3);
return Math.log(xp * (r - 1) / a + r) / Math.log(r);
};
Run Code Online (Sandbox Code Playgroud)
由于精度损失较小,您可以进一步简化:
function getLevelEstimate(xp){
return 4.328085 * Math.log(0.00519842 * xp + 1.259921045)
};
Run Code Online (Sandbox Code Playgroud)
这只是一个估计,但它运作良好,不需要任何循环!
对于20012272 XP,近似反函数返回50.00006263463371,如果要查找确切结果,这应该是一个很好的起点.
function getExperience(level) {
let a = 0;
for (let x = 1; x < level; x += 1) {
a += Math.floor(x + (200 * (2 ** (x / 3))));
}
return Math.floor(a / 4);
}
function getLevelEstimate(xp){
return 4.328085 * Math.log(0.00519842 * xp + 1.259921045)
};
for (var i = 1; i < 100; i++) {
console.log(`Level ${i} (XP = ${getExperience(i)}). Estimated level : ${getLevelEstimate(getExperience(i))}`);
}Run Code Online (Sandbox Code Playgroud)
Arm*_*mel 12
您可以使用二进制搜索算法来避免遍历所有可能性.
这是我适应你案例的一个例子.
你首先需要创建一个数组来映射你的所有level => experience,这个动作应该只在ONCE完成,然后你再也不用了.
正如您在我的示例中所看到的,即使有1000个级别,您也不必迭代超过您想要查找的级别的9倍.
// You first have to create an array with all your levels.
// This has to be done only ONCE because it's an expensive one!
const list = [];
for (let i = 1; i <= 1000; i++) {
list[i] = getExperience(i);
}
function getExperience(level) {
let a = 0;
for (let x = 1; x < level; x += 1) {
a += Math.floor(x + (200 * (2 ** (x / 3))));
}
return Math.floor(a / 4);
}
function getLevel(value) {
// initial values for start, middle and end
let start = 0
let stop = list.length - 1
let middle = Math.floor((start + stop) / 2)
let iterations = 0;
// While the middle is not what we're looking for and the list does not have a single item.
while (list[middle] !== value && start < stop) {
iterations++;
if (value < list[middle]) {
stop = middle - 1
} else {
start = middle + 1
}
// Recalculate middle on every iteration.
middle = Math.floor((start + stop) / 2)
}
console.log(`${value} is Level ${middle} (Result found after ${iterations} iterations)`);
return middle;
}
// Then you can search your level according to the experience
getLevel(0);
getLevel(72);
getLevel(20010272);
getLevel(getExperience(50));
getLevel(33578608987644589722);Run Code Online (Sandbox Code Playgroud)
Cer*_*nce 11
一个蛮力(但不优雅)的解决方案就是调用getExperience级别,直到达到需要比传递的更多经验的级别exp:
function getLevel(exp) {
if (exp === 0) return 0;
let level = 0;
let calcExp = 0;
while (exp > calcExp) {
calcExp = getExperience(level);
if (calcExp > exp) break;
level++;
}
return level - 1;
}
console.log(getLevel(20012272)); // experience required for 50 on the dot
console.log(getLevel(20012270));
console.log(getLevel(20012274));
console.log(getLevel(0));
function getExperience(level) {
let a = 0;
for (let x = 1; x < level; x += 1) {
a += Math.floor(x + (200 * (2 ** (x / 3))));
}
return Math.floor(a / 4);
}Run Code Online (Sandbox Code Playgroud)