BUGFIX: Improve implementation of getRandomInt (#1282)

This commit is contained in:
catloversg 2024-05-19 05:12:06 +07:00 committed by GitHub
parent 8deb907b89
commit 175af0bd28
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 160 additions and 130 deletions

@ -3,7 +3,7 @@ import type { IReviverValue } from "../../utils/JSONReviver";
import type { Availability } from "../Types"; import type { Availability } from "../Types";
import { ActionClass, ActionParams } from "./Action"; import { ActionClass, ActionParams } from "./Action";
import { getRandomInt } from "../../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
import { clampInteger } from "../../utils/helpers/clampNumber"; import { clampInteger } from "../../utils/helpers/clampNumber";
export type LevelableActionParams = ActionParams & { export type LevelableActionParams = ActionParams & {
@ -37,7 +37,7 @@ export abstract class LevelableActionClass extends ActionClass {
if (params.maxCount) this.maxCount = params.maxCount; if (params.maxCount) this.maxCount = params.maxCount;
if (params.difficultyFac) this.difficultyFac = params.difficultyFac; if (params.difficultyFac) this.difficultyFac = params.difficultyFac;
if (params.rewardFac) this.rewardFac = params.rewardFac; if (params.rewardFac) this.rewardFac = params.rewardFac;
this.count = getRandomInt(this.minCount, this.maxCount); this.count = getRandomIntInclusive(this.minCount, this.maxCount);
this.growthFunction = params.growthFunction; this.growthFunction = params.growthFunction;
} }
@ -65,7 +65,7 @@ export abstract class LevelableActionClass extends ActionClass {
/** Reset a levelable action's tracked stats */ /** Reset a levelable action's tracked stats */
reset() { reset() {
this.count = getRandomInt(this.minCount, this.maxCount); this.count = getRandomIntInclusive(this.minCount, this.maxCount);
this.level = 1; this.level = 1;
this.maxLevel = 1; this.maxLevel = 1;
this.autoLevel = true; this.autoLevel = true;

@ -24,7 +24,7 @@ import { Player } from "@player";
import { Router } from "../ui/GameRoot"; import { Router } from "../ui/GameRoot";
import { ConsoleHelpText } from "./data/Help"; import { ConsoleHelpText } from "./data/Help";
import { exceptionAlert } from "../utils/helpers/exceptionAlert"; import { exceptionAlert } from "../utils/helpers/exceptionAlert";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
import { BladeburnerConstants } from "./data/Constants"; import { BladeburnerConstants } from "./data/Constants";
import { formatExp, formatMoney, formatPercent, formatBigNumber, formatStamina } from "../ui/formatNumber"; import { formatExp, formatMoney, formatPercent, formatBigNumber, formatStamina } from "../ui/formatNumber";
import { currentNodeMults } from "../BitNode/BitNodeMultipliers"; import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
@ -64,7 +64,7 @@ export class Bladeburner {
storedCycles = 0; storedCycles = 0;
randomEventCounter: number = getRandomInt(240, 600); randomEventCounter: number = getRandomIntInclusive(240, 600);
actionTimeToComplete = 0; actionTimeToComplete = 0;
actionTimeCurrent = 0; actionTimeCurrent = 0;
@ -522,11 +522,11 @@ export class Bladeburner {
const sourceCity = this.cities[sourceCityName]; const sourceCity = this.cities[sourceCityName];
const rand = Math.random(); const rand = Math.random();
let percentage = getRandomInt(3, 15) / 100; let percentage = getRandomIntInclusive(3, 15) / 100;
if (rand < 0.05 && sourceCity.comms > 0) { if (rand < 0.05 && sourceCity.comms > 0) {
// 5% chance for community migration // 5% chance for community migration
percentage *= getRandomInt(2, 4); // Migration increases population change percentage *= getRandomIntInclusive(2, 4); // Migration increases population change
--sourceCity.comms; --sourceCity.comms;
++destCity.comms; ++destCity.comms;
} }
@ -565,7 +565,7 @@ export class Bladeburner {
if (chance <= 0.05) { if (chance <= 0.05) {
// New Synthoid Community, 5% // New Synthoid Community, 5%
++sourceCity.comms; ++sourceCity.comms;
const percentage = getRandomInt(10, 20) / 100; const percentage = getRandomIntInclusive(10, 20) / 100;
const count = Math.round(sourceCity.pop * percentage); const count = Math.round(sourceCity.pop * percentage);
sourceCity.pop += count; sourceCity.pop += count;
if (sourceCity.pop < BladeburnerConstants.PopGrowthCeiling) { if (sourceCity.pop < BladeburnerConstants.PopGrowthCeiling) {
@ -579,7 +579,7 @@ export class Bladeburner {
if (sourceCity.comms <= 0) { if (sourceCity.comms <= 0) {
// If no comms in source city, then instead trigger a new Synthoid community event // If no comms in source city, then instead trigger a new Synthoid community event
++sourceCity.comms; ++sourceCity.comms;
const percentage = getRandomInt(10, 20) / 100; const percentage = getRandomIntInclusive(10, 20) / 100;
const count = Math.round(sourceCity.pop * percentage); const count = Math.round(sourceCity.pop * percentage);
sourceCity.pop += count; sourceCity.pop += count;
if (sourceCity.pop < BladeburnerConstants.PopGrowthCeiling) { if (sourceCity.pop < BladeburnerConstants.PopGrowthCeiling) {
@ -593,7 +593,7 @@ export class Bladeburner {
++destCity.comms; ++destCity.comms;
// Change pop // Change pop
const percentage = getRandomInt(10, 20) / 100; const percentage = getRandomIntInclusive(10, 20) / 100;
const count = Math.round(sourceCity.pop * percentage); const count = Math.round(sourceCity.pop * percentage);
sourceCity.pop -= count; sourceCity.pop -= count;
destCity.pop += count; destCity.pop += count;
@ -608,7 +608,7 @@ export class Bladeburner {
} }
} else if (chance <= 0.3) { } else if (chance <= 0.3) {
// New Synthoids (non community), 20% // New Synthoids (non community), 20%
const percentage = getRandomInt(8, 24) / 100; const percentage = getRandomIntInclusive(8, 24) / 100;
const count = Math.round(sourceCity.pop * percentage); const count = Math.round(sourceCity.pop * percentage);
sourceCity.pop += count; sourceCity.pop += count;
if (sourceCity.pop < BladeburnerConstants.PopGrowthCeiling) { if (sourceCity.pop < BladeburnerConstants.PopGrowthCeiling) {
@ -632,13 +632,13 @@ export class Bladeburner {
} else if (chance <= 0.7) { } else if (chance <= 0.7) {
// Synthoid Riots (+chaos), 20% // Synthoid Riots (+chaos), 20%
sourceCity.chaos += 1; sourceCity.chaos += 1;
sourceCity.chaos *= 1 + getRandomInt(5, 20) / 100; sourceCity.chaos *= 1 + getRandomIntInclusive(5, 20) / 100;
if (this.logging.events) { if (this.logging.events) {
this.log("Tensions between Synthoids and humans lead to riots in " + sourceCityName + "! Chaos increased"); this.log("Tensions between Synthoids and humans lead to riots in " + sourceCityName + "! Chaos increased");
} }
} else if (chance <= 0.9) { } else if (chance <= 0.9) {
// Less Synthoids, 20% // Less Synthoids, 20%
const percentage = getRandomInt(8, 20) / 100; const percentage = getRandomIntInclusive(8, 20) / 100;
const count = Math.round(sourceCity.pop * percentage); const count = Math.round(sourceCity.pop * percentage);
sourceCity.pop -= count; sourceCity.pop -= count;
if (this.logging.events) { if (this.logging.events) {
@ -753,7 +753,7 @@ export class Bladeburner {
const teamCount = action.teamCount; const teamCount = action.teamCount;
if (teamCount >= 1) { if (teamCount >= 1) {
const maxLosses = success ? Math.ceil(teamCount / 2) : Math.floor(teamCount); const maxLosses = success ? Math.ceil(teamCount / 2) : Math.floor(teamCount);
const losses = getRandomInt(0, maxLosses); const losses = getRandomIntInclusive(0, maxLosses);
this.teamSize -= losses; this.teamSize -= losses;
if (this.teamSize < this.sleeveSize) { if (this.teamSize < this.sleeveSize) {
const sup = Player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork)); const sup = Player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
@ -803,13 +803,13 @@ export class Bladeburner {
}); });
--city.comms; --city.comms;
} else { } else {
const change = getRandomInt(-10, -5) / 10; const change = getRandomIntInclusive(-10, -5) / 10;
city.changePopulationByPercentage(change, { city.changePopulationByPercentage(change, {
nonZero: true, nonZero: true,
changeEstEqually: false, changeEstEqually: false,
}); });
} }
city.changeChaosByPercentage(getRandomInt(1, 5)); city.changeChaosByPercentage(getRandomIntInclusive(1, 5));
break; break;
case BladeOperationName.stealthRetirement: case BladeOperationName.stealthRetirement:
if (success) { if (success) {
@ -818,13 +818,13 @@ export class Bladeburner {
nonZero: true, nonZero: true,
}); });
} }
city.changeChaosByPercentage(getRandomInt(-3, -1)); city.changeChaosByPercentage(getRandomIntInclusive(-3, -1));
break; break;
case BladeOperationName.assassination: case BladeOperationName.assassination:
if (success) { if (success) {
city.changePopulationByCount(-1, { estChange: -1, estOffset: 0 }); city.changePopulationByCount(-1, { estChange: -1, estOffset: 0 });
} }
city.changeChaosByPercentage(getRandomInt(-5, 5)); city.changeChaosByPercentage(getRandomIntInclusive(-5, 5));
break; break;
default: default:
throw new Error("Invalid Action name in completeOperation: " + this.action.name); throw new Error("Invalid Action name in completeOperation: " + this.action.name);
@ -838,7 +838,7 @@ export class Bladeburner {
case BladeContractName.tracking: case BladeContractName.tracking:
// Increase estimate accuracy by a relatively small amount // Increase estimate accuracy by a relatively small amount
city.improvePopulationEstimateByCount( city.improvePopulationEstimateByCount(
getRandomInt(100, 1e3) * this.getSkillMult(BladeMultName.successChanceEstimate), getRandomIntInclusive(100, 1e3) * this.getSkillMult(BladeMultName.successChanceEstimate),
); );
break; break;
case BladeContractName.bountyHunter: case BladeContractName.bountyHunter:
@ -1012,7 +1012,7 @@ export class Bladeburner {
// Calculate team losses // Calculate team losses
if (teamCount >= 1) { if (teamCount >= 1) {
const losses = getRandomInt(1, teamLossMax); const losses = getRandomIntInclusive(1, teamLossMax);
this.teamSize -= losses; this.teamSize -= losses;
if (this.teamSize < this.sleeveSize) { if (this.teamSize < this.sleeveSize) {
const sup = Player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork)); const sup = Player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
@ -1332,7 +1332,7 @@ export class Bladeburner {
if (this.randomEventCounter <= 0) { if (this.randomEventCounter <= 0) {
this.randomEvent(); this.randomEvent();
// Add instead of setting because we might have gone over the required time for the event // Add instead of setting because we might have gone over the required time for the event
this.randomEventCounter += getRandomInt(240, 600); this.randomEventCounter += getRandomIntInclusive(240, 600);
} }
this.processAction(seconds); this.processAction(seconds);

@ -1,6 +1,6 @@
import { CityName } from "@enums"; import { CityName } from "@enums";
import { BladeburnerConstants } from "./data/Constants"; import { BladeburnerConstants } from "./data/Constants";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver";
import { addOffset } from "../utils/helpers/addOffset"; import { addOffset } from "../utils/helpers/addOffset";
import { clampInteger, clampNumber } from "../utils/helpers/clampNumber"; import { clampInteger, clampNumber } from "../utils/helpers/clampNumber";
@ -16,11 +16,14 @@ export class City {
this.name = name; this.name = name;
// Synthoid population and estimate // Synthoid population and estimate
this.pop = getRandomInt(BladeburnerConstants.PopulationThreshold, 1.5 * BladeburnerConstants.PopulationThreshold); this.pop = getRandomIntInclusive(
BladeburnerConstants.PopulationThreshold,
1.5 * BladeburnerConstants.PopulationThreshold,
);
this.popEst = this.pop * (Math.random() + 0.5); this.popEst = this.pop * (Math.random() + 0.5);
// Number of Synthoid communities population and estimate // Number of Synthoid communities population and estimate
this.comms = getRandomInt(5, 150); this.comms = getRandomIntInclusive(5, 150);
this.chaos = 0; this.chaos = 0;
} }

@ -1,6 +1,6 @@
import { BladeContractName } from "@enums"; import { BladeContractName } from "@enums";
import { Contract } from "../Actions/Contract"; import { Contract } from "../Actions/Contract";
import { getRandomInt } from "../../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
import { assertLoadingType } from "../../utils/TypeAssertion"; import { assertLoadingType } from "../../utils/TypeAssertion";
export function createContracts(): Record<BladeContractName, Contract> { export function createContracts(): Record<BladeContractName, Contract> {
@ -36,7 +36,7 @@ export function createContracts(): Record<BladeContractName, Contract> {
intelligence: 1, intelligence: 1,
}, },
isStealth: true, isStealth: true,
growthFunction: () => getRandomInt(5, 75) / 10, growthFunction: () => getRandomIntInclusive(5, 75) / 10,
minCount: 25, minCount: 25,
}), }),
[BladeContractName.bountyHunter]: new Contract({ [BladeContractName.bountyHunter]: new Contract({
@ -69,7 +69,7 @@ export function createContracts(): Record<BladeContractName, Contract> {
intelligence: 0.9, intelligence: 0.9,
}, },
isKill: true, isKill: true,
growthFunction: () => getRandomInt(5, 75) / 10, growthFunction: () => getRandomIntInclusive(5, 75) / 10,
minCount: 5, minCount: 5,
}), }),
[BladeContractName.retirement]: new Contract({ [BladeContractName.retirement]: new Contract({
@ -102,7 +102,7 @@ export function createContracts(): Record<BladeContractName, Contract> {
intelligence: 0.9, intelligence: 0.9,
}, },
isKill: true, isKill: true,
growthFunction: () => getRandomInt(5, 75) / 10, growthFunction: () => getRandomIntInclusive(5, 75) / 10,
minCount: 5, minCount: 5,
}), }),
}; };

@ -1,6 +1,6 @@
import { BladeOperationName } from "@enums"; import { BladeOperationName } from "@enums";
import { Operation } from "../Actions/Operation"; import { Operation } from "../Actions/Operation";
import { getRandomInt } from "../../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
import { LevelableActionClass } from "../Actions/LevelableAction"; import { LevelableActionClass } from "../Actions/LevelableAction";
import { assertLoadingType } from "../../utils/TypeAssertion"; import { assertLoadingType } from "../../utils/TypeAssertion";
@ -36,7 +36,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
intelligence: 0.9, intelligence: 0.9,
}, },
isStealth: true, isStealth: true,
growthFunction: () => getRandomInt(10, 40) / 10, growthFunction: () => getRandomIntInclusive(10, 40) / 10,
maxCount: 100, maxCount: 100,
}), }),
[BladeOperationName.undercover]: new Operation({ [BladeOperationName.undercover]: new Operation({
@ -69,7 +69,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
intelligence: 0.9, intelligence: 0.9,
}, },
isStealth: true, isStealth: true,
growthFunction: () => getRandomInt(10, 40) / 10, growthFunction: () => getRandomIntInclusive(10, 40) / 10,
maxCount: 100, maxCount: 100,
}), }),
[BladeOperationName.sting]: new Operation({ [BladeOperationName.sting]: new Operation({
@ -100,7 +100,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
intelligence: 0.9, intelligence: 0.9,
}, },
isStealth: true, isStealth: true,
growthFunction: () => getRandomInt(3, 40) / 10, growthFunction: () => getRandomIntInclusive(3, 40) / 10,
}), }),
[BladeOperationName.raid]: new Operation({ [BladeOperationName.raid]: new Operation({
name: BladeOperationName.raid, name: BladeOperationName.raid,
@ -132,7 +132,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
intelligence: 0.9, intelligence: 0.9,
}, },
isKill: true, isKill: true,
growthFunction: () => getRandomInt(2, 40) / 10, growthFunction: () => getRandomIntInclusive(2, 40) / 10,
getAvailability: function (bladeburner) { getAvailability: function (bladeburner) {
if (bladeburner.getCurrentCity().comms < 1) return { error: "No Synthoid communities in current city" }; if (bladeburner.getCurrentCity().comms < 1) return { error: "No Synthoid communities in current city" };
return LevelableActionClass.prototype.getAvailability.call(this, bladeburner); return LevelableActionClass.prototype.getAvailability.call(this, bladeburner);
@ -169,7 +169,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
}, },
isStealth: true, isStealth: true,
isKill: true, isKill: true,
growthFunction: () => getRandomInt(1, 20) / 10, growthFunction: () => getRandomIntInclusive(1, 20) / 10,
}), }),
[BladeOperationName.assassination]: new Operation({ [BladeOperationName.assassination]: new Operation({
name: BladeOperationName.assassination, name: BladeOperationName.assassination,
@ -202,7 +202,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
}, },
isStealth: true, isStealth: true,
isKill: true, isKill: true,
growthFunction: () => getRandomInt(1, 20) / 10, growthFunction: () => getRandomIntInclusive(1, 20) / 10,
}), }),
}; };
} }

@ -12,7 +12,7 @@ import { SpecialServers } from "./Server/data/SpecialServers";
import { Server } from "./Server/Server"; import { Server } from "./Server/Server";
import { BaseServer } from "./Server/BaseServer"; import { BaseServer } from "./Server/BaseServer";
import { getRandomInt } from "./utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "./utils/helpers/getRandomIntInclusive";
import { ContractFilePath, resolveContractFilePath } from "./Paths/ContractFilePath"; import { ContractFilePath, resolveContractFilePath } from "./Paths/ContractFilePath";
export function generateRandomContract(): void { export function generateRandomContract(): void {
@ -121,7 +121,7 @@ function sanitizeRewardType(rewardType: CodingContractRewardType): CodingContrac
function getRandomProblemType(): string { function getRandomProblemType(): string {
const problemTypes = Object.keys(CodingContractTypes); const problemTypes = Object.keys(CodingContractTypes);
const randIndex = getRandomInt(0, problemTypes.length - 1); const randIndex = getRandomIntInclusive(0, problemTypes.length - 1);
return problemTypes[randIndex]; return problemTypes[randIndex];
} }
@ -130,7 +130,7 @@ function getRandomReward(): ICodingContractReward {
// Don't offer money reward by default if BN multiplier is 0 (e.g. BN8) // Don't offer money reward by default if BN multiplier is 0 (e.g. BN8)
const rewardTypeUpperBound = const rewardTypeUpperBound =
currentNodeMults.CodingContractMoney === 0 ? CodingContractRewardType.Money - 1 : CodingContractRewardType.Money; currentNodeMults.CodingContractMoney === 0 ? CodingContractRewardType.Money - 1 : CodingContractRewardType.Money;
const rewardType = sanitizeRewardType(getRandomInt(0, rewardTypeUpperBound)); const rewardType = sanitizeRewardType(getRandomIntInclusive(0, rewardTypeUpperBound));
// Add additional information based on the reward type // Add additional information based on the reward type
const factionsThatAllowHacking = Player.factions.filter((fac) => Factions[fac].getInfo().offerHackingWork); const factionsThatAllowHacking = Player.factions.filter((fac) => Factions[fac].getInfo().offerHackingWork);
@ -140,13 +140,22 @@ function getRandomReward(): ICodingContractReward {
// Get a random faction that player is a part of. That // Get a random faction that player is a part of. That
// faction must allow hacking contracts // faction must allow hacking contracts
const numFactions = factionsThatAllowHacking.length; const numFactions = factionsThatAllowHacking.length;
const randFaction = factionsThatAllowHacking[getRandomInt(0, numFactions - 1)]; // This check is unnecessary because sanitizeRewardType ensures that it won't happen. However, I'll still leave
// it here, just in case somebody else changes sanitizeRewardType without taking account of this check.
if (numFactions > 0) {
const randFaction = factionsThatAllowHacking[getRandomIntInclusive(0, numFactions - 1)];
return { type: rewardType, name: randFaction }; return { type: rewardType, name: randFaction };
} }
return { type: CodingContractRewardType.Money };
}
case CodingContractRewardType.CompanyReputation: { case CodingContractRewardType.CompanyReputation: {
const allJobs = Object.keys(Player.jobs); const allJobs = Object.keys(Player.jobs);
// This check is also unnecessary. Check the comment above.
if (allJobs.length > 0) { if (allJobs.length > 0) {
return { type: CodingContractRewardType.CompanyReputation, name: allJobs[getRandomInt(0, allJobs.length - 1)] }; return {
type: CodingContractRewardType.CompanyReputation,
name: allJobs[getRandomIntInclusive(0, allJobs.length - 1)],
};
} }
return { type: CodingContractRewardType.Money }; return { type: CodingContractRewardType.Money };
} }
@ -157,7 +166,7 @@ function getRandomReward(): ICodingContractReward {
function getRandomServer(): BaseServer { function getRandomServer(): BaseServer {
const servers = GetAllServers().filter((server: BaseServer) => server.serversOnNetwork.length !== 0); const servers = GetAllServers().filter((server: BaseServer) => server.serversOnNetwork.length !== 0);
let randIndex = getRandomInt(0, servers.length - 1); let randIndex = getRandomIntInclusive(0, servers.length - 1);
let randServer = servers[randIndex]; let randServer = servers[randIndex];
// An infinite loop shouldn't ever happen, but to be safe we'll use // An infinite loop shouldn't ever happen, but to be safe we'll use
@ -170,7 +179,7 @@ function getRandomServer(): BaseServer {
) { ) {
break; break;
} }
randIndex = getRandomInt(0, servers.length - 1); randIndex = getRandomIntInclusive(0, servers.length - 1);
randServer = servers[randIndex]; randServer = servers[randIndex];
} }
@ -181,7 +190,7 @@ function getRandomFilename(
server: BaseServer, server: BaseServer,
reward: ICodingContractReward = { type: CodingContractRewardType.Money }, reward: ICodingContractReward = { type: CodingContractRewardType.Money },
): ContractFilePath { ): ContractFilePath {
let contractFn = `contract-${getRandomInt(0, 1e6)}`; let contractFn = `contract-${getRandomIntInclusive(0, 1e6)}`;
for (let i = 0; i < 1000; ++i) { for (let i = 0; i < 1000; ++i) {
if ( if (
@ -191,7 +200,7 @@ function getRandomFilename(
) { ) {
break; break;
} }
contractFn = `contract-${getRandomInt(0, 1e6)}`; contractFn = `contract-${getRandomIntInclusive(0, 1e6)}`;
} }
if ("name" in reward) { if ("name" in reward) {

@ -14,7 +14,7 @@ import { FactionName, IndustryType } from "@enums";
import { ResearchMap } from "./ResearchMap"; import { ResearchMap } from "./ResearchMap";
import { isRelevantMaterial } from "./ui/Helpers"; import { isRelevantMaterial } from "./ui/Helpers";
import { CityName } from "@enums"; import { CityName } from "@enums";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
import { getRecordValues } from "../Types/Record"; import { getRecordValues } from "../Types/Record";
import { import {
calculateOfficeSizeUpgradeCost, calculateOfficeSizeUpgradeCost,
@ -166,7 +166,7 @@ export function issueNewShares(
const privateOwnedRatio = corporation.investorShares / corporation.totalShares; const privateOwnedRatio = corporation.investorShares / corporation.totalShares;
const maxPrivateShares = Math.round((amount / 2) * privateOwnedRatio); const maxPrivateShares = Math.round((amount / 2) * privateOwnedRatio);
const privateShares = Math.round(getRandomInt(0, maxPrivateShares) / 10e6) * 10e6; const privateShares = Math.round(getRandomIntInclusive(0, maxPrivateShares) / 10e6) * 10e6;
corporation.issuedShares += amount - privateShares; corporation.issuedShares += amount - privateShares;
corporation.investorShares += privateShares; corporation.investorShares += privateShares;

@ -3,7 +3,7 @@ import { CityName, CorpEmployeeJob, IndustryType } from "@enums";
import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver";
import { IndustryResearchTrees, IndustriesData } from "./data/IndustryData"; import { IndustryResearchTrees, IndustriesData } from "./data/IndustryData";
import * as corpConstants from "./data/Constants"; import * as corpConstants from "./data/Constants";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
import { calculateEffectWithFactors } from "../utils/calculateEffectWithFactors"; import { calculateEffectWithFactors } from "../utils/calculateEffectWithFactors";
import { OfficeSpace } from "./OfficeSpace"; import { OfficeSpace } from "./OfficeSpace";
import { Product } from "./Product"; import { Product } from "./Product";
@ -254,7 +254,7 @@ export class Division {
processProductMarket(marketCycles = 1): void { processProductMarket(marketCycles = 1): void {
// Demand gradually decreases, and competition gradually increases // Demand gradually decreases, and competition gradually increases
for (const product of this.products.values()) { for (const product of this.products.values()) {
let change = getRandomInt(0, 3) * 0.0004; let change = getRandomIntInclusive(0, 3) * 0.0004;
if (change === 0) continue; if (change === 0) continue;
if ( if (
@ -985,7 +985,7 @@ export class Division {
const awareness = (this.awareness + 3 * advMult) * (1.005 * advMult); const awareness = (this.awareness + 3 * advMult) * (1.005 * advMult);
this.awareness = Math.min(awareness, Number.MAX_VALUE); this.awareness = Math.min(awareness, Number.MAX_VALUE);
const popularity = (this.popularity + 1 * advMult) * ((1 + getRandomInt(1, 3) / 200) * advMult); const popularity = (this.popularity + 1 * advMult) * ((1 + getRandomIntInclusive(1, 3) / 200) * advMult);
this.popularity = Math.min(popularity, Number.MAX_VALUE); this.popularity = Math.min(popularity, Number.MAX_VALUE);
++this.numAdVerts; ++this.numAdVerts;

@ -3,7 +3,7 @@ import * as corpConstants from "./data/Constants";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver";
import { Division } from "./Division"; import { Division } from "./Division";
import { Corporation } from "./Corporation"; import { Corporation } from "./Corporation";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
import { createEnumKeyedRecord, getRecordKeys } from "../Types/Record"; import { createEnumKeyedRecord, getRecordKeys } from "../Types/Record";
interface IParams { interface IParams {
@ -178,15 +178,19 @@ export class OfficeSpace {
hireRandomEmployee(position: CorpEmployeeJob): boolean { hireRandomEmployee(position: CorpEmployeeJob): boolean {
if (this.atCapacity()) return false; if (this.atCapacity()) return false;
this.totalExperience += getRandomInt(50, 100); this.totalExperience += getRandomIntInclusive(50, 100);
this.avgMorale = (this.avgMorale * this.numEmployees + getRandomInt(50, 100)) / (this.numEmployees + 1); this.avgMorale = (this.avgMorale * this.numEmployees + getRandomIntInclusive(50, 100)) / (this.numEmployees + 1);
this.avgEnergy = (this.avgEnergy * this.numEmployees + getRandomInt(50, 100)) / (this.numEmployees + 1); this.avgEnergy = (this.avgEnergy * this.numEmployees + getRandomIntInclusive(50, 100)) / (this.numEmployees + 1);
this.avgIntelligence = (this.avgIntelligence * this.numEmployees + getRandomInt(50, 100)) / (this.numEmployees + 1); this.avgIntelligence =
this.avgCharisma = (this.avgCharisma * this.numEmployees + getRandomInt(50, 100)) / (this.numEmployees + 1); (this.avgIntelligence * this.numEmployees + getRandomIntInclusive(50, 100)) / (this.numEmployees + 1);
this.avgCreativity = (this.avgCreativity * this.numEmployees + getRandomInt(50, 100)) / (this.numEmployees + 1); this.avgCharisma =
this.avgEfficiency = (this.avgEfficiency * this.numEmployees + getRandomInt(50, 100)) / (this.numEmployees + 1); (this.avgCharisma * this.numEmployees + getRandomIntInclusive(50, 100)) / (this.numEmployees + 1);
this.avgCreativity =
(this.avgCreativity * this.numEmployees + getRandomIntInclusive(50, 100)) / (this.numEmployees + 1);
this.avgEfficiency =
(this.avgEfficiency * this.numEmployees + getRandomIntInclusive(50, 100)) / (this.numEmployees + 1);
++this.numEmployees; ++this.numEmployees;
++this.employeeJobs[position]; ++this.employeeJobs[position];

@ -6,7 +6,7 @@ import { IndustriesData } from "./data/IndustryData";
import { MaterialInfo } from "./MaterialInfo"; import { MaterialInfo } from "./MaterialInfo";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
import { PartialRecord, createEnumKeyedRecord, getRecordEntries, getRecordKeys } from "../Types/Record"; import { PartialRecord, createEnumKeyedRecord, getRecordEntries, getRecordKeys } from "../Types/Record";
interface IConstructorParams { interface IConstructorParams {
@ -202,7 +202,7 @@ export class Product {
this.demand = this.demand =
division.awareness === 0 ? 20 : Math.min(100, advMult * (100 * (division.popularity / division.awareness))); division.awareness === 0 ? 20 : Math.min(100, advMult * (100 * (division.popularity / division.awareness)));
this.competition = getRandomInt(0, 70); this.competition = getRandomIntInclusive(0, 70);
//Calculate the product's required materials and size //Calculate the product's required materials and size
this.size = 0; this.size = 0;

@ -11,7 +11,7 @@ import { dialogBoxCreate } from "../ui/React/DialogBox";
import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver";
import { exceptionAlert } from "../utils/helpers/exceptionAlert"; import { exceptionAlert } from "../utils/helpers/exceptionAlert";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
import { GangMemberUpgrade } from "./GangMemberUpgrade"; import { GangMemberUpgrade } from "./GangMemberUpgrade";
import { GangConstants } from "./data/Constants"; import { GangConstants } from "./data/Constants";
@ -215,7 +215,7 @@ export class Gang {
const others = gangs.filter((e) => { const others = gangs.filter((e) => {
return e !== gangs[i]; return e !== gangs[i];
}); });
const other = getRandomInt(0, others.length - 1); const other = getRandomIntInclusive(0, others.length - 1);
const thisGang = gangs[i]; const thisGang = gangs[i];
const otherGang = others[other]; const otherGang = others[other];

@ -23,7 +23,7 @@ import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../../utils/JSONReviver"; import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../../utils/JSONReviver";
import { JSONMap, JSONSet } from "../../Types/Jsonable"; import { JSONMap, JSONSet } from "../../Types/Jsonable";
import { cyrb53 } from "../../utils/StringHelperFunctions"; import { cyrb53 } from "../../utils/StringHelperFunctions";
import { getRandomInt } from "../../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
import { CONSTANTS } from "../../Constants"; import { CONSTANTS } from "../../Constants";
import { Person } from "../Person"; import { Person } from "../Person";
import { isMember } from "../../utils/EnumHelper"; import { isMember } from "../../utils/EnumHelper";
@ -142,7 +142,7 @@ export class PlayerObject extends Person implements IPlayer {
navigator.userAgent + navigator.userAgent +
window.innerWidth + window.innerWidth +
window.innerHeight + window.innerHeight +
getRandomInt(100, 999), getRandomIntInclusive(100, 999),
); );
this.lastAugReset = this.lastNodeReset = Date.now(); this.lastAugReset = this.lastNodeReset = Date.now();
} }

@ -6,7 +6,7 @@ import { HacknetServer } from "../Hacknet/HacknetServer";
import { IMinMaxRange } from "../types"; import { IMinMaxRange } from "../types";
import { createRandomIp } from "../utils/IPAddress"; import { createRandomIp } from "../utils/IPAddress";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
import { Reviver } from "../utils/JSONReviver"; import { Reviver } from "../utils/JSONReviver";
import { SpecialServers } from "./data/SpecialServers"; import { SpecialServers } from "./data/SpecialServers";
import { currentNodeMults } from "../BitNode/BitNodeMultipliers"; import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
@ -133,7 +133,7 @@ export function initForeignServers(homeComputer: Server): void {
const toNumber = (value: number | IMinMaxRange): number => { const toNumber = (value: number | IMinMaxRange): number => {
if (typeof value === "number") return value; if (typeof value === "number") return value;
else return getRandomInt(value.min, value.max); else return getRandomIntInclusive(value.min, value.max);
}; };
for (const metadata of serverMetadata) { for (const metadata of serverMetadata) {

@ -1,6 +1,6 @@
import { IMinMaxRange } from "../types"; import { IMinMaxRange } from "../types";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
export const StockForecastInfluenceLimit = 5; export const StockForecastInfluenceLimit = 5;
@ -37,7 +37,7 @@ function toNumber(n: number | IMinMaxRange): number {
} }
case "object": { case "object": {
const range = n; const range = n;
value = getRandomInt(range.min, range.max); value = getRandomIntInclusive(range.min, range.max);
break; break;
} }
default: default:
@ -136,7 +136,7 @@ export class Stock {
this.b = p.b; this.b = p.b;
this.otlkMag = p.otlkMag; this.otlkMag = p.otlkMag;
this.otlkMagForecast = this.getAbsoluteForecast(); this.otlkMagForecast = this.getAbsoluteForecast();
this.cap = getRandomInt(this.price * 1e3, this.price * 25e3); this.cap = getRandomIntInclusive(this.price * 1e3, this.price * 25e3);
this.spreadPerc = toNumber(p.spreadPerc); this.spreadPerc = toNumber(p.spreadPerc);
this.shareTxForMovement = toNumber(p.shareTxForMovement); this.shareTxForMovement = toNumber(p.shareTxForMovement);
this.shareTxUntilMovement = this.shareTxForMovement; this.shareTxUntilMovement = this.shareTxForMovement;

@ -15,7 +15,7 @@ import { dialogBoxCreate } from "../ui/React/DialogBox";
import { Reviver } from "../utils/JSONReviver"; import { Reviver } from "../utils/JSONReviver";
import { NetscriptContext } from "../Netscript/APIWrapper"; import { NetscriptContext } from "../Netscript/APIWrapper";
import { helpers } from "../Netscript/NetscriptHelpers"; import { helpers } from "../Netscript/NetscriptHelpers";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
export let StockMarket: IStockMarket = { export let StockMarket: IStockMarket = {
lastUpdate: 0, lastUpdate: 0,
@ -169,7 +169,7 @@ export function initStockMarket(): void {
StockMarket.storedCycles = 0; StockMarket.storedCycles = 0;
StockMarket.lastUpdate = 0; StockMarket.lastUpdate = 0;
StockMarket.ticksUntilCycle = getRandomInt(1, StockMarketConstants.TicksPerCycle); StockMarket.ticksUntilCycle = getRandomIntInclusive(1, StockMarketConstants.TicksPerCycle);
initSymbolToStockMap(); initSymbolToStockMap();
} }

@ -1,4 +1,4 @@
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
import { MinHeap } from "../utils/Heap"; import { MinHeap } from "../utils/Heap";
import { comprGenChar, comprLZGenerate, comprLZEncode, comprLZDecode } from "../utils/CompressionContracts"; import { comprGenChar, comprLZGenerate, comprLZEncode, comprLZDecode } from "../utils/CompressionContracts";
@ -69,7 +69,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 1, difficulty: 1,
gen: (): number => { gen: (): number => {
return getRandomInt(500, 1e9); return getRandomIntInclusive(500, 1e9);
}, },
name: "Find Largest Prime Factor", name: "Find Largest Prime Factor",
numTries: 10, numTries: 10,
@ -99,11 +99,11 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 1, difficulty: 1,
gen: (): number[] => { gen: (): number[] => {
const len: number = getRandomInt(5, 40); const len: number = getRandomIntInclusive(5, 40);
const arr: number[] = []; const arr: number[] = [];
arr.length = len; arr.length = len;
for (let i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
arr[i] = getRandomInt(-10, 10); arr[i] = getRandomIntInclusive(-10, 10);
} }
return arr; return arr;
@ -135,7 +135,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 1.5, difficulty: 1.5,
gen: (): number => { gen: (): number => {
return getRandomInt(8, 100); return getRandomIntInclusive(8, 100);
}, },
name: "Total Ways to Sum", name: "Total Ways to Sum",
numTries: 10, numTries: 10,
@ -167,8 +167,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 2, difficulty: 2,
gen: (): [number, number[]] => { gen: (): [number, number[]] => {
const n: number = getRandomInt(12, 200); const n: number = getRandomIntInclusive(12, 200);
const maxLen: number = getRandomInt(8, 12); const maxLen: number = getRandomIntInclusive(8, 12);
const s: number[] = []; const s: number[] = [];
// Bias towards small numbers is intentional to have much bigger answers in general // Bias towards small numbers is intentional to have much bigger answers in general
// to force people better optimize their solutions // to force people better optimize their solutions
@ -241,8 +241,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 2, difficulty: 2,
gen: (): number[][] => { gen: (): number[][] => {
const m: number = getRandomInt(1, 15); const m: number = getRandomIntInclusive(1, 15);
const n: number = getRandomInt(1, 15); const n: number = getRandomIntInclusive(1, 15);
const matrix: number[][] = []; const matrix: number[][] = [];
matrix.length = m; matrix.length = m;
for (let i = 0; i < m; ++i) { for (let i = 0; i < m; ++i) {
@ -252,7 +252,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
for (let i = 0; i < m; ++i) { for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j) { for (let j = 0; j < n; ++j) {
matrix[i][j] = getRandomInt(1, 50); matrix[i][j] = getRandomIntInclusive(1, 50);
} }
} }
@ -345,14 +345,14 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 2.5, difficulty: 2.5,
gen: (): number[] => { gen: (): number[] => {
const len: number = getRandomInt(3, 25); const len: number = getRandomIntInclusive(3, 25);
const arr: number[] = []; const arr: number[] = [];
arr.length = len; arr.length = len;
for (let i = 0; i < arr.length; ++i) { for (let i = 0; i < arr.length; ++i) {
if (Math.random() < 0.2) { if (Math.random() < 0.2) {
arr[i] = 0; // 20% chance of being 0 arr[i] = 0; // 20% chance of being 0
} else { } else {
arr[i] = getRandomInt(0, 10); arr[i] = getRandomIntInclusive(0, 10);
} }
} }
@ -389,7 +389,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 3, difficulty: 3,
gen: (): number[] => { gen: (): number[] => {
const len: number = getRandomInt(3, 25); const len: number = getRandomIntInclusive(3, 25);
const arr: number[] = []; const arr: number[] = [];
arr.length = len; arr.length = len;
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
@ -447,10 +447,10 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
difficulty: 3, difficulty: 3,
gen: (): number[][] => { gen: (): number[][] => {
const intervals: number[][] = []; const intervals: number[][] = [];
const numIntervals: number = getRandomInt(3, 20); const numIntervals: number = getRandomIntInclusive(3, 20);
for (let i = 0; i < numIntervals; ++i) { for (let i = 0; i < numIntervals; ++i) {
const start: number = getRandomInt(1, 25); const start: number = getRandomIntInclusive(1, 25);
const end: number = start + getRandomInt(1, 10); const end: number = start + getRandomIntInclusive(1, 10);
intervals.push([start, end]); intervals.push([start, end]);
} }
@ -503,7 +503,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
gen: (): string => { gen: (): string => {
let str = ""; let str = "";
for (let i = 0; i < 4; ++i) { for (let i = 0; i < 4; ++i) {
const num: number = getRandomInt(0, 255); const num: number = getRandomIntInclusive(0, 255);
const convNum: string = num.toString(); const convNum: string = num.toString();
str += convNum; str += convNum;
} }
@ -567,11 +567,11 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 1, difficulty: 1,
gen: (): number[] => { gen: (): number[] => {
const len: number = getRandomInt(3, 50); const len: number = getRandomIntInclusive(3, 50);
const arr: number[] = []; const arr: number[] = [];
arr.length = len; arr.length = len;
for (let i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
arr[i] = getRandomInt(1, 200); arr[i] = getRandomIntInclusive(1, 200);
} }
return arr; return arr;
@ -607,11 +607,11 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 2, difficulty: 2,
gen: (): number[] => { gen: (): number[] => {
const len: number = getRandomInt(3, 50); const len: number = getRandomIntInclusive(3, 50);
const arr: number[] = []; const arr: number[] = [];
arr.length = len; arr.length = len;
for (let i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
arr[i] = getRandomInt(1, 200); arr[i] = getRandomIntInclusive(1, 200);
} }
return arr; return arr;
@ -645,11 +645,11 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 5, difficulty: 5,
gen: (): number[] => { gen: (): number[] => {
const len: number = getRandomInt(3, 50); const len: number = getRandomIntInclusive(3, 50);
const arr: number[] = []; const arr: number[] = [];
arr.length = len; arr.length = len;
for (let i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
arr[i] = getRandomInt(1, 200); arr[i] = getRandomIntInclusive(1, 200);
} }
return arr; return arr;
@ -693,12 +693,12 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 8, difficulty: 8,
gen: (): [number, number[]] => { gen: (): [number, number[]] => {
const k = getRandomInt(2, 10); const k = getRandomIntInclusive(2, 10);
const len = getRandomInt(3, 50); const len = getRandomIntInclusive(3, 50);
const prices: number[] = []; const prices: number[] = [];
prices.length = len; prices.length = len;
for (let i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
prices[i] = getRandomInt(1, 200); prices[i] = getRandomIntInclusive(1, 200);
} }
return [k, prices]; return [k, prices];
@ -785,14 +785,14 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
difficulty: 5, difficulty: 5,
gen: (): number[][] => { gen: (): number[][] => {
const triangle: number[][] = []; const triangle: number[][] = [];
const levels: number = getRandomInt(3, 12); const levels: number = getRandomIntInclusive(3, 12);
triangle.length = levels; triangle.length = levels;
for (let row = 0; row < levels; ++row) { for (let row = 0; row < levels; ++row) {
triangle[row] = []; triangle[row] = [];
triangle[row].length = row + 1; triangle[row].length = row + 1;
for (let i = 0; i < triangle[row].length; ++i) { for (let i = 0; i < triangle[row].length; ++i) {
triangle[row][i] = getRandomInt(1, 9); triangle[row][i] = getRandomIntInclusive(1, 9);
} }
} }
@ -832,8 +832,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 3, difficulty: 3,
gen: (): number[] => { gen: (): number[] => {
const numRows: number = getRandomInt(2, 14); const numRows: number = getRandomIntInclusive(2, 14);
const numColumns: number = getRandomInt(2, 14); const numColumns: number = getRandomIntInclusive(2, 14);
return [numRows, numColumns]; return [numRows, numColumns];
}, },
@ -878,8 +878,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 5, difficulty: 5,
gen: (): number[][] => { gen: (): number[][] => {
const numRows: number = getRandomInt(2, 12); const numRows: number = getRandomIntInclusive(2, 12);
const numColumns: number = getRandomInt(2, 12); const numColumns: number = getRandomIntInclusive(2, 12);
const grid: number[][] = []; const grid: number[][] = [];
grid.length = numRows; grid.length = numRows;
@ -961,8 +961,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
difficulty: 7, difficulty: 7,
numTries: 10, numTries: 10,
gen: (): number[][] => { gen: (): number[][] => {
const height = getRandomInt(6, 12); const height = getRandomIntInclusive(6, 12);
const width = getRandomInt(6, 12); const width = getRandomIntInclusive(6, 12);
const dstY = height - 1; const dstY = height - 1;
const dstX = width - 1; const dstX = width - 1;
const minPathLength = dstY + dstX; // Math.abs(dstY - srcY) + Math.abs(dstX - srcX) const minPathLength = dstY + dstX; // Math.abs(dstY - srcY) + Math.abs(dstX - srcX)
@ -1087,7 +1087,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 10, difficulty: 10,
gen: (): string => { gen: (): string => {
const len: number = getRandomInt(6, 20); const len: number = getRandomIntInclusive(6, 20);
const chars: string[] = []; const chars: string[] = [];
chars.length = len; chars.length = len;
@ -1205,18 +1205,18 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
difficulty: 10, difficulty: 10,
gen: (): [string, number] => { gen: (): [string, number] => {
const numDigits = getRandomInt(4, 12); const numDigits = getRandomIntInclusive(4, 12);
const digitsArray: string[] = []; const digitsArray: string[] = [];
digitsArray.length = numDigits; digitsArray.length = numDigits;
for (let i = 0; i < digitsArray.length; ++i) { for (let i = 0; i < digitsArray.length; ++i) {
if (i === 0) { if (i === 0) {
digitsArray[i] = String(getRandomInt(1, 9)); digitsArray[i] = String(getRandomIntInclusive(1, 9));
} else { } else {
digitsArray[i] = String(getRandomInt(0, 9)); digitsArray[i] = String(getRandomIntInclusive(0, 9));
} }
} }
const target: number = getRandomInt(-100, 100); const target: number = getRandomIntInclusive(-100, 100);
const digits: string = digitsArray.join(""); const digits: string = digitsArray.join("");
return [digits, target]; return [digits, target];
@ -1316,7 +1316,9 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
].join(" "); ].join(" ");
}, },
gen: (): number => { gen: (): number => {
return getRandomInt(Math.pow(2, 4), Math.pow(2, getRandomInt(1, 57))); const x = Math.pow(2, 4);
const y = Math.pow(2, getRandomIntInclusive(1, 57));
return getRandomIntInclusive(Math.min(x, y), Math.max(x, y));
}, },
solver: (data: unknown, ans: string): boolean => { solver: (data: unknown, ans: string): boolean => {
if (typeof data !== "number") throw new Error("solver expected number"); if (typeof data !== "number") throw new Error("solver expected number");
@ -1351,11 +1353,13 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
}, },
gen: (): string => { gen: (): string => {
const _alteredBit = Math.round(Math.random()); const _alteredBit = Math.round(Math.random());
const _buildArray: string[] = HammingEncodeProperly( const x = Math.pow(2, 4);
getRandomInt(Math.pow(2, 4), Math.pow(2, getRandomInt(1, 57))), const y = Math.pow(2, getRandomIntInclusive(1, 57));
).split(""); const _buildArray: string[] = HammingEncodeProperly(getRandomIntInclusive(Math.min(x, y), Math.max(x, y))).split(
"",
);
if (_alteredBit) { if (_alteredBit) {
const _randomIndex: number = getRandomInt(0, _buildArray.length - 1); const _randomIndex: number = getRandomIntInclusive(0, _buildArray.length - 1);
_buildArray[_randomIndex] = _buildArray[_randomIndex] == "0" ? "1" : "0"; _buildArray[_randomIndex] = _buildArray[_randomIndex] == "0" ? "1" : "0";
} }
return _buildArray.join(""); return _buildArray.join("");

@ -4,7 +4,7 @@ import type { NetscriptContext } from "../Netscript/APIWrapper";
import * as allEnums from "../Enums"; import * as allEnums from "../Enums";
import { assertString } from "../Netscript/TypeAssertion"; import { assertString } from "../Netscript/TypeAssertion";
import { errorMessage } from "../Netscript/ErrorMessages"; import { errorMessage } from "../Netscript/ErrorMessages";
import { getRandomInt } from "./helpers/getRandomInt"; import { getRandomIntInclusive } from "./helpers/getRandomIntInclusive";
interface GetMemberOptions { interface GetMemberOptions {
/** Whether to use fuzzy matching on the input (case insensitive, ignore spaces and dashes) */ /** Whether to use fuzzy matching on the input (case insensitive, ignore spaces and dashes) */
@ -69,7 +69,7 @@ class EnumHelper<EnumObj extends object, EnumMember extends Member<EnumObj> & st
} }
// Get a random enum member // Get a random enum member
random() { random() {
const index = getRandomInt(0, this.valueArray.length - 1); const index = getRandomIntInclusive(0, this.valueArray.length - 1);
return this.valueArray[index]; return this.valueArray[index];
} }
} }

@ -1,4 +1,4 @@
import { getRandomInt } from "./getRandomInt"; import { getRandomIntInclusive } from "./getRandomIntInclusive";
/** /**
* Gets a random value in the range of a byte (0 - 255), or up to the maximum. * Gets a random value in the range of a byte (0 - 255), or up to the maximum.
@ -9,5 +9,5 @@ export function getRandomByte(max: number): number {
const byteMaximum = 255; const byteMaximum = 255;
const upper: number = Math.max(Math.min(max, byteMaximum), 0); const upper: number = Math.max(Math.min(max, byteMaximum), 0);
return getRandomInt(0, upper); return getRandomIntInclusive(0, upper);
} }

@ -1,11 +0,0 @@
/**
* Gets a random integer bounded by the values passed in.
* @param min The minimum value in the range.
* @param max The maximum value in the range.
*/
export function getRandomInt(min: number, max: number): number {
const lower: number = Math.min(min, max);
const upper: number = Math.max(min, max);
return Math.floor(Math.random() * (upper - lower + 1)) + lower;
}

@ -0,0 +1,21 @@
/**
*
* Gets a random integer between min (inclusive) and max (inclusive).
*
* Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
*
* @param min The minimum value in the range.
* @param max The maximum value in the range.
*/
export function getRandomIntInclusive(min: number, max: number): number {
if (!Number.isInteger(min)) {
throw new Error(`Min is not an integer. Min: ${min}.`);
}
if (!Number.isInteger(max)) {
throw new Error(`Max is not an integer. Max: ${max}.`);
}
if (min > max) {
throw new Error(`Min is greater than max. Min: ${min}. Max: ${max}.`);
}
return Math.floor(Math.random() * (max - min + 1) + min);
}