Skip to content

Commit 175af0b

Browse files
authored
BUGFIX: Improve implementation of getRandomInt (#1282)
1 parent 8deb907 commit 175af0b

20 files changed

+160
-130
lines changed

src/Bladeburner/Actions/LevelableAction.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { IReviverValue } from "../../utils/JSONReviver";
33
import type { Availability } from "../Types";
44

55
import { ActionClass, ActionParams } from "./Action";
6-
import { getRandomInt } from "../../utils/helpers/getRandomInt";
6+
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
77
import { clampInteger } from "../../utils/helpers/clampNumber";
88

99
export type LevelableActionParams = ActionParams & {
@@ -37,7 +37,7 @@ export abstract class LevelableActionClass extends ActionClass {
3737
if (params.maxCount) this.maxCount = params.maxCount;
3838
if (params.difficultyFac) this.difficultyFac = params.difficultyFac;
3939
if (params.rewardFac) this.rewardFac = params.rewardFac;
40-
this.count = getRandomInt(this.minCount, this.maxCount);
40+
this.count = getRandomIntInclusive(this.minCount, this.maxCount);
4141
this.growthFunction = params.growthFunction;
4242
}
4343

@@ -65,7 +65,7 @@ export abstract class LevelableActionClass extends ActionClass {
6565

6666
/** Reset a levelable action's tracked stats */
6767
reset() {
68-
this.count = getRandomInt(this.minCount, this.maxCount);
68+
this.count = getRandomIntInclusive(this.minCount, this.maxCount);
6969
this.level = 1;
7070
this.maxLevel = 1;
7171
this.autoLevel = true;

src/Bladeburner/Bladeburner.ts

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { Player } from "@player";
2424
import { Router } from "../ui/GameRoot";
2525
import { ConsoleHelpText } from "./data/Help";
2626
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
27-
import { getRandomInt } from "../utils/helpers/getRandomInt";
27+
import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
2828
import { BladeburnerConstants } from "./data/Constants";
2929
import { formatExp, formatMoney, formatPercent, formatBigNumber, formatStamina } from "../ui/formatNumber";
3030
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
@@ -64,7 +64,7 @@ export class Bladeburner {
6464

6565
storedCycles = 0;
6666

67-
randomEventCounter: number = getRandomInt(240, 600);
67+
randomEventCounter: number = getRandomIntInclusive(240, 600);
6868

6969
actionTimeToComplete = 0;
7070
actionTimeCurrent = 0;
@@ -522,11 +522,11 @@ export class Bladeburner {
522522
const sourceCity = this.cities[sourceCityName];
523523

524524
const rand = Math.random();
525-
let percentage = getRandomInt(3, 15) / 100;
525+
let percentage = getRandomIntInclusive(3, 15) / 100;
526526

527527
if (rand < 0.05 && sourceCity.comms > 0) {
528528
// 5% chance for community migration
529-
percentage *= getRandomInt(2, 4); // Migration increases population change
529+
percentage *= getRandomIntInclusive(2, 4); // Migration increases population change
530530
--sourceCity.comms;
531531
++destCity.comms;
532532
}
@@ -565,7 +565,7 @@ export class Bladeburner {
565565
if (chance <= 0.05) {
566566
// New Synthoid Community, 5%
567567
++sourceCity.comms;
568-
const percentage = getRandomInt(10, 20) / 100;
568+
const percentage = getRandomIntInclusive(10, 20) / 100;
569569
const count = Math.round(sourceCity.pop * percentage);
570570
sourceCity.pop += count;
571571
if (sourceCity.pop < BladeburnerConstants.PopGrowthCeiling) {
@@ -579,7 +579,7 @@ export class Bladeburner {
579579
if (sourceCity.comms <= 0) {
580580
// If no comms in source city, then instead trigger a new Synthoid community event
581581
++sourceCity.comms;
582-
const percentage = getRandomInt(10, 20) / 100;
582+
const percentage = getRandomIntInclusive(10, 20) / 100;
583583
const count = Math.round(sourceCity.pop * percentage);
584584
sourceCity.pop += count;
585585
if (sourceCity.pop < BladeburnerConstants.PopGrowthCeiling) {
@@ -593,7 +593,7 @@ export class Bladeburner {
593593
++destCity.comms;
594594

595595
// Change pop
596-
const percentage = getRandomInt(10, 20) / 100;
596+
const percentage = getRandomIntInclusive(10, 20) / 100;
597597
const count = Math.round(sourceCity.pop * percentage);
598598
sourceCity.pop -= count;
599599
destCity.pop += count;
@@ -608,7 +608,7 @@ export class Bladeburner {
608608
}
609609
} else if (chance <= 0.3) {
610610
// New Synthoids (non community), 20%
611-
const percentage = getRandomInt(8, 24) / 100;
611+
const percentage = getRandomIntInclusive(8, 24) / 100;
612612
const count = Math.round(sourceCity.pop * percentage);
613613
sourceCity.pop += count;
614614
if (sourceCity.pop < BladeburnerConstants.PopGrowthCeiling) {
@@ -632,13 +632,13 @@ export class Bladeburner {
632632
} else if (chance <= 0.7) {
633633
// Synthoid Riots (+chaos), 20%
634634
sourceCity.chaos += 1;
635-
sourceCity.chaos *= 1 + getRandomInt(5, 20) / 100;
635+
sourceCity.chaos *= 1 + getRandomIntInclusive(5, 20) / 100;
636636
if (this.logging.events) {
637637
this.log("Tensions between Synthoids and humans lead to riots in " + sourceCityName + "! Chaos increased");
638638
}
639639
} else if (chance <= 0.9) {
640640
// Less Synthoids, 20%
641-
const percentage = getRandomInt(8, 20) / 100;
641+
const percentage = getRandomIntInclusive(8, 20) / 100;
642642
const count = Math.round(sourceCity.pop * percentage);
643643
sourceCity.pop -= count;
644644
if (this.logging.events) {
@@ -753,7 +753,7 @@ export class Bladeburner {
753753
const teamCount = action.teamCount;
754754
if (teamCount >= 1) {
755755
const maxLosses = success ? Math.ceil(teamCount / 2) : Math.floor(teamCount);
756-
const losses = getRandomInt(0, maxLosses);
756+
const losses = getRandomIntInclusive(0, maxLosses);
757757
this.teamSize -= losses;
758758
if (this.teamSize < this.sleeveSize) {
759759
const sup = Player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
@@ -803,13 +803,13 @@ export class Bladeburner {
803803
});
804804
--city.comms;
805805
} else {
806-
const change = getRandomInt(-10, -5) / 10;
806+
const change = getRandomIntInclusive(-10, -5) / 10;
807807
city.changePopulationByPercentage(change, {
808808
nonZero: true,
809809
changeEstEqually: false,
810810
});
811811
}
812-
city.changeChaosByPercentage(getRandomInt(1, 5));
812+
city.changeChaosByPercentage(getRandomIntInclusive(1, 5));
813813
break;
814814
case BladeOperationName.stealthRetirement:
815815
if (success) {
@@ -818,13 +818,13 @@ export class Bladeburner {
818818
nonZero: true,
819819
});
820820
}
821-
city.changeChaosByPercentage(getRandomInt(-3, -1));
821+
city.changeChaosByPercentage(getRandomIntInclusive(-3, -1));
822822
break;
823823
case BladeOperationName.assassination:
824824
if (success) {
825825
city.changePopulationByCount(-1, { estChange: -1, estOffset: 0 });
826826
}
827-
city.changeChaosByPercentage(getRandomInt(-5, 5));
827+
city.changeChaosByPercentage(getRandomIntInclusive(-5, 5));
828828
break;
829829
default:
830830
throw new Error("Invalid Action name in completeOperation: " + this.action.name);
@@ -838,7 +838,7 @@ export class Bladeburner {
838838
case BladeContractName.tracking:
839839
// Increase estimate accuracy by a relatively small amount
840840
city.improvePopulationEstimateByCount(
841-
getRandomInt(100, 1e3) * this.getSkillMult(BladeMultName.successChanceEstimate),
841+
getRandomIntInclusive(100, 1e3) * this.getSkillMult(BladeMultName.successChanceEstimate),
842842
);
843843
break;
844844
case BladeContractName.bountyHunter:
@@ -1012,7 +1012,7 @@ export class Bladeburner {
10121012

10131013
// Calculate team losses
10141014
if (teamCount >= 1) {
1015-
const losses = getRandomInt(1, teamLossMax);
1015+
const losses = getRandomIntInclusive(1, teamLossMax);
10161016
this.teamSize -= losses;
10171017
if (this.teamSize < this.sleeveSize) {
10181018
const sup = Player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
@@ -1332,7 +1332,7 @@ export class Bladeburner {
13321332
if (this.randomEventCounter <= 0) {
13331333
this.randomEvent();
13341334
// Add instead of setting because we might have gone over the required time for the event
1335-
this.randomEventCounter += getRandomInt(240, 600);
1335+
this.randomEventCounter += getRandomIntInclusive(240, 600);
13361336
}
13371337

13381338
this.processAction(seconds);

src/Bladeburner/City.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { CityName } from "@enums";
22
import { BladeburnerConstants } from "./data/Constants";
3-
import { getRandomInt } from "../utils/helpers/getRandomInt";
3+
import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
44
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver";
55
import { addOffset } from "../utils/helpers/addOffset";
66
import { clampInteger, clampNumber } from "../utils/helpers/clampNumber";
@@ -16,11 +16,14 @@ export class City {
1616
this.name = name;
1717

1818
// Synthoid population and estimate
19-
this.pop = getRandomInt(BladeburnerConstants.PopulationThreshold, 1.5 * BladeburnerConstants.PopulationThreshold);
19+
this.pop = getRandomIntInclusive(
20+
BladeburnerConstants.PopulationThreshold,
21+
1.5 * BladeburnerConstants.PopulationThreshold,
22+
);
2023
this.popEst = this.pop * (Math.random() + 0.5);
2124

2225
// Number of Synthoid communities population and estimate
23-
this.comms = getRandomInt(5, 150);
26+
this.comms = getRandomIntInclusive(5, 150);
2427
this.chaos = 0;
2528
}
2629

src/Bladeburner/data/Contracts.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { BladeContractName } from "@enums";
22
import { Contract } from "../Actions/Contract";
3-
import { getRandomInt } from "../../utils/helpers/getRandomInt";
3+
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
44
import { assertLoadingType } from "../../utils/TypeAssertion";
55

66
export function createContracts(): Record<BladeContractName, Contract> {
@@ -36,7 +36,7 @@ export function createContracts(): Record<BladeContractName, Contract> {
3636
intelligence: 1,
3737
},
3838
isStealth: true,
39-
growthFunction: () => getRandomInt(5, 75) / 10,
39+
growthFunction: () => getRandomIntInclusive(5, 75) / 10,
4040
minCount: 25,
4141
}),
4242
[BladeContractName.bountyHunter]: new Contract({
@@ -69,7 +69,7 @@ export function createContracts(): Record<BladeContractName, Contract> {
6969
intelligence: 0.9,
7070
},
7171
isKill: true,
72-
growthFunction: () => getRandomInt(5, 75) / 10,
72+
growthFunction: () => getRandomIntInclusive(5, 75) / 10,
7373
minCount: 5,
7474
}),
7575
[BladeContractName.retirement]: new Contract({
@@ -102,7 +102,7 @@ export function createContracts(): Record<BladeContractName, Contract> {
102102
intelligence: 0.9,
103103
},
104104
isKill: true,
105-
growthFunction: () => getRandomInt(5, 75) / 10,
105+
growthFunction: () => getRandomIntInclusive(5, 75) / 10,
106106
minCount: 5,
107107
}),
108108
};

src/Bladeburner/data/Operations.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { BladeOperationName } from "@enums";
22
import { Operation } from "../Actions/Operation";
3-
import { getRandomInt } from "../../utils/helpers/getRandomInt";
3+
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
44
import { LevelableActionClass } from "../Actions/LevelableAction";
55
import { assertLoadingType } from "../../utils/TypeAssertion";
66

@@ -36,7 +36,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
3636
intelligence: 0.9,
3737
},
3838
isStealth: true,
39-
growthFunction: () => getRandomInt(10, 40) / 10,
39+
growthFunction: () => getRandomIntInclusive(10, 40) / 10,
4040
maxCount: 100,
4141
}),
4242
[BladeOperationName.undercover]: new Operation({
@@ -69,7 +69,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
6969
intelligence: 0.9,
7070
},
7171
isStealth: true,
72-
growthFunction: () => getRandomInt(10, 40) / 10,
72+
growthFunction: () => getRandomIntInclusive(10, 40) / 10,
7373
maxCount: 100,
7474
}),
7575
[BladeOperationName.sting]: new Operation({
@@ -100,7 +100,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
100100
intelligence: 0.9,
101101
},
102102
isStealth: true,
103-
growthFunction: () => getRandomInt(3, 40) / 10,
103+
growthFunction: () => getRandomIntInclusive(3, 40) / 10,
104104
}),
105105
[BladeOperationName.raid]: new Operation({
106106
name: BladeOperationName.raid,
@@ -132,7 +132,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
132132
intelligence: 0.9,
133133
},
134134
isKill: true,
135-
growthFunction: () => getRandomInt(2, 40) / 10,
135+
growthFunction: () => getRandomIntInclusive(2, 40) / 10,
136136
getAvailability: function (bladeburner) {
137137
if (bladeburner.getCurrentCity().comms < 1) return { error: "No Synthoid communities in current city" };
138138
return LevelableActionClass.prototype.getAvailability.call(this, bladeburner);
@@ -169,7 +169,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
169169
},
170170
isStealth: true,
171171
isKill: true,
172-
growthFunction: () => getRandomInt(1, 20) / 10,
172+
growthFunction: () => getRandomIntInclusive(1, 20) / 10,
173173
}),
174174
[BladeOperationName.assassination]: new Operation({
175175
name: BladeOperationName.assassination,
@@ -202,7 +202,7 @@ export function createOperations(): Record<BladeOperationName, Operation> {
202202
},
203203
isStealth: true,
204204
isKill: true,
205-
growthFunction: () => getRandomInt(1, 20) / 10,
205+
growthFunction: () => getRandomIntInclusive(1, 20) / 10,
206206
}),
207207
};
208208
}

src/CodingContractGenerator.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { SpecialServers } from "./Server/data/SpecialServers";
1212
import { Server } from "./Server/Server";
1313
import { BaseServer } from "./Server/BaseServer";
1414

15-
import { getRandomInt } from "./utils/helpers/getRandomInt";
15+
import { getRandomIntInclusive } from "./utils/helpers/getRandomIntInclusive";
1616
import { ContractFilePath, resolveContractFilePath } from "./Paths/ContractFilePath";
1717

1818
export function generateRandomContract(): void {
@@ -121,7 +121,7 @@ function sanitizeRewardType(rewardType: CodingContractRewardType): CodingContrac
121121

122122
function getRandomProblemType(): string {
123123
const problemTypes = Object.keys(CodingContractTypes);
124-
const randIndex = getRandomInt(0, problemTypes.length - 1);
124+
const randIndex = getRandomIntInclusive(0, problemTypes.length - 1);
125125

126126
return problemTypes[randIndex];
127127
}
@@ -130,7 +130,7 @@ function getRandomReward(): ICodingContractReward {
130130
// Don't offer money reward by default if BN multiplier is 0 (e.g. BN8)
131131
const rewardTypeUpperBound =
132132
currentNodeMults.CodingContractMoney === 0 ? CodingContractRewardType.Money - 1 : CodingContractRewardType.Money;
133-
const rewardType = sanitizeRewardType(getRandomInt(0, rewardTypeUpperBound));
133+
const rewardType = sanitizeRewardType(getRandomIntInclusive(0, rewardTypeUpperBound));
134134

135135
// Add additional information based on the reward type
136136
const factionsThatAllowHacking = Player.factions.filter((fac) => Factions[fac].getInfo().offerHackingWork);
@@ -140,13 +140,22 @@ function getRandomReward(): ICodingContractReward {
140140
// Get a random faction that player is a part of. That
141141
// faction must allow hacking contracts
142142
const numFactions = factionsThatAllowHacking.length;
143-
const randFaction = factionsThatAllowHacking[getRandomInt(0, numFactions - 1)];
144-
return { type: rewardType, name: randFaction };
143+
// This check is unnecessary because sanitizeRewardType ensures that it won't happen. However, I'll still leave
144+
// it here, just in case somebody else changes sanitizeRewardType without taking account of this check.
145+
if (numFactions > 0) {
146+
const randFaction = factionsThatAllowHacking[getRandomIntInclusive(0, numFactions - 1)];
147+
return { type: rewardType, name: randFaction };
148+
}
149+
return { type: CodingContractRewardType.Money };
145150
}
146151
case CodingContractRewardType.CompanyReputation: {
147152
const allJobs = Object.keys(Player.jobs);
153+
// This check is also unnecessary. Check the comment above.
148154
if (allJobs.length > 0) {
149-
return { type: CodingContractRewardType.CompanyReputation, name: allJobs[getRandomInt(0, allJobs.length - 1)] };
155+
return {
156+
type: CodingContractRewardType.CompanyReputation,
157+
name: allJobs[getRandomIntInclusive(0, allJobs.length - 1)],
158+
};
150159
}
151160
return { type: CodingContractRewardType.Money };
152161
}
@@ -157,7 +166,7 @@ function getRandomReward(): ICodingContractReward {
157166

158167
function getRandomServer(): BaseServer {
159168
const servers = GetAllServers().filter((server: BaseServer) => server.serversOnNetwork.length !== 0);
160-
let randIndex = getRandomInt(0, servers.length - 1);
169+
let randIndex = getRandomIntInclusive(0, servers.length - 1);
161170
let randServer = servers[randIndex];
162171

163172
// An infinite loop shouldn't ever happen, but to be safe we'll use
@@ -170,7 +179,7 @@ function getRandomServer(): BaseServer {
170179
) {
171180
break;
172181
}
173-
randIndex = getRandomInt(0, servers.length - 1);
182+
randIndex = getRandomIntInclusive(0, servers.length - 1);
174183
randServer = servers[randIndex];
175184
}
176185

@@ -181,7 +190,7 @@ function getRandomFilename(
181190
server: BaseServer,
182191
reward: ICodingContractReward = { type: CodingContractRewardType.Money },
183192
): ContractFilePath {
184-
let contractFn = `contract-${getRandomInt(0, 1e6)}`;
193+
let contractFn = `contract-${getRandomIntInclusive(0, 1e6)}`;
185194

186195
for (let i = 0; i < 1000; ++i) {
187196
if (
@@ -191,7 +200,7 @@ function getRandomFilename(
191200
) {
192201
break;
193202
}
194-
contractFn = `contract-${getRandomInt(0, 1e6)}`;
203+
contractFn = `contract-${getRandomIntInclusive(0, 1e6)}`;
195204
}
196205

197206
if ("name" in reward) {

0 commit comments

Comments
 (0)