forked from mirrors/0ad
Unify random integer and float helper functions of GUI, Simulation and AI.
Patch By: bb
Differential Revision: D121
Refs: #4326
Removes the Random.js simulation helper and randomFloat function of the
random map scripts library.
Adds randomIntInclusive and randomIntExclusive to make the calls more
readable and fix and prevent off-by-one mistakes.
Adds randBool and use it in an AI occurance. It will be used in many
places by the random map scripts.
Use the pickRandom function introduced in 3c56638e8b in more applicable
occurances.
Replace remaining occurances of Math.random() with the new functions to
easily test completeness.
Cleanup of the random map script functions will come in a separate
commit.
This was SVN commit r19270.
This commit is contained in:
@@ -16,9 +16,50 @@ function randomNormal2D()
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random element of the source array
|
||||
* Return a random element of the source array.
|
||||
*/
|
||||
function pickRandom(source)
|
||||
{
|
||||
return source.length ? source[Math.floor(source.length * Math.random())] : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random floating point number.
|
||||
*
|
||||
* If two parameters are given, and the returned float is in the interval [min, max).
|
||||
* If no parameter is given, the returned float is in the interval [0, 1).
|
||||
*/
|
||||
function randFloat(min = 0, max = 1)
|
||||
{
|
||||
return min + Math.random() * (max - min);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random integer of the interval [floor(min) .. ceil(max)] using Math.random library.
|
||||
*
|
||||
* If an argument is not integer, the uniform distribution is cut off at that endpoint.
|
||||
* For example randIntInclusive(1.5, 2.5) yields 50% chance to get 2 and 25% chance for 1 and 3.
|
||||
*/
|
||||
function randIntInclusive(min, max)
|
||||
{
|
||||
return Math.floor(min + Math.random() * (max + 1 - min));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random integer of the interval [floor(min) .. ceil(max-1)].
|
||||
*
|
||||
* If an argument is not integer, the uniform distribution is cut off at that endpoint.
|
||||
* For example randIntExclusive(1.5, 3.5) yields 50% chance to get 2 and 25% chance for 1 and 3.
|
||||
*/
|
||||
function randIntExclusive(min, max)
|
||||
{
|
||||
return Math.floor(min + Math.random() * (max - min));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true or false randomly.
|
||||
*/
|
||||
function randBool()
|
||||
{
|
||||
return Math.random() < 0.5;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ function shuffleArray(source)
|
||||
let result = [source[0]];
|
||||
for (let i = 1; i < source.length; ++i)
|
||||
{
|
||||
let j = Math.floor(Math.random() * (i+1));
|
||||
let j = randIntInclusive(0, i);
|
||||
result[i] = result[j];
|
||||
result[j] = source[i];
|
||||
}
|
||||
|
||||
@@ -3,16 +3,6 @@
|
||||
*/
|
||||
var g_LastNickNotification = -1;
|
||||
|
||||
function getRandom(randomMin, randomMax)
|
||||
{
|
||||
// Returns a random whole number in a min..max range.
|
||||
// NOTE: There should probably be an engine function for this,
|
||||
// since we'd need to keep track of random seeds for replays.
|
||||
|
||||
var randomNum = randomMin + (randomMax-randomMin)*Math.random(); // num is random, from A to B
|
||||
return Math.round(randomNum);
|
||||
}
|
||||
|
||||
// Get list of XML files in pathname with recursion, excepting those starting with _
|
||||
function getXMLFileList(pathname)
|
||||
{
|
||||
|
||||
@@ -79,7 +79,7 @@ Music.prototype.updateState = function()
|
||||
break;
|
||||
|
||||
case this.states.MENU:
|
||||
this.switchMusic(this.getRandomTrack(this.tracks.MENU), 0.0, true);
|
||||
this.switchMusic(pickRandom(this.tracks.MENU), 0, true);
|
||||
break;
|
||||
|
||||
case this.states.PEACE:
|
||||
@@ -130,11 +130,6 @@ Music.prototype.storeTracks = function(civMusic)
|
||||
}
|
||||
};
|
||||
|
||||
Music.prototype.getRandomTrack = function(tracks)
|
||||
{
|
||||
return tracks[getRandom(0, tracks.length-1)];
|
||||
};
|
||||
|
||||
Music.prototype.startPlayList = function(tracks, fadeInPeriod, isLooping)
|
||||
{
|
||||
Engine.ClearPlaylist();
|
||||
|
||||
@@ -1298,8 +1298,7 @@ function launchGame()
|
||||
{
|
||||
let victoryScriptsSelected = g_GameAttributes.settings.VictoryScripts;
|
||||
let gameTypeSelected = g_GameAttributes.settings.GameType;
|
||||
selectMap(Engine.GetGUIObjectByName("mapSelection").list_data[Math.floor(Math.random() *
|
||||
(Engine.GetGUIObjectByName("mapSelection").list.length - 1)) + 1]);
|
||||
selectMap(pickRandom(Engine.GetGUIObjectByName("mapSelection").list_data.slice(1)));
|
||||
g_GameAttributes.settings.VictoryScripts = victoryScriptsSelected;
|
||||
g_GameAttributes.settings.GameType = gameTypeSelected;
|
||||
}
|
||||
@@ -1322,9 +1321,8 @@ function launchGame()
|
||||
let chosenCiv = g_GameAttributes.settings.PlayerData[i].Civ || "random";
|
||||
if (chosenCiv == "random")
|
||||
{
|
||||
let culture = cultures[Math.floor(Math.random() * cultures.length)];
|
||||
let civs = Object.keys(g_CivData).filter(civ => g_CivData[civ].Culture == culture);
|
||||
chosenCiv = civs[Math.floor(Math.random() * civs.length)];
|
||||
let culture = pickRandom(cultures);
|
||||
chosenCiv = pickRandom(Object.keys(g_CivData).filter(civ => g_CivData[civ].Culture == culture));
|
||||
}
|
||||
g_GameAttributes.settings.PlayerData[i].Civ = chosenCiv;
|
||||
|
||||
@@ -1332,7 +1330,7 @@ function launchGame()
|
||||
if (g_GameAttributes.mapType === "scenario" || !g_GameAttributes.settings.PlayerData[i].AI)
|
||||
continue;
|
||||
|
||||
let chosenName = g_CivData[chosenCiv].AINames[Math.floor(Math.random() * g_CivData[chosenCiv].AINames.length)];
|
||||
let chosenName = pickRandom(g_CivData[chosenCiv].AINames);
|
||||
|
||||
if (!g_IsNetworked)
|
||||
chosenName = translate(chosenName);
|
||||
@@ -1352,8 +1350,8 @@ function launchGame()
|
||||
}
|
||||
|
||||
// Seed used for both map generation and simulation
|
||||
g_GameAttributes.settings.Seed = Math.floor(Math.random() * Math.pow(2, 32));
|
||||
g_GameAttributes.settings.AISeed = Math.floor(Math.random() * Math.pow(2, 32));
|
||||
g_GameAttributes.settings.Seed = randIntExclusive(0, Math.pow(2, 32));
|
||||
g_GameAttributes.settings.AISeed = randIntExclusive(0, Math.pow(2, 32));
|
||||
|
||||
// Used for identifying rated game reports for the lobby
|
||||
g_GameAttributes.matchID = Engine.GetMatchID();
|
||||
|
||||
@@ -13,7 +13,7 @@ function init(data)
|
||||
if (tipTextLoadingArray.length > 0)
|
||||
{
|
||||
// Set tip text
|
||||
let tipTextFilePath = tipTextLoadingArray[getRandom(0, tipTextLoadingArray.length-1)];
|
||||
let tipTextFilePath = pickRandom(tipTextLoadingArray);
|
||||
let tipText = Engine.TranslateLines(Engine.ReadFile(tipTextFilePath));
|
||||
|
||||
if (tipText)
|
||||
@@ -62,7 +62,7 @@ function init(data)
|
||||
|
||||
// Pick a random quote of the day (each line is a separate tip).
|
||||
let quoteArray = Engine.ReadFileLines("gui/text/quotes.txt");
|
||||
Engine.GetGUIObjectByName("quoteText").caption = translate(quoteArray[getRandom(0, quoteArray.length-1)]);
|
||||
Engine.GetGUIObjectByName("quoteText").caption = translate(pickRandom(quoteArray));
|
||||
}
|
||||
|
||||
function displayProgress()
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
var userReportEnabledText; // contains the original version with "$status" placeholder
|
||||
var currentSubmenuType; // contains submenu type
|
||||
const MARGIN = 4; // menu border size
|
||||
var g_BackgroundCode; // Background type.
|
||||
|
||||
var g_ShowSplashScreens;
|
||||
|
||||
/**
|
||||
* Available backdrops
|
||||
*/
|
||||
var g_BackgroundLayerData = [];
|
||||
|
||||
/**
|
||||
* Chosen backdrop
|
||||
*/
|
||||
var g_BackgroundLayerset;
|
||||
|
||||
var g_T0 = +(new Date());
|
||||
var g_LastTickTime = new Date();
|
||||
|
||||
@@ -26,13 +34,12 @@ function init(initData, hotloadData)
|
||||
g_ShowSplashScreens = hotloadData ? hotloadData.showSplashScreens : initData && initData.isStartup;
|
||||
|
||||
// Pick a random background and initialise it
|
||||
g_BackgroundCode = Math.floor(Math.random() * g_BackgroundLayerData.length);
|
||||
var layerset = g_BackgroundLayerData[g_BackgroundCode];
|
||||
for (var i = 0; i < layerset.length; ++i)
|
||||
g_BackgroundLayerset = pickRandom(g_BackgroundLayerData);
|
||||
for (let i = 0; i < g_BackgroundLayerset.length; ++i)
|
||||
{
|
||||
var guiObj = Engine.GetGUIObjectByName("background["+i+"]");
|
||||
guiObj.hidden = false;
|
||||
guiObj.sprite = layerset[i].sprite;
|
||||
guiObj.sprite = g_BackgroundLayerset[i].sprite;
|
||||
guiObj.z = i;
|
||||
}
|
||||
}
|
||||
@@ -44,10 +51,8 @@ function getHotloadData()
|
||||
|
||||
function scrollBackgrounds()
|
||||
{
|
||||
var layerset = g_BackgroundLayerData[g_BackgroundCode];
|
||||
for (var i = 0; i < layerset.length; ++i)
|
||||
for (let i = 0; i < g_BackgroundLayerset.length; ++i)
|
||||
{
|
||||
var layer = layerset[i];
|
||||
var guiObj = Engine.GetGUIObjectByName("background["+i+"]");
|
||||
|
||||
var screen = guiObj.parent.getComputedSize();
|
||||
@@ -56,8 +61,8 @@ function scrollBackgrounds()
|
||||
var iw = h * 2;
|
||||
|
||||
var time = (new Date() - g_T0) / 1000;
|
||||
var offset = layer.offset(time, w);
|
||||
if (layer.tiling)
|
||||
var offset = g_BackgroundLayerset[i].offset(time, w);
|
||||
if (g_BackgroundLayerset[i].tiling)
|
||||
{
|
||||
var left = offset % iw;
|
||||
if (left >= 0)
|
||||
|
||||
@@ -36,7 +36,7 @@ PlacementSupport.prototype.SetDefaultAngle = function()
|
||||
|
||||
PlacementSupport.prototype.RandomizeActorSeed = function()
|
||||
{
|
||||
this.actorSeed = Math.floor(65535 * Math.random());
|
||||
this.actorSeed = randIntExclusive(0, Math.pow(2, 16));
|
||||
};
|
||||
|
||||
var placementSupport = new PlacementSupport();
|
||||
|
||||
@@ -1257,7 +1257,7 @@ function updateAdditionalHighlight()
|
||||
|
||||
function playAmbient()
|
||||
{
|
||||
Engine.PlayAmbientSound(g_Ambient[Math.floor(Math.random() * g_Ambient.length)], true);
|
||||
Engine.PlayAmbientSound(pickRandom(g_Ambient), true);
|
||||
}
|
||||
|
||||
function getBuildString()
|
||||
|
||||
@@ -1,31 +1,5 @@
|
||||
// TODO: rename/change these functions, so the bounds are more clear
|
||||
|
||||
/*
|
||||
* Return a random floating point number using Math.random library
|
||||
*
|
||||
* If no parameter given, the returned float is in the interval [0, 1)
|
||||
* If two parameters are given, they are minval and maxval, and the returned float is in the interval [minval, maxval)
|
||||
*/
|
||||
function randFloat()
|
||||
{
|
||||
if (arguments.length == 0)
|
||||
{
|
||||
return Math.random();
|
||||
}
|
||||
else if (arguments.length == 2)
|
||||
{
|
||||
var minVal = arguments[0];
|
||||
var maxVal = arguments[1];
|
||||
|
||||
return minVal + randFloat() * (maxVal - minVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("randFloat: invalid number of arguments: "+arguments.length);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a random integer using Math.random library
|
||||
*
|
||||
|
||||
@@ -158,7 +158,7 @@ m.AttackPlan = function(gameState, Config, uniqueID, type, data)
|
||||
}
|
||||
|
||||
// Put some randomness on the attack size
|
||||
let variation = 0.8 + 0.4*Math.random();
|
||||
let variation = randFloat(0.8, 1.2);
|
||||
// and lower priority and smaller sizes for easier difficulty levels
|
||||
if (this.Config.difficulty < 2)
|
||||
{
|
||||
@@ -1444,7 +1444,7 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
||||
ent.attack(mStruct[0].id(), m.allowCapture(gameState, ent, mStruct[0]));
|
||||
else
|
||||
{
|
||||
let rand = Math.floor(Math.random() * mStruct.length * 0.2);
|
||||
let rand = randIntExclusive(0, mStruct.length * 0.2);
|
||||
ent.attack(mStruct[rand].id(), m.allowCapture(gameState, ent, mStruct[rand]));
|
||||
}
|
||||
}
|
||||
@@ -1502,7 +1502,7 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
||||
valb -= 20000;
|
||||
return valb - vala;
|
||||
});
|
||||
let rand = Math.floor(Math.random() * mUnit.length * 0.1);
|
||||
let rand = randIntExclusive(0, mUnit.length * 0.1);
|
||||
ent.attack(mUnit[rand].id(), m.allowCapture(gameState, ent, mUnit[rand]));
|
||||
}
|
||||
else if (this.isBlocked)
|
||||
@@ -1553,7 +1553,7 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
||||
ent.attack(mStruct[0].id(), false);
|
||||
else
|
||||
{
|
||||
let rand = Math.floor(Math.random() * mStruct.length * 0.2);
|
||||
let rand = randIntExclusive(0, mStruct.length * 0.2);
|
||||
ent.attack(mStruct[rand].id(), m.allowCapture(gameState, ent, mStruct[rand]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,9 +131,9 @@ m.Config.prototype.setConfig = function(gameState)
|
||||
// initialize personality traits
|
||||
if (this.difficulty > 1)
|
||||
{
|
||||
this.personality.aggressive = Math.random();
|
||||
this.personality.cooperative = Math.random();
|
||||
this.personality.defensive = Math.random();
|
||||
this.personality.aggressive = randFloat(0, 1);
|
||||
this.personality.cooperative = randFloat(0, 1);
|
||||
this.personality.defensive = randFloat(0, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -216,7 +216,7 @@ m.DiplomacyManager.prototype.lastManStandingCheck = function(gameState)
|
||||
// wait a bit before turning
|
||||
if (!this.waitingToBetray)
|
||||
{
|
||||
this.betrayLapseTime = gameState.ai.elapsedTime + Math.random() * 100 + 10;
|
||||
this.betrayLapseTime = gameState.ai.elapsedTime + randFloat(10, 110);
|
||||
this.waitingToBetray = true;
|
||||
return;
|
||||
}
|
||||
@@ -277,7 +277,7 @@ m.DiplomacyManager.prototype.handleDiplomacyRequest = function(gameState, player
|
||||
let moreEnemiesThanAllies = gameState.getEnemies().length > gameState.getMutualAllies().length;
|
||||
|
||||
// For any given diplomacy request be likely to permanently decline
|
||||
if (!request && gameState.getPlayerCiv() !== gameState.getPlayerCiv(player) && Math.random() > 0.4 ||
|
||||
if (!request && gameState.getPlayerCiv() !== gameState.getPlayerCiv(player) && randFloat(0, 1) > 0.4 ||
|
||||
!moreEnemiesThanAllies || gameState.ai.HQ.attackManager.currentEnemyPlayer === player)
|
||||
{
|
||||
this.diplomacyRequests.set(player, { "requestType": requestType, "status": "declinedRequest" });
|
||||
@@ -296,7 +296,7 @@ m.DiplomacyManager.prototype.handleDiplomacyRequest = function(gameState, player
|
||||
}
|
||||
}
|
||||
else if (requestType === "ally" && gameState.getEntities(player).length < gameState.getOwnEntities().length &&
|
||||
Math.random() > 0.6 || requestType === "neutral" && moreEnemiesThanAllies && Math.random() > 0.2)
|
||||
randFloat(0, 1) > 0.6 || requestType === "neutral" && moreEnemiesThanAllies && randFloat(0, 1) > 0.2)
|
||||
{
|
||||
response = "accept";
|
||||
this.changePlayerDiplomacy(gameState, player, requestType);
|
||||
|
||||
@@ -504,12 +504,8 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
||||
requirements = [ ["strength", 1] ];
|
||||
|
||||
let classes = ["CitizenSoldier", "Infantry"];
|
||||
let proba = Math.random();
|
||||
// we require at least 30% ranged and 30% melee
|
||||
if ( proba < 0.3 )
|
||||
classes.push("Ranged");
|
||||
else if ( proba < 0.6 )
|
||||
classes.push("Melee");
|
||||
// We want at least 33% ranged and 33% melee
|
||||
classes.push(pickRandom(["Ranged", "Melee", "Infantry"]));
|
||||
|
||||
template = this.findBestTrainableUnit(gameState, classes, requirements);
|
||||
}
|
||||
@@ -1770,7 +1766,7 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions)
|
||||
}
|
||||
let autogarrison = numGarrisoned < nearestAnchor.garrisonMax() &&
|
||||
nearestAnchor.hitpoints() > nearestAnchor.garrisonEjectHealth() * nearestAnchor.maxHitpoints();
|
||||
let rangedWanted = Math.random() > 0.5 && autogarrison;
|
||||
let rangedWanted = randBool() && autogarrison;
|
||||
|
||||
let total = gameState.getResources();
|
||||
let templateFound;
|
||||
|
||||
@@ -235,9 +235,9 @@ m.ResearchManager.prototype.update = function(gameState, queues)
|
||||
}
|
||||
if (!techs.length)
|
||||
return;
|
||||
|
||||
// randomly pick one. No worries about pairs in that case.
|
||||
let p = Math.floor(Math.random()*techs.length);
|
||||
queues.minorTech.addPlan(new m.ResearchPlan(gameState, techs[p][0]));
|
||||
queues.minorTech.addPlan(new m.ResearchPlan(gameState, pickRandom(techs)[0]));
|
||||
};
|
||||
|
||||
m.ResearchManager.prototype.CostSum = function(cost)
|
||||
|
||||
@@ -300,7 +300,7 @@ BuildingAI.prototype.FireArrows = function()
|
||||
arrowsToFire = this.arrowsLeft;
|
||||
else
|
||||
arrowsToFire = Math.min(
|
||||
Math.round(2 * Math.random() * this.GetArrowCount() / roundCount),
|
||||
randIntInclusive(0, 2 * this.GetArrowCount() / roundCount),
|
||||
this.arrowsLeft
|
||||
);
|
||||
|
||||
|
||||
@@ -667,7 +667,7 @@ Formation.prototype.ComputeFormationOffsets = function(active, positions)
|
||||
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
var obj = new Vector2D(Math.random()*width, Math.random()*width);
|
||||
var obj = new Vector2D(randFloat(0, width), randFloat(0, width));
|
||||
obj.row = 1;
|
||||
obj.column = i + 1;
|
||||
offsets.push(obj);
|
||||
@@ -720,13 +720,9 @@ Formation.prototype.ComputeFormationOffsets = function(active, positions)
|
||||
x += side * centerGap / 2;
|
||||
}
|
||||
var column = Math.ceil(n/2) + Math.ceil(c/2) * side;
|
||||
var r1 = 0;
|
||||
var r2 = 0;
|
||||
if (this.sloppyness != 0)
|
||||
{
|
||||
r1 = (Math.random() * 2 - 1) * this.sloppyness;
|
||||
r2 = (Math.random() * 2 - 1) * this.sloppyness;
|
||||
}
|
||||
var r1 = randFloat(-1, 1) * this.sloppyness;
|
||||
var r2 = randFloat(-1, 1) * this.sloppyness;
|
||||
|
||||
offsets.push(new Vector2D(x + r1, z + r2));
|
||||
offsets[offsets.length - 1].row = r+1;
|
||||
offsets[offsets.length - 1].column = column;
|
||||
|
||||
@@ -308,7 +308,7 @@ Player.prototype.TrySubtractResources = function(amounts)
|
||||
|
||||
Player.prototype.GetNextTradingGoods = function()
|
||||
{
|
||||
var value = 100*Math.random();
|
||||
var value = randFloat(0, 100);
|
||||
var last = this.tradingGoods.length - 1;
|
||||
var sumProba = 0;
|
||||
for (var i = 0; i < last; ++i)
|
||||
|
||||
@@ -3225,7 +3225,7 @@ UnitAI.prototype.UnitFsmSpec = {
|
||||
this.SelectAnimation("walk", false, this.GetWalkSpeed());
|
||||
this.MoveRandomly(+this.template.RoamDistance);
|
||||
// Set a random timer to switch to feeding state
|
||||
this.StartTimer(RandomInt(+this.template.RoamTimeMin, +this.template.RoamTimeMax));
|
||||
this.StartTimer(randIntInclusive(+this.template.RoamTimeMin, +this.template.RoamTimeMax));
|
||||
this.SetFacePointAfterMove(false);
|
||||
},
|
||||
|
||||
@@ -3270,7 +3270,7 @@ UnitAI.prototype.UnitFsmSpec = {
|
||||
// Stop and eat for a while
|
||||
this.SelectAnimation("feeding");
|
||||
this.StopMoving();
|
||||
this.StartTimer(RandomInt(+this.template.FeedTimeMin, +this.template.FeedTimeMax));
|
||||
this.StartTimer(randIntInclusive(+this.template.FeedTimeMin, +this.template.FeedTimeMax));
|
||||
},
|
||||
|
||||
"leave": function() {
|
||||
@@ -5989,8 +5989,8 @@ UnitAI.prototype.MoveRandomly = function(distance)
|
||||
|
||||
// Randomly adjust the range's center a bit, so we tend to prefer
|
||||
// moving in random directions (if there's nothing in the way)
|
||||
var tx = pos.x + (2*Math.random()-1)*jitter;
|
||||
var tz = pos.z + (2*Math.random()-1)*jitter;
|
||||
var tx = pos.x + randFloat(-1, 1) * jitter;
|
||||
var tz = pos.z + randFloat(-1, 1) * jitter;
|
||||
|
||||
var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
|
||||
cmpMotion.MoveToPointRange(tx, tz, distance, distance);
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Returns a random integer from min (inclusive) to max (exclusive)
|
||||
*/
|
||||
function RandomInt(min, max)
|
||||
{
|
||||
return Math.floor(min + Math.random() * (max-min));
|
||||
}
|
||||
|
||||
Engine.RegisterGlobal("RandomInt", RandomInt);
|
||||
@@ -31,9 +31,9 @@ WeightedList.prototype.itemAt = function(index)
|
||||
};
|
||||
|
||||
WeightedList.prototype.randomIndex = function() {
|
||||
var element,
|
||||
targetWeight = Math.random() * this.totalWeight,
|
||||
cumulativeWeight = 0;
|
||||
var element;
|
||||
var targetWeight = randFloat(0, this.totalWeight);
|
||||
var cumulativeWeight = 0;
|
||||
for (var index = 0; index < this.elements.length; index++)
|
||||
{
|
||||
element = this.elements[index];
|
||||
|
||||
Reference in New Issue
Block a user