namespaced formulas for easier importing
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
a6a00066cc
commit
f12de39c91
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
NOTE: All user scripts to be synced with the game is found under `src/`.
|
NOTE: All user scripts to be synced with the game is found under `src/`.
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- Fix the fucking ezgame.formulas.hacking.growTime(). calculateIntelligenceBonus() is throwing errors when calculating intelligence. Clearly my intelligence value is 0.
|
||||||
|
|
||||||
This is a template for a viteburner project. It is a simple example of how to use Viteburner.
|
This is a template for a viteburner project. It is a simple example of how to use Viteburner.
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
|
||||||
5
src/ezgame.ts
Normal file
5
src/ezgame.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { formulas } from "./ezgame/formulas";
|
||||||
|
|
||||||
|
export const ezgame = {
|
||||||
|
formulas,
|
||||||
|
};
|
||||||
15
src/ezgame/formulas.ts
Normal file
15
src/ezgame/formulas.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { gang } from "./formulas/gang";
|
||||||
|
import { hacking } from "./formulas/hacking";
|
||||||
|
import { hacknetNodes } from "./formulas/hacknet-nodes";
|
||||||
|
import { hacknetServers } from "./formulas/hacknet-servers";
|
||||||
|
import { reputation } from "./formulas/reputation";
|
||||||
|
import { skills } from "./formulas/skills";
|
||||||
|
|
||||||
|
export const formulas = {
|
||||||
|
gang,
|
||||||
|
hacking,
|
||||||
|
hacknetNodes,
|
||||||
|
hacknetServers,
|
||||||
|
reputation,
|
||||||
|
skills,
|
||||||
|
};
|
||||||
|
|
@ -6,7 +6,7 @@ Reverse engineered from the [bitburner source](https://github.com/bitburner-offi
|
||||||
|
|
||||||
### Gang
|
### Gang
|
||||||
|
|
||||||
- [ ] `ascencionMultipler(points)`
|
- [ ] `ascensionMultiplier(points)`
|
||||||
- [ ] `ascensionPointsGain(exp)`
|
- [ ] `ascensionPointsGain(exp)`
|
||||||
- [ ] `moneyGain(gang, member, task)`
|
- [ ] `moneyGain(gang, member, task)`
|
||||||
- [ ] `respectGain(gang, member, task)`
|
- [ ] `respectGain(gang, member, task)`
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { Multipliers } from "@ns";
|
import { Multipliers } from "@ns";
|
||||||
|
import { PartialRecord } from "./exports";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic Game Constants
|
* Generic Game Constants
|
||||||
|
|
@ -210,3 +211,4 @@ export const MaxFavor = 35331;
|
||||||
// This is the nearest representable value of log(1.02), which is the base of our power.
|
// This is the nearest representable value of log(1.02), which is the base of our power.
|
||||||
// It is *not* the same as Math.log(1.02), since "1.02" lacks sufficient precision.
|
// It is *not* the same as Math.log(1.02), since "1.02" lacks sufficient precision.
|
||||||
export const log1point02 = 0.019802627296179712;
|
export const log1point02 = 0.019802627296179712;
|
||||||
|
export const getRecordEntries = Object.entries as <K extends string, V>(record: PartialRecord<K, V>) => [K, V][];
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import { clampNumber } from "./utils";
|
import { clampNumber } from "@/utils/utils";
|
||||||
|
import { getRecordEntries } from "./constants";
|
||||||
|
|
||||||
export type PartialRecord<K extends string, V> = Partial<Record<K, V>>;
|
export type PartialRecord<K extends string, V> = Partial<Record<K, V>>;
|
||||||
export const getRecordEntries = Object.entries as <K extends string, V>(record: PartialRecord<K, V>) => [K, V][];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bitnode multipliers influence the difficulty of different aspects of the game.
|
* Bitnode multipliers influence the difficulty of different aspects of the game.
|
||||||
* Each Bitnode has a different theme/strategy to achieving the end goal, so these multipliers will can help drive the
|
* Each Bitnode has a different theme/strategy to achieving the end goal, so these multipliers will can help drive the
|
||||||
|
|
@ -1,18 +1,27 @@
|
||||||
import { currentNodeMults } from "./exports";
|
import { currentNodeMults } from "./exports";
|
||||||
|
|
||||||
export interface FormulaGang {
|
export const gang = {
|
||||||
|
ascensionMultiplier: calculateAscensionMult,
|
||||||
|
ascensionPointsGain: calculateAscensionPointsGain,
|
||||||
|
moneyGain: calculateMoneyGain,
|
||||||
|
respectGain: calculateRespectGain,
|
||||||
|
wantedLevelGain: calculateWantedLevelGain,
|
||||||
|
wantedPenalty: calculateWantedPenalty,
|
||||||
|
};
|
||||||
|
|
||||||
|
interface FormulaGang {
|
||||||
respect: number;
|
respect: number;
|
||||||
territory: number;
|
territory: number;
|
||||||
wantedLevel: number;
|
wantedLevel: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITerritory {
|
interface ITerritory {
|
||||||
money: number;
|
money: number;
|
||||||
respect: number;
|
respect: number;
|
||||||
wanted: number;
|
wanted: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITaskParams {
|
interface ITaskParams {
|
||||||
baseRespect?: number;
|
baseRespect?: number;
|
||||||
baseWanted?: number;
|
baseWanted?: number;
|
||||||
baseMoney?: number;
|
baseMoney?: number;
|
||||||
|
|
@ -26,7 +35,7 @@ export interface ITaskParams {
|
||||||
territory?: ITerritory;
|
territory?: ITerritory;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GangMember {
|
class GangMember {
|
||||||
name: string;
|
name: string;
|
||||||
task = "Unassigned";
|
task = "Unassigned";
|
||||||
|
|
||||||
|
|
@ -68,7 +77,7 @@ export class GangMember {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GangMemberTask {
|
class GangMemberTask {
|
||||||
name: string;
|
name: string;
|
||||||
desc: string;
|
desc: string;
|
||||||
|
|
||||||
|
|
@ -132,11 +141,11 @@ export class GangMemberTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateWantedPenalty(gang: FormulaGang): number {
|
function calculateWantedPenalty(gang: FormulaGang): number {
|
||||||
return gang.respect / (gang.respect + gang.wantedLevel);
|
return gang.respect / (gang.respect + gang.wantedLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateRespectGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
|
function calculateRespectGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
|
||||||
if (task.baseRespect === 0) return 0;
|
if (task.baseRespect === 0) return 0;
|
||||||
let statWeight =
|
let statWeight =
|
||||||
(task.hackWeight / 100) * member.hack +
|
(task.hackWeight / 100) * member.hack +
|
||||||
|
|
@ -154,7 +163,7 @@ export function calculateRespectGain(gang: FormulaGang, member: GangMember, task
|
||||||
return Math.pow(11 * task.baseRespect * statWeight * territoryMult * respectMult, territoryPenalty);
|
return Math.pow(11 * task.baseRespect * statWeight * territoryMult * respectMult, territoryPenalty);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateWantedLevelGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
|
function calculateWantedLevelGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
|
||||||
if (task.baseWanted === 0) return 0;
|
if (task.baseWanted === 0) return 0;
|
||||||
let statWeight =
|
let statWeight =
|
||||||
(task.hackWeight / 100) * member.hack +
|
(task.hackWeight / 100) * member.hack +
|
||||||
|
|
@ -177,7 +186,7 @@ export function calculateWantedLevelGain(gang: FormulaGang, member: GangMember,
|
||||||
return Math.min(100, calc);
|
return Math.min(100, calc);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateMoneyGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
|
function calculateMoneyGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
|
||||||
if (task.baseMoney === 0) return 0;
|
if (task.baseMoney === 0) return 0;
|
||||||
let statWeight =
|
let statWeight =
|
||||||
(task.hackWeight / 100) * member.hack +
|
(task.hackWeight / 100) * member.hack +
|
||||||
|
|
@ -196,10 +205,10 @@ export function calculateMoneyGain(gang: FormulaGang, member: GangMember, task:
|
||||||
return Math.pow(5 * task.baseMoney * statWeight * territoryMult * respectMult, territoryPenalty);
|
return Math.pow(5 * task.baseMoney * statWeight * territoryMult * respectMult, territoryPenalty);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateAscensionPointsGain(exp: number): number {
|
function calculateAscensionPointsGain(exp: number): number {
|
||||||
return Math.max(exp - 1000, 0);
|
return Math.max(exp - 1000, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateAscensionMult(points: number): number {
|
function calculateAscensionMult(points: number): number {
|
||||||
return Math.max(Math.pow(points / 2000, 0.5), 1);
|
return Math.max(Math.pow(points / 2000, 0.5), 1);
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,26 @@
|
||||||
|
import { clampNumber, isValidNumber } from "@/utils/utils";
|
||||||
import { Player as IPerson, Server as IServer } from "@ns";
|
import { Player as IPerson, Server as IServer } from "@ns";
|
||||||
import { ServerConstants } from "./constants";
|
import { ServerConstants } from "./constants";
|
||||||
import { currentNodeMults } from "./exports";
|
import { currentNodeMults } from "./exports";
|
||||||
import { Player } from "./player";
|
import { Player } from "./player";
|
||||||
import { clampNumber, isValidNumber } from "./utils";
|
|
||||||
|
|
||||||
export function calculateIntelligenceBonus(intelligence: number, weight = 1): number {
|
export const hacking = {
|
||||||
|
growAmount: calculateGrowMoney,
|
||||||
|
growPercent: calculateServerGrowth,
|
||||||
|
growThreads,
|
||||||
|
growTime: calculateGrowTime,
|
||||||
|
hackChance: calculateHackingChance,
|
||||||
|
hackExp: calculateHackingExpGain,
|
||||||
|
hackPercent: calculatePercentMoneyHacked,
|
||||||
|
hackTime: calculateHackingTime,
|
||||||
|
weakenTime: calculateWeakenTime,
|
||||||
|
numCycleForGrowthCorrected,
|
||||||
|
calculateServerGrowthLog,
|
||||||
|
numCycleForGrowth,
|
||||||
|
getWeakenEffect,
|
||||||
|
};
|
||||||
|
|
||||||
|
function calculateIntelligenceBonus(intelligence: number, weight = 1): number {
|
||||||
const effectiveIntelligence =
|
const effectiveIntelligence =
|
||||||
Player.bitNodeOptions.intelligenceOverride !== undefined
|
Player.bitNodeOptions.intelligenceOverride !== undefined
|
||||||
? Math.min(Player.bitNodeOptions.intelligenceOverride, intelligence)
|
? Math.min(Player.bitNodeOptions.intelligenceOverride, intelligence)
|
||||||
|
|
@ -13,7 +29,7 @@ export function calculateIntelligenceBonus(intelligence: number, weight = 1): nu
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the chance the person has to successfully hack a server */
|
/** Returns the chance the person has to successfully hack a server */
|
||||||
export function calculateHackingChance(server: IServer, person: IPerson): number {
|
function calculateHackingChance(server: IServer, person: IPerson): number {
|
||||||
const hackDifficulty = server.hackDifficulty ?? 100;
|
const hackDifficulty = server.hackDifficulty ?? 100;
|
||||||
const requiredHackingSkill = server.requiredHackingSkill ?? 1e9;
|
const requiredHackingSkill = server.requiredHackingSkill ?? 1e9;
|
||||||
// Unrooted or unhackable server
|
// Unrooted or unhackable server
|
||||||
|
|
@ -34,7 +50,7 @@ export function calculateHackingChance(server: IServer, person: IPerson): number
|
||||||
* Returns the amount of hacking experience the person will gain upon
|
* Returns the amount of hacking experience the person will gain upon
|
||||||
* successfully hacking a server
|
* successfully hacking a server
|
||||||
*/
|
*/
|
||||||
export function calculateHackingExpGain(server: IServer, person: IPerson): number {
|
function calculateHackingExpGain(server: IServer, person: IPerson): number {
|
||||||
const baseDifficulty = server.baseDifficulty;
|
const baseDifficulty = server.baseDifficulty;
|
||||||
if (!baseDifficulty) return 0;
|
if (!baseDifficulty) return 0;
|
||||||
const baseExpGain = 3;
|
const baseExpGain = 3;
|
||||||
|
|
@ -48,7 +64,7 @@ export function calculateHackingExpGain(server: IServer, person: IPerson): numbe
|
||||||
* Returns the percentage of money that will be stolen from a server if
|
* Returns the percentage of money that will be stolen from a server if
|
||||||
* it is successfully hacked (returns the decimal form, not the actual percent value)
|
* it is successfully hacked (returns the decimal form, not the actual percent value)
|
||||||
*/
|
*/
|
||||||
export function calculatePercentMoneyHacked(server: IServer, person: IPerson): number {
|
function calculatePercentMoneyHacked(server: IServer, person: IPerson): number {
|
||||||
const hackDifficulty = server.hackDifficulty ?? 100;
|
const hackDifficulty = server.hackDifficulty ?? 100;
|
||||||
if (hackDifficulty >= 100) return 0;
|
if (hackDifficulty >= 100) return 0;
|
||||||
const requiredHackingSkill = server.requiredHackingSkill ?? 1e9;
|
const requiredHackingSkill = server.requiredHackingSkill ?? 1e9;
|
||||||
|
|
@ -64,7 +80,7 @@ export function calculatePercentMoneyHacked(server: IServer, person: IPerson): n
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns time it takes to complete a hack on a server, in seconds */
|
/** Returns time it takes to complete a hack on a server, in seconds */
|
||||||
export function calculateHackingTime(server: IServer, person: IPerson): number {
|
function calculateHackingTime(server: IServer, person: IPerson): number {
|
||||||
const { hackDifficulty, requiredHackingSkill } = server;
|
const { hackDifficulty, requiredHackingSkill } = server;
|
||||||
if (typeof hackDifficulty !== "number" || typeof requiredHackingSkill !== "number") return Infinity;
|
if (typeof hackDifficulty !== "number" || typeof requiredHackingSkill !== "number") return Infinity;
|
||||||
const difficultyMult = requiredHackingSkill * hackDifficulty;
|
const difficultyMult = requiredHackingSkill * hackDifficulty;
|
||||||
|
|
@ -86,21 +102,21 @@ export function calculateHackingTime(server: IServer, person: IPerson): number {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns time it takes to complete a grow operation on a server, in seconds */
|
/** Returns time it takes to complete a grow operation on a server, in seconds */
|
||||||
export function calculateGrowTime(server: IServer, person: IPerson): number {
|
function calculateGrowTime(server: IServer, person: IPerson): number {
|
||||||
const growTimeMultiplier = 3.2; // Relative to hacking time. 16/5 = 3.2
|
const growTimeMultiplier = 3.2; // Relative to hacking time. 16/5 = 3.2
|
||||||
|
|
||||||
return growTimeMultiplier * calculateHackingTime(server, person);
|
return growTimeMultiplier * calculateHackingTime(server, person);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns time it takes to complete a weaken operation on a server, in seconds */
|
/** Returns time it takes to complete a weaken operation on a server, in seconds */
|
||||||
export function calculateWeakenTime(server: IServer, person: IPerson): number {
|
function calculateWeakenTime(server: IServer, person: IPerson): number {
|
||||||
const weakenTimeMultiplier = 4; // Relative to hacking time
|
const weakenTimeMultiplier = 4; // Relative to hacking time
|
||||||
|
|
||||||
return weakenTimeMultiplier * calculateHackingTime(server, person);
|
return weakenTimeMultiplier * calculateHackingTime(server, person);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the log of the growth rate. When passing 1 for threads, this gives a useful constant.
|
// Returns the log of the growth rate. When passing 1 for threads, this gives a useful constant.
|
||||||
export function calculateServerGrowthLog(server: IServer, threads: number, p: IPerson, cores = 1): number {
|
function calculateServerGrowthLog(server: IServer, threads: number, p: IPerson, cores = 1): number {
|
||||||
if (!server.serverGrowth) return -Infinity;
|
if (!server.serverGrowth) return -Infinity;
|
||||||
const hackDifficulty = server.hackDifficulty ?? 100;
|
const hackDifficulty = server.hackDifficulty ?? 100;
|
||||||
const numServerGrowthCycles = Math.max(threads, 0);
|
const numServerGrowthCycles = Math.max(threads, 0);
|
||||||
|
|
@ -123,14 +139,14 @@ export function calculateServerGrowthLog(server: IServer, threads: number, p: IP
|
||||||
return adjGrowthLog * serverGrowthPercentageAdjusted * p.mults.hacking_grow * coreBonus * numServerGrowthCycles;
|
return adjGrowthLog * serverGrowthPercentageAdjusted * p.mults.hacking_grow * coreBonus * numServerGrowthCycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateServerGrowth(server: IServer, threads: number, p: IPerson, cores = 1): number {
|
function calculateServerGrowth(server: IServer, threads: number, p: IPerson, cores = 1): number {
|
||||||
if (!server.serverGrowth) return 0;
|
if (!server.serverGrowth) return 0;
|
||||||
return Math.exp(calculateServerGrowthLog(server, threads, p, cores));
|
return Math.exp(calculateServerGrowthLog(server, threads, p, cores));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This differs from calculateServerGrowth in that it includes the additive
|
// This differs from calculateServerGrowth in that it includes the additive
|
||||||
// factor and all the boundary checks.
|
// factor and all the boundary checks.
|
||||||
export function calculateGrowMoney(server: IServer, threads: number, p: IPerson, cores = 1): number {
|
function calculateGrowMoney(server: IServer, p: IPerson, threads: number, cores = 1): number {
|
||||||
let serverGrowth = calculateServerGrowth(server, threads, p, cores);
|
let serverGrowth = calculateServerGrowth(server, threads, p, cores);
|
||||||
if (serverGrowth < 1) {
|
if (serverGrowth < 1) {
|
||||||
console.warn("serverGrowth calculated to be less than 1");
|
console.warn("serverGrowth calculated to be less than 1");
|
||||||
|
|
@ -160,27 +176,48 @@ export function calculateGrowMoney(server: IServer, threads: number, p: IPerson,
|
||||||
* @param p - Reference to Player object
|
* @param p - Reference to Player object
|
||||||
* @returns Number of "growth cycles" needed
|
* @returns Number of "growth cycles" needed
|
||||||
*/
|
*/
|
||||||
export function numCycleForGrowth(server: IServer, growth: number, cores = 1): number {
|
function numCycleForGrowth(server: IServer, growth: number, cores = 1): number {
|
||||||
if (!server.serverGrowth) return Infinity;
|
if (!server.serverGrowth) return Infinity;
|
||||||
return Math.log(growth) / calculateServerGrowthLog(server, 1, Player, cores);
|
return Math.log(growth) / calculateServerGrowthLog(server, 1, Player, cores);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper of the function `numCycleForGrowthCorrected`.
|
||||||
|
*
|
||||||
|
* Calculate how many threads it will take to grow server to targetMoney. Starting money is server.moneyAvailable.
|
||||||
|
* Note that when simulating the effect of {@link NS.grow | grow}, what matters is the state of the server and player
|
||||||
|
* when the grow *finishes*, not when it is started.
|
||||||
|
*
|
||||||
|
* The growth amount depends both linearly *and* exponentially on threads; see {@link NS.grow | grow} for more details.
|
||||||
|
*
|
||||||
|
* The inverse of this function is {@link HackingFormulas.growAmount | formulas.hacking.growAmount},
|
||||||
|
* although it can work with fractional threads.
|
||||||
|
* @param server - Server info, typically from {@link NS.getServer | getServer}
|
||||||
|
* @param player - Player info, typically from {@link NS.getPlayer | getPlayer}
|
||||||
|
* @param targetMoney - Desired final money, capped to server's moneyMax
|
||||||
|
* @param cores - Number of cores on the computer that will execute grow.
|
||||||
|
* @returns The calculated grow threads as an integer, rounded up.
|
||||||
|
*/
|
||||||
|
function growThreads(server: IServer, player: IPerson, targetMoney: number, cores = 1): number {
|
||||||
|
return numCycleForGrowthCorrected(server, player, targetMoney, server.moneyAvailable ?? 0, cores);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function calculates the number of threads needed to grow a server from one $amount to a higher $amount
|
* This function calculates the number of threads needed to grow a server from one $amount to a higher $amount
|
||||||
* (ie, how many threads to grow this server from $200 to $600 for example).
|
* (ie, how many threads to grow this server from $200 to $600 for example).
|
||||||
* It protects the inputs (so putting in INFINITY for targetMoney will use moneyMax, putting in a negative for start will use 0, etc.)
|
* It protects the inputs (so putting in INFINITY for targetMoney will use moneyMax, putting in a negative for start will use 0, etc.)
|
||||||
* @param server - Server being grown
|
* @param server - Server being grown
|
||||||
* @param targetMoney - How much you want the server grown TO (not by), for instance, to grow from 200 to 600, input 600
|
* @param targetMoney - How much you want the server grown TO (not by), for instance, to grow from 200 to 600, input 600
|
||||||
* @param startMoney - How much you are growing the server from, for instance, to grow from 200 to 600, input 200
|
* @param startMoney - How much you are growing the server from, for instance, to grow from 200 to 600, input 200. Usually this will just be the server's current money `server.available`, but it is a parameter to allow for more flexible use.
|
||||||
* @param cores - Number of cores on the host performing grow
|
* @param cores - Number of cores on the host performing grow
|
||||||
* @returns Integer threads needed by a single ns.grow call to reach targetMoney from startMoney.
|
* @returns Integer threads needed by a single ns.grow call to reach targetMoney from startMoney.
|
||||||
*/
|
*/
|
||||||
export function numCycleForGrowthCorrected(
|
function numCycleForGrowthCorrected(
|
||||||
server: IServer,
|
server: IServer,
|
||||||
|
person: IPerson = Player,
|
||||||
targetMoney: number,
|
targetMoney: number,
|
||||||
startMoney: number,
|
startMoney: number,
|
||||||
cores = 1,
|
cores = 1,
|
||||||
person: IPerson = Player,
|
|
||||||
): number {
|
): number {
|
||||||
if (!server.serverGrowth) return Infinity;
|
if (!server.serverGrowth) return Infinity;
|
||||||
const moneyMax = server.moneyMax ?? 1;
|
const moneyMax = server.moneyMax ?? 1;
|
||||||
|
|
@ -286,12 +323,12 @@ export function numCycleForGrowthCorrected(
|
||||||
return ccycle + 1;
|
return ccycle + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCoreBonus(cores = 1): number {
|
function getCoreBonus(cores = 1): number {
|
||||||
const coreBonus = 1 + (cores - 1) / 16;
|
const coreBonus = 1 + (cores - 1) / 16;
|
||||||
return coreBonus;
|
return coreBonus;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeakenEffect(threads: number, cores: number): number {
|
function getWeakenEffect(threads: number, cores: number): number {
|
||||||
const coreBonus = getCoreBonus(cores);
|
const coreBonus = getCoreBonus(cores);
|
||||||
return ServerConstants.ServerWeakenAmount * threads * coreBonus * currentNodeMults.ServerWeakenRate;
|
return ServerConstants.ServerWeakenAmount * threads * coreBonus * currentNodeMults.ServerWeakenRate;
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,15 @@
|
||||||
import { currentNodeMults } from "./exports";
|
import { currentNodeMults } from "./exports";
|
||||||
import { HacknetNodeConstants } from "./constants";
|
import { HacknetNodeConstants } from "./constants";
|
||||||
|
|
||||||
export function calculateMoneyGainRate(level: number, ram: number, cores: number, mult: number): number {
|
export const hacknetNodes = {
|
||||||
|
calculateMoneyGainRate,
|
||||||
|
calculateLevelUpgradeCost,
|
||||||
|
calculateRamUpgradeCost,
|
||||||
|
calculateCoreUpgradeCost,
|
||||||
|
calculateNodeCost,
|
||||||
|
};
|
||||||
|
|
||||||
|
function calculateMoneyGainRate(level: number, ram: number, cores: number, mult: number): number {
|
||||||
const gainPerLevel = HacknetNodeConstants.MoneyGainPerLevel;
|
const gainPerLevel = HacknetNodeConstants.MoneyGainPerLevel;
|
||||||
|
|
||||||
const levelMult = level * gainPerLevel;
|
const levelMult = level * gainPerLevel;
|
||||||
|
|
@ -10,7 +18,7 @@ export function calculateMoneyGainRate(level: number, ram: number, cores: number
|
||||||
return levelMult * ramMult * coresMult * mult * currentNodeMults.HacknetNodeMoney;
|
return levelMult * ramMult * coresMult * mult * currentNodeMults.HacknetNodeMoney;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1, costMult = 1): number {
|
function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1, costMult = 1): number {
|
||||||
const sanitizedLevels = Math.round(extraLevels);
|
const sanitizedLevels = Math.round(extraLevels);
|
||||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -31,7 +39,7 @@ export function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1
|
||||||
return HacknetNodeConstants.LevelBaseCost * totalMultiplier * costMult;
|
return HacknetNodeConstants.LevelBaseCost * totalMultiplier * costMult;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, costMult = 1): number {
|
function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, costMult = 1): number {
|
||||||
const sanitizedLevels = Math.round(extraLevels);
|
const sanitizedLevels = Math.round(extraLevels);
|
||||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -60,7 +68,7 @@ export function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, co
|
||||||
return totalCost;
|
return totalCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1, costMult = 1): number {
|
function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1, costMult = 1): number {
|
||||||
const sanitizedCores = Math.round(extraLevels);
|
const sanitizedCores = Math.round(extraLevels);
|
||||||
if (isNaN(sanitizedCores) || sanitizedCores < 1) {
|
if (isNaN(sanitizedCores) || sanitizedCores < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -84,7 +92,7 @@ export function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1,
|
||||||
return totalCost;
|
return totalCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateNodeCost(n: number, mult = 1): number {
|
function calculateNodeCost(n: number, mult = 1): number {
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
import { currentNodeMults } from "./exports";
|
import { currentNodeMults } from "./exports";
|
||||||
import { HacknetServerConstants } from "./constants";
|
import { HacknetServerConstants } from "./constants";
|
||||||
|
|
||||||
export function calculateHashGainRate(
|
export const hacknetServers = {
|
||||||
level: number,
|
calculateHashGainRate,
|
||||||
ramUsed: number,
|
calculateLevelUpgradeCost,
|
||||||
maxRam: number,
|
calculateRamUpgradeCost,
|
||||||
cores: number,
|
calculateCoreUpgradeCost,
|
||||||
mult: number,
|
calculateCacheUpgradeCost,
|
||||||
): number {
|
calculateServerCost,
|
||||||
|
};
|
||||||
|
|
||||||
|
function calculateHashGainRate(level: number, ramUsed: number, maxRam: number, cores: number, mult: number): number {
|
||||||
const baseGain = HacknetServerConstants.HashesPerLevel * level;
|
const baseGain = HacknetServerConstants.HashesPerLevel * level;
|
||||||
const ramMultiplier = Math.pow(1.07, Math.log2(maxRam));
|
const ramMultiplier = Math.pow(1.07, Math.log2(maxRam));
|
||||||
const coreMultiplier = 1 + (cores - 1) / 5;
|
const coreMultiplier = 1 + (cores - 1) / 5;
|
||||||
|
|
@ -16,7 +19,7 @@ export function calculateHashGainRate(
|
||||||
return baseGain * ramMultiplier * coreMultiplier * ramRatio * mult * currentNodeMults.HacknetNodeMoney;
|
return baseGain * ramMultiplier * coreMultiplier * ramRatio * mult * currentNodeMults.HacknetNodeMoney;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1, costMult = 1): number {
|
function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1, costMult = 1): number {
|
||||||
const sanitizedLevels = Math.round(extraLevels);
|
const sanitizedLevels = Math.round(extraLevels);
|
||||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -37,7 +40,7 @@ export function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1
|
||||||
return 10 * HacknetServerConstants.BaseCost * totalMultiplier * costMult;
|
return 10 * HacknetServerConstants.BaseCost * totalMultiplier * costMult;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, costMult = 1): number {
|
function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, costMult = 1): number {
|
||||||
const sanitizedLevels = Math.round(extraLevels);
|
const sanitizedLevels = Math.round(extraLevels);
|
||||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -64,7 +67,7 @@ export function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, co
|
||||||
return totalCost;
|
return totalCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1, costMult = 1): number {
|
function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1, costMult = 1): number {
|
||||||
const sanitizedLevels = Math.round(extraLevels);
|
const sanitizedLevels = Math.round(extraLevels);
|
||||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -87,7 +90,7 @@ export function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1,
|
||||||
return totalCost;
|
return totalCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateCacheUpgradeCost(startingCache: number, extraLevels = 1): number {
|
function calculateCacheUpgradeCost(startingCache: number, extraLevels = 1): number {
|
||||||
const sanitizedLevels = Math.round(extraLevels);
|
const sanitizedLevels = Math.round(extraLevels);
|
||||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -111,7 +114,7 @@ export function calculateCacheUpgradeCost(startingCache: number, extraLevels = 1
|
||||||
|
|
||||||
// TODO: reverse engineer hashUpgradeCost
|
// TODO: reverse engineer hashUpgradeCost
|
||||||
|
|
||||||
export function calculateServerCost(n: number, mult = 1): number {
|
function calculateServerCost(n: number, mult = 1): number {
|
||||||
if (n - 1 >= HacknetServerConstants.MaxServers) {
|
if (n - 1 >= HacknetServerConstants.MaxServers) {
|
||||||
return Infinity;
|
return Infinity;
|
||||||
}
|
}
|
||||||
|
|
@ -1,35 +1,45 @@
|
||||||
import { Person as IPerson } from "@ns";
|
import { Person as IPerson } from "@ns";
|
||||||
import { currentNodeMults } from "./exports";
|
import { currentNodeMults } from "./exports";
|
||||||
import { clampNumber } from "./utils";
|
|
||||||
import { CONSTANTS, log1point02, MaxFavor } from "./constants";
|
import { CONSTANTS, log1point02, MaxFavor } from "./constants";
|
||||||
import { Player } from "./player";
|
import { Player } from "./player";
|
||||||
|
import { clampNumber } from "@/utils/utils";
|
||||||
|
|
||||||
export function favorToRep(f: number): number {
|
export const reputation = {
|
||||||
|
favorToRep,
|
||||||
|
repToFavor,
|
||||||
|
calculateFavorAfterResetting,
|
||||||
|
repFromDonation,
|
||||||
|
donationForRep,
|
||||||
|
repNeededToDonate,
|
||||||
|
canDonate,
|
||||||
|
};
|
||||||
|
|
||||||
|
function favorToRep(f: number): number {
|
||||||
// expm1 is e^x - 1, which is more accurate for small x than doing it the obvious way.
|
// expm1 is e^x - 1, which is more accurate for small x than doing it the obvious way.
|
||||||
return clampNumber(25000 * Math.expm1(log1point02 * f), 0);
|
return clampNumber(25000 * Math.expm1(log1point02 * f), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function repToFavor(r: number): number {
|
function repToFavor(r: number): number {
|
||||||
// log1p is log(x + 1), which is more accurate for small x than doing it the obvious way.
|
// log1p is log(x + 1), which is more accurate for small x than doing it the obvious way.
|
||||||
return clampNumber(Math.log1p(r / 25000) / log1point02, 0, MaxFavor);
|
return clampNumber(Math.log1p(r / 25000) / log1point02, 0, MaxFavor);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateFavorAfterResetting(favor: number, playerReputation: number) {
|
function calculateFavorAfterResetting(favor: number, playerReputation: number) {
|
||||||
return repToFavor(favorToRep(favor) + playerReputation);
|
return repToFavor(favorToRep(favor) + playerReputation);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function repFromDonation(amt: number, person: IPerson): number {
|
function repFromDonation(amt: number, person: IPerson): number {
|
||||||
return (amt / CONSTANTS.DonateMoneyToRepDivisor) * person.mults.faction_rep * currentNodeMults.FactionWorkRepGain;
|
return (amt / CONSTANTS.DonateMoneyToRepDivisor) * person.mults.faction_rep * currentNodeMults.FactionWorkRepGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function donationForRep(rep: number, person: IPerson): number {
|
function donationForRep(rep: number, person: IPerson): number {
|
||||||
return (rep * CONSTANTS.DonateMoneyToRepDivisor) / person.mults.faction_rep / currentNodeMults.FactionWorkRepGain;
|
return (rep * CONSTANTS.DonateMoneyToRepDivisor) / person.mults.faction_rep / currentNodeMults.FactionWorkRepGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function repNeededToDonate(): number {
|
function repNeededToDonate(): number {
|
||||||
return Math.floor(CONSTANTS.BaseFavorToDonate * currentNodeMults.RepToDonateToFaction);
|
return Math.floor(CONSTANTS.BaseFavorToDonate * currentNodeMults.RepToDonateToFaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canDonate(amt: number): boolean {
|
function canDonate(amt: number): boolean {
|
||||||
return !isNaN(amt) && amt > 0 && Player.money >= amt;
|
return !isNaN(amt) && amt > 0 && Player.money >= amt;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,11 @@
|
||||||
import { clampNumber } from "./utils";
|
import { clampNumber } from "@/utils/utils";
|
||||||
|
|
||||||
|
export const skills = {
|
||||||
|
calculateSkill,
|
||||||
|
calculateExp,
|
||||||
|
calculateSkillProgress,
|
||||||
|
getEmptySkillProgress,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an experience amount and stat multiplier, calculates the
|
* Given an experience amount and stat multiplier, calculates the
|
||||||
|
|
@ -14,7 +21,7 @@ export function calculateSkill(exp: number, mult = 1): number {
|
||||||
return clampNumber(value, 1);
|
return clampNumber(value, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateExp(skill: number, mult = 1): number {
|
function calculateExp(skill: number, mult = 1): number {
|
||||||
const floorSkill = Math.floor(skill);
|
const floorSkill = Math.floor(skill);
|
||||||
let value = Math.exp((skill / mult + 200) / 32) - 534.6;
|
let value = Math.exp((skill / mult + 200) / 32) - 534.6;
|
||||||
if (skill === floorSkill && Number.isFinite(skill) && Number.isFinite(value)) {
|
if (skill === floorSkill && Number.isFinite(skill) && Number.isFinite(value)) {
|
||||||
|
|
@ -33,7 +40,7 @@ export function calculateExp(skill: number, mult = 1): number {
|
||||||
return clampNumber(value, 0);
|
return clampNumber(value, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateSkillProgress(exp: number, mult = 1): ISkillProgress {
|
function calculateSkillProgress(exp: number, mult = 1): ISkillProgress {
|
||||||
const currentSkill = calculateSkill(exp, mult);
|
const currentSkill = calculateSkill(exp, mult);
|
||||||
const nextSkill = currentSkill + 1;
|
const nextSkill = currentSkill + 1;
|
||||||
|
|
||||||
|
|
@ -60,7 +67,7 @@ export function calculateSkillProgress(exp: number, mult = 1): ISkillProgress {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISkillProgress {
|
interface ISkillProgress {
|
||||||
currentSkill: number;
|
currentSkill: number;
|
||||||
nextSkill: number;
|
nextSkill: number;
|
||||||
baseExperience: number;
|
baseExperience: number;
|
||||||
|
|
@ -71,7 +78,7 @@ export interface ISkillProgress {
|
||||||
progress: number;
|
progress: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getEmptySkillProgress(): ISkillProgress {
|
function getEmptySkillProgress(): ISkillProgress {
|
||||||
return {
|
return {
|
||||||
currentSkill: 0,
|
currentSkill: 0,
|
||||||
nextSkill: 0,
|
nextSkill: 0,
|
||||||
12
src/test.ts
12
src/test.ts
|
|
@ -1,9 +1,11 @@
|
||||||
import { NS } from "@ns";
|
import { NS } from "@ns";
|
||||||
import { scan } from "./utils/scan";
|
import { ezgame } from "./ezgame";
|
||||||
import { startall } from "./utils/startall";
|
|
||||||
import { kill } from "./utils/kill";
|
|
||||||
|
|
||||||
export const main = (ns: NS) => {
|
export const main = (ns: NS) => {
|
||||||
ns.tprint(ns.getPurchasedServerCost(256));
|
const server = ns.getServer("n00dles");
|
||||||
console.log(ns.getPlayer());
|
const player = ns.getPlayer();
|
||||||
|
const testResult = ezgame.formulas.hacking.growTime(server, player);
|
||||||
|
const actualResult = ns.formulas.hacking.growTime(server, player);
|
||||||
|
console.log(testResult);
|
||||||
|
console.log(actualResult);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
// format the date/time
|
/**
|
||||||
// if the date is today, show the time
|
* Format the date/time.
|
||||||
|
* If the date is today, show the time. Otherwise, show the date in "day month year" format.
|
||||||
|
* @param dateString The date string to format
|
||||||
|
* @returns Formatted date/time string
|
||||||
|
*/
|
||||||
export const utilityFormatDate = (dateString: string): string => {
|
export const utilityFormatDate = (dateString: string): string => {
|
||||||
const date = new Date(dateString);
|
const date = new Date(dateString);
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
|
|
@ -20,7 +24,11 @@ export const utilityFormatDate = (dateString: string): string => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// format the file sizes
|
/**
|
||||||
|
* Format bytes into human-readable size
|
||||||
|
* @param bytes Number of bytes to format
|
||||||
|
* @returns Formatted size string
|
||||||
|
*/
|
||||||
export const utilityFormatSize = (bytes: number): string => {
|
export const utilityFormatSize = (bytes: number): string => {
|
||||||
if (bytes === 0) return "0 Bytes";
|
if (bytes === 0) return "0 Bytes";
|
||||||
|
|
||||||
|
|
@ -32,7 +40,11 @@ export const utilityFormatSize = (bytes: number): string => {
|
||||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
||||||
};
|
};
|
||||||
|
|
||||||
// UNformat the file sizes
|
/**
|
||||||
|
* Convert a formatted size string back to bytes
|
||||||
|
* @param formattedSize Formatted size string (must be in the same format produced by `utilityFormatSize()`)
|
||||||
|
* @returns Number of bytes
|
||||||
|
*/
|
||||||
export const utilityUnformatSize = (formattedSize: string): number => {
|
export const utilityUnformatSize = (formattedSize: string): number => {
|
||||||
const sizes = ["Bytes", "KB", "MB", "GB"];
|
const sizes = ["Bytes", "KB", "MB", "GB"];
|
||||||
const [value, unit] = formattedSize.split(" ");
|
const [value, unit] = formattedSize.split(" ");
|
||||||
|
|
@ -40,9 +52,12 @@ export const utilityUnformatSize = (formattedSize: string): number => {
|
||||||
return parseFloat(value) * Math.pow(1024, index);
|
return parseFloat(value) * Math.pow(1024, index);
|
||||||
};
|
};
|
||||||
|
|
||||||
// extract filename and extension from a path
|
/**
|
||||||
// heeheeheehaw safe coding my boys 🤠
|
* Extract filename stem and extension from a file path
|
||||||
// only consider things after the last period
|
* @param filePath The file path to parse
|
||||||
|
* @returns Object containing `fileStem` and `fileExtension`. `fileStem` is the filename without the extension, and `fileExtension` is the extension in lowercase (or an empty string if there is no extension).
|
||||||
|
* @throws Error if the file path is invalid
|
||||||
|
*/
|
||||||
export const utilityExtractFilename = (filePath: string): { fileStem: string; fileExtension: string } | null => {
|
export const utilityExtractFilename = (filePath: string): { fileStem: string; fileExtension: string } | null => {
|
||||||
const lastSlashIndex = filePath.lastIndexOf("/");
|
const lastSlashIndex = filePath.lastIndexOf("/");
|
||||||
const lastDotIndex = filePath.lastIndexOf(".");
|
const lastDotIndex = filePath.lastIndexOf(".");
|
||||||
|
|
@ -74,11 +89,11 @@ export const utilityExtractFilename = (filePath: string): { fileStem: string; fi
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clamps the value on a lower and an upper bound
|
* Clamps a value to a lower and upper bound
|
||||||
* @param {number} value Value to clamp
|
* @param value Value to clamp
|
||||||
* @param {number} min Lower bound, defaults to negative Number.MAX_VALUE
|
* @param min Lower bound, defaults to negative `Number.MAX_VALUE`
|
||||||
* @param {number} max Upper bound, defaults to Number.MAX_VALUE
|
* @param max Upper bound, defaults to `Number.MAX_VALUE`
|
||||||
* @returns {number} Clamped value
|
* @returns Clamped value
|
||||||
*/
|
*/
|
||||||
export function clampNumber(value: number, min: number = -Number.MAX_VALUE, max: number = Number.MAX_VALUE): number {
|
export function clampNumber(value: number, min: number = -Number.MAX_VALUE, max: number = Number.MAX_VALUE): number {
|
||||||
if (isNaN(value)) {
|
if (isNaN(value)) {
|
||||||
|
|
@ -89,11 +104,11 @@ export function clampNumber(value: number, min: number = -Number.MAX_VALUE, max:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clamps the value to an integer within a lower and an upper bound
|
* Clamps a value to an integer within a lower and upper bound
|
||||||
* @param {number} value Value to clamp
|
* @param value Value to clamp
|
||||||
* @param {number} min Lower bound, defaults to negative Number.MAX_SAFE_INTEGER
|
* @param min Lower bound, defaults to negative `Number.MAX_SAFE_INTEGER`
|
||||||
* @param {number} max Upper bound, defaults to Number.MAX_SAFE_INTEGER
|
* @param max Upper bound, defaults to `Number.MAX_SAFE_INTEGER`
|
||||||
* @returns {number} Clamped integer value
|
* @returns Clamped integer value
|
||||||
*/
|
*/
|
||||||
export function clampInteger(
|
export function clampInteger(
|
||||||
value: number,
|
value: number,
|
||||||
|
|
@ -108,11 +123,32 @@ export function clampInteger(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that a variable is a valid number. A valid number
|
* Checks that a variable is a valid number
|
||||||
* must be a "number" type and cannot be NaN
|
* A valid number must be of type "number" and cannot be NaN
|
||||||
* @param {number} n The number to check
|
* @param n The number to check
|
||||||
* @returns {boolean} True if n is a valid number, false otherwise
|
* @returns True if n is a valid number, false otherwise
|
||||||
*/
|
*/
|
||||||
export function isValidNumber(n: number): boolean {
|
export function isValidNumber(n: number): boolean {
|
||||||
return typeof n === "number" && !isNaN(n);
|
return typeof n === "number" && !isNaN(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a random number between min and max (inclusive)
|
||||||
|
* @param min Minimum value (inclusive)
|
||||||
|
* @param max Maximum value (inclusive)
|
||||||
|
* @returns Random number between min and max
|
||||||
|
*/
|
||||||
|
export function randomNumber(min: number, max: number): number {
|
||||||
|
if (min > max) throw new Error("min cannot be greater than max");
|
||||||
|
return Math.random() * (max - min) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a random integer between min and max (inclusive)
|
||||||
|
* @param min Minimum value (inclusive)
|
||||||
|
* @param max Maximum value (inclusive)
|
||||||
|
* @returns Random integer between min and max
|
||||||
|
*/
|
||||||
|
export function randomInteger(min: number, max: number): number {
|
||||||
|
return Math.floor(randomNumber(min, max + 1));
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue