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

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

@ -1,6 +1,6 @@
import { CityName } from "@enums";
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 { addOffset } from "../utils/helpers/addOffset";
import { clampInteger, clampNumber } from "../utils/helpers/clampNumber";
@ -16,11 +16,14 @@ export class City {
this.name = name;
// 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);
// Number of Synthoid communities population and estimate
this.comms = getRandomInt(5, 150);
this.comms = getRandomIntInclusive(5, 150);
this.chaos = 0;
}

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

@ -1,6 +1,6 @@
import { BladeOperationName } from "@enums";
import { Operation } from "../Actions/Operation";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
import { LevelableActionClass } from "../Actions/LevelableAction";
import { assertLoadingType } from "../../utils/TypeAssertion";
@ -36,7 +36,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
intelligence: 0.9,
},
isStealth: true,
growthFunction: () => getRandomInt(10, 40) / 10,
growthFunction: () => getRandomIntInclusive(10, 40) / 10,
maxCount: 100,
}),
[BladeOperationName.undercover]: new Operation({
@ -69,7 +69,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
intelligence: 0.9,
},
isStealth: true,
growthFunction: () => getRandomInt(10, 40) / 10,
growthFunction: () => getRandomIntInclusive(10, 40) / 10,
maxCount: 100,
}),
[BladeOperationName.sting]: new Operation({
@ -100,7 +100,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
intelligence: 0.9,
},
isStealth: true,
growthFunction: () => getRandomInt(3, 40) / 10,
growthFunction: () => getRandomIntInclusive(3, 40) / 10,
}),
[BladeOperationName.raid]: new Operation({
name: BladeOperationName.raid,
@ -132,7 +132,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
intelligence: 0.9,
},
isKill: true,
growthFunction: () => getRandomInt(2, 40) / 10,
growthFunction: () => getRandomIntInclusive(2, 40) / 10,
getAvailability: function (bladeburner) {
if (bladeburner.getCurrentCity().comms < 1) return { error: "No Synthoid communities in current city" };
return LevelableActionClass.prototype.getAvailability.call(this, bladeburner);
@ -169,7 +169,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
},
isStealth: true,
isKill: true,
growthFunction: () => getRandomInt(1, 20) / 10,
growthFunction: () => getRandomIntInclusive(1, 20) / 10,
}),
[BladeOperationName.assassination]: new Operation({
name: BladeOperationName.assassination,
@ -202,7 +202,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
},
isStealth: 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 { BaseServer } from "./Server/BaseServer";
import { getRandomInt } from "./utils/helpers/getRandomInt";
import { getRandomIntInclusive } from "./utils/helpers/getRandomIntInclusive";
import { ContractFilePath, resolveContractFilePath } from "./Paths/ContractFilePath";
export function generateRandomContract(): void {
@ -121,7 +121,7 @@ function sanitizeRewardType(rewardType: CodingContractRewardType): CodingContrac
function getRandomProblemType(): string {
const problemTypes = Object.keys(CodingContractTypes);
const randIndex = getRandomInt(0, problemTypes.length - 1);
const randIndex = getRandomIntInclusive(0, problemTypes.length - 1);
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)
const rewardTypeUpperBound =
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
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
// faction must allow hacking contracts
const numFactions = factionsThatAllowHacking.length;
const randFaction = factionsThatAllowHacking[getRandomInt(0, numFactions - 1)];
return { type: rewardType, name: randFaction };
// 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: CodingContractRewardType.Money };
}
case CodingContractRewardType.CompanyReputation: {
const allJobs = Object.keys(Player.jobs);
// This check is also unnecessary. Check the comment above.
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 };
}
@ -157,7 +166,7 @@ function getRandomReward(): ICodingContractReward {
function getRandomServer(): BaseServer {
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];
// An infinite loop shouldn't ever happen, but to be safe we'll use
@ -170,7 +179,7 @@ function getRandomServer(): BaseServer {
) {
break;
}
randIndex = getRandomInt(0, servers.length - 1);
randIndex = getRandomIntInclusive(0, servers.length - 1);
randServer = servers[randIndex];
}
@ -181,7 +190,7 @@ function getRandomFilename(
server: BaseServer,
reward: ICodingContractReward = { type: CodingContractRewardType.Money },
): ContractFilePath {
let contractFn = `contract-${getRandomInt(0, 1e6)}`;
let contractFn = `contract-${getRandomIntInclusive(0, 1e6)}`;
for (let i = 0; i < 1000; ++i) {
if (
@ -191,7 +200,7 @@ function getRandomFilename(
) {
break;
}
contractFn = `contract-${getRandomInt(0, 1e6)}`;
contractFn = `contract-${getRandomIntInclusive(0, 1e6)}`;
}
if ("name" in reward) {

@ -14,7 +14,7 @@ import { FactionName, IndustryType } from "@enums";
import { ResearchMap } from "./ResearchMap";
import { isRelevantMaterial } from "./ui/Helpers";
import { CityName } from "@enums";
import { getRandomInt } from "../utils/helpers/getRandomInt";
import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
import { getRecordValues } from "../Types/Record";
import {
calculateOfficeSizeUpgradeCost,
@ -166,7 +166,7 @@ export function issueNewShares(
const privateOwnedRatio = corporation.investorShares / corporation.totalShares;
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.investorShares += privateShares;

@ -3,7 +3,7 @@ import { CityName, CorpEmployeeJob, IndustryType } from "@enums";
import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver";
import { IndustryResearchTrees, IndustriesData } from "./data/IndustryData";
import * as corpConstants from "./data/Constants";
import { getRandomInt } from "../utils/helpers/getRandomInt";
import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
import { calculateEffectWithFactors } from "../utils/calculateEffectWithFactors";
import { OfficeSpace } from "./OfficeSpace";
import { Product } from "./Product";
@ -254,7 +254,7 @@ export class Division {
processProductMarket(marketCycles = 1): void {
// Demand gradually decreases, and competition gradually increases
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 (
@ -985,7 +985,7 @@ export class Division {
const awareness = (this.awareness + 3 * advMult) * (1.005 * advMult);
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.numAdVerts;

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

@ -6,7 +6,7 @@ import { IndustriesData } from "./data/IndustryData";
import { MaterialInfo } from "./MaterialInfo";
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";
interface IConstructorParams {
@ -202,7 +202,7 @@ export class Product {
this.demand =
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
this.size = 0;

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

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

@ -6,7 +6,7 @@ import { HacknetServer } from "../Hacknet/HacknetServer";
import { IMinMaxRange } from "../types";
import { createRandomIp } from "../utils/IPAddress";
import { getRandomInt } from "../utils/helpers/getRandomInt";
import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
import { Reviver } from "../utils/JSONReviver";
import { SpecialServers } from "./data/SpecialServers";
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
@ -133,7 +133,7 @@ export function initForeignServers(homeComputer: Server): void {
const toNumber = (value: number | IMinMaxRange): number => {
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) {

@ -1,6 +1,6 @@
import { IMinMaxRange } from "../types";
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;
@ -37,7 +37,7 @@ function toNumber(n: number | IMinMaxRange): number {
}
case "object": {
const range = n;
value = getRandomInt(range.min, range.max);
value = getRandomIntInclusive(range.min, range.max);
break;
}
default:
@ -136,7 +136,7 @@ export class Stock {
this.b = p.b;
this.otlkMag = p.otlkMag;
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.shareTxForMovement = toNumber(p.shareTxForMovement);
this.shareTxUntilMovement = this.shareTxForMovement;

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

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

@ -4,7 +4,7 @@ import type { NetscriptContext } from "../Netscript/APIWrapper";
import * as allEnums from "../Enums";
import { assertString } from "../Netscript/TypeAssertion";
import { errorMessage } from "../Netscript/ErrorMessages";
import { getRandomInt } from "./helpers/getRandomInt";
import { getRandomIntInclusive } from "./helpers/getRandomIntInclusive";
interface GetMemberOptions {
/** 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
random() {
const index = getRandomInt(0, this.valueArray.length - 1);
const index = getRandomIntInclusive(0, this.valueArray.length - 1);
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.
@ -9,5 +9,5 @@ export function getRandomByte(max: number): number {
const byteMaximum = 255;
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);
}