Skip to content

Commit

Permalink
BUGFIX: Improve implementation of getRandomInt (#1282)
Browse files Browse the repository at this point in the history
  • Loading branch information
catloversg authored May 18, 2024
1 parent 8deb907 commit 175af0b
Show file tree
Hide file tree
Showing 20 changed files with 160 additions and 130 deletions.
6 changes: 3 additions & 3 deletions src/Bladeburner/Actions/LevelableAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 & {
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down
36 changes: 18 additions & 18 deletions src/Bladeburner/Bladeburner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -64,7 +64,7 @@ export class Bladeburner {

storedCycles = 0;

randomEventCounter: number = getRandomInt(240, 600);
randomEventCounter: number = getRandomIntInclusive(240, 600);

actionTimeToComplete = 0;
actionTimeCurrent = 0;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand All @@ -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:
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down
9 changes: 6 additions & 3 deletions src/Bladeburner/City.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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;
}

Expand Down
8 changes: 4 additions & 4 deletions src/Bladeburner/data/Contracts.ts
Original file line number Diff line number Diff line change
@@ -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> {
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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,
}),
};
Expand Down
14 changes: 7 additions & 7 deletions src/Bladeburner/data/Operations.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -202,7 +202,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
},
isStealth: true,
isKill: true,
growthFunction: () => getRandomInt(1, 20) / 10,
growthFunction: () => getRandomIntInclusive(1, 20) / 10,
}),
};
}
Expand Down
29 changes: 19 additions & 10 deletions src/CodingContractGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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];
}
Expand All @@ -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);
Expand All @@ -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 };
}
Expand All @@ -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
Expand All @@ -170,7 +179,7 @@ function getRandomServer(): BaseServer {
) {
break;
}
randIndex = getRandomInt(0, servers.length - 1);
randIndex = getRandomIntInclusive(0, servers.length - 1);
randServer = servers[randIndex];
}

Expand All @@ -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 (
Expand All @@ -191,7 +200,7 @@ function getRandomFilename(
) {
break;
}
contractFn = `contract-${getRandomInt(0, 1e6)}`;
contractFn = `contract-${getRandomIntInclusive(0, 1e6)}`;
}

if ("name" in reward) {
Expand Down
Loading

0 comments on commit 175af0b

Please sign in to comment.