init 3
This commit is contained in:
parent
d24d3a63c8
commit
374196acce
@ -5,6 +5,7 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "node build.js",
|
||||
"check": "tsc --noEmit",
|
||||
"defs": "node ./updateDefs.js"
|
||||
},
|
||||
"repository": {
|
||||
|
49
src/batch-cal.ts
Normal file
49
src/batch-cal.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { NS, AutocompleteData } from '@ns'
|
||||
import { parse } from './lib/flag';
|
||||
import { sprintf } from './lib/printf';
|
||||
import {calculateBatchResource} from './lib/batchbase';
|
||||
|
||||
// eslint-disable-next-line require-await
|
||||
export async function main(ns: NS) : Promise<void> {
|
||||
const flag = parse(ns.args.map(x=>x.toString()));
|
||||
if(flag.h || flag.help){
|
||||
const msg = ['run cmd [startThread] [--hostname || -h] [--graph]']
|
||||
msg.forEach(x=>ns.tprint(x));
|
||||
return;
|
||||
}
|
||||
if(flag._.length === 0){
|
||||
ns.tprint("Error. Require Argument");
|
||||
return;
|
||||
}
|
||||
if(!(flag.host)){
|
||||
ns.tprint("host required");
|
||||
return;
|
||||
}
|
||||
const v = parseInt(flag._[0].toString());
|
||||
const hostname = flag.host ?? flag.t;
|
||||
const server = ns.getServer(hostname)
|
||||
if(flag.graph){
|
||||
const col = [];
|
||||
for (let i = 1; i < v; i++) {
|
||||
const info = calculateBatchResource(ns,hostname,i,server.moneyMax,1);
|
||||
col.push({
|
||||
costEffect :(info.earnMoneyPerSec / info.totalThreadCount),
|
||||
index: i,
|
||||
total: info.totalThreadCount
|
||||
})
|
||||
}
|
||||
col.forEach(({costEffect,index,total})=>{
|
||||
ns.tprint(sprintf("%3d %10.2f %4d",index,costEffect,total));
|
||||
})
|
||||
ns.tprint(col.map(x=>x.costEffect))
|
||||
return;
|
||||
}
|
||||
const info = calculateBatchResource(ns,hostname,v,server.moneyMax,1);
|
||||
ns.tprint(JSON.stringify(info,undefined,2));
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export function autocomplete(data : AutocompleteData, args : string[]) : string[] {
|
||||
return [...data.servers]
|
||||
}
|
45
src/deploy-share.ts
Normal file
45
src/deploy-share.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { AutocompleteData, NS } from "@ns";
|
||||
import {parse} from "./lib/flag";
|
||||
import { installBatchFilePack, isBatchFilePackInstalled, scpBatchFilePack, execWeakenLoop, getRamOfScript } from './lib/batchbase';
|
||||
|
||||
/** @param {NS} ns */
|
||||
export async function main(ns: NS): Promise<void> {
|
||||
const flag = parse(ns.args.map(String));
|
||||
if(flag._.length < 1){
|
||||
ns.tprint("argument required");
|
||||
ns.tprint("run cmd [src(hostname)]");
|
||||
ns.exit();
|
||||
}
|
||||
const hostname = String(flag._[0]);
|
||||
|
||||
const th = flag.thread || false;
|
||||
|
||||
ns.scp("share-server.js",hostname);
|
||||
|
||||
let nThread;
|
||||
if(th){
|
||||
nThread = th;
|
||||
}
|
||||
else {
|
||||
nThread = calculateMaximumThread(ns, hostname, getRamOfScript(ns,"weakenLoop"));
|
||||
}
|
||||
const pid = ns.exec("share-server.js",hostname, nThread);
|
||||
ns.tprint(pid," Process started.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {NS} ns
|
||||
* @param {string} dst
|
||||
* @param {number} amount the program ram
|
||||
*/
|
||||
export function calculateMaximumThread(ns:NS,host:string,amount:number):number{
|
||||
const maxRam = ns.getServerMaxRam(host);
|
||||
const usedRam = ns.getServerUsedRam(host);
|
||||
const restRam = maxRam - usedRam;
|
||||
return Math.floor(restRam / amount);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export function autocomplete(data: AutocompleteData,args: string[]): string[]{
|
||||
return [...data.servers];
|
||||
}
|
57
src/deploy-weaken.ts
Normal file
57
src/deploy-weaken.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { AutocompleteData, NS } from "@ns";
|
||||
import {parse} from "./lib/flag";
|
||||
import { installBatchFilePack, isBatchFilePackInstalled, scpBatchFilePack, execWeakenLoop, getRamOfScript } from './lib/batchbase';
|
||||
|
||||
/** @param {NS} ns */
|
||||
export async function main(ns: NS): Promise<void> {
|
||||
const flag = parse(ns.args.map(String));
|
||||
if(flag._.length < 2){
|
||||
ns.tprint("argument required");
|
||||
ns.tprint("run cmd [src(hostname)] [dest(hostname)]");
|
||||
ns.exit();
|
||||
}
|
||||
const src = String(flag._[0]);
|
||||
const dest = String(flag._[1]);
|
||||
|
||||
const th = flag.thread || false;
|
||||
|
||||
if(!isBatchFilePackInstalled(ns)){
|
||||
await installBatchFilePack(ns);
|
||||
}
|
||||
|
||||
await scpBatchFilePack(ns,src);
|
||||
|
||||
const stock = flag.stock ?? false;
|
||||
|
||||
let nThread;
|
||||
if(th){
|
||||
nThread = th;
|
||||
}
|
||||
else {
|
||||
nThread = calculateMaximumThread(ns, src, getRamOfScript(ns,"weakenLoop"));
|
||||
}
|
||||
const pid = execWeakenLoop(ns,{
|
||||
hostname: src,
|
||||
target: dest,
|
||||
numThread: nThread,
|
||||
stock: stock,
|
||||
});
|
||||
ns.tprint(pid," Process started.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {NS} ns
|
||||
* @param {string} dst
|
||||
* @param {number} amount the program ram
|
||||
*/
|
||||
export function calculateMaximumThread(ns:NS,host:string,amount:number):number{
|
||||
const maxRam = ns.getServerMaxRam(host);
|
||||
const usedRam = ns.getServerUsedRam(host);
|
||||
const restRam = maxRam - usedRam;
|
||||
return Math.floor(restRam / amount);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export function autocomplete(data: AutocompleteData,args: string[]): string[]{
|
||||
return [...data.servers];
|
||||
}
|
@ -2,16 +2,17 @@ import { NS } from '@ns'
|
||||
|
||||
export async function main(ns : NS) : Promise<void> {
|
||||
const stat: number[] = [];
|
||||
const M = 10;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const start = performance.now();
|
||||
await ns.sleep(0);
|
||||
await ns.sleep(M);
|
||||
const end = performance.now();
|
||||
stat.push(end- start);
|
||||
}
|
||||
const avg = stat.reduce((x,y)=>x+y)/stat.length;
|
||||
const max = Math.max(...stat);
|
||||
const min = Math.min(...stat);
|
||||
ns.tprint(`avg : ${avg}`);
|
||||
ns.tprint(`max : ${max}`);
|
||||
ns.tprint(`min : ${min}`);
|
||||
ns.tprint(`avg : ${avg - M}`);
|
||||
ns.tprint(`max : ${max - M}`);
|
||||
ns.tprint(`min : ${min - M}`);
|
||||
}
|
@ -1,11 +1,17 @@
|
||||
import { NS } from "@ns"
|
||||
import { NS, Server } from "@ns"
|
||||
import { calculateServerGrowth, FormulaHelper } from "./formula";
|
||||
|
||||
type FilePackEntry = {
|
||||
|
||||
export type BatchType = "hack" | "grow" | "weaken" | "weakenLoop";
|
||||
|
||||
type BatchFilePackEntry = {
|
||||
type: BatchType;
|
||||
path: string;
|
||||
content: string;
|
||||
ram: number;
|
||||
};
|
||||
|
||||
type FilePack = FilePackEntry[];
|
||||
type FilePack = BatchFilePackEntry[];
|
||||
|
||||
const createScriptContent: (f: string) => string = (funcName: string) => `export async function main(ns) {
|
||||
if(ns.args.length < 3){
|
||||
@ -17,13 +23,15 @@ const createScriptContent: (f: string) => string = (funcName: string) => `export
|
||||
const sleepDuration = parseInt(ns.args[0]);
|
||||
const hostname = ns.args[1].toString();
|
||||
const stock = ns.args[2] == "true";
|
||||
await ns.sleep(sleepDuration);
|
||||
if(sleepDuration > 0){
|
||||
await ns.sleep(sleepDuration);
|
||||
}
|
||||
await ns.${funcName}(hostname,{
|
||||
stock,
|
||||
});
|
||||
}`
|
||||
|
||||
async function unpackFileEntry(ns: NS, filePack: FilePackEntry): Promise<void> {
|
||||
async function unpackFileEntry(ns: NS, filePack: BatchFilePackEntry): Promise<void> {
|
||||
await ns.write(filePack.path, filePack.content, "w");
|
||||
}
|
||||
|
||||
@ -35,23 +43,50 @@ export async function unpackFilePack(ns: NS, pack: FilePack): Promise<void> {
|
||||
|
||||
export const batchFilePack: FilePack = [
|
||||
{
|
||||
type: "hack",
|
||||
path: "/tmp/hack.js",
|
||||
content: createScriptContent("hack")
|
||||
content: createScriptContent("hack"),
|
||||
ram:1.7,
|
||||
},
|
||||
{
|
||||
type: "weaken",
|
||||
path: "/tmp/weaken.js",
|
||||
content: createScriptContent("weaken")
|
||||
content: createScriptContent("weaken"),
|
||||
ram: 1.75,
|
||||
},
|
||||
{
|
||||
type: "grow",
|
||||
path: "/tmp/grow.js",
|
||||
content: createScriptContent("grow")
|
||||
content: createScriptContent("grow"),
|
||||
ram: 1.75,
|
||||
},
|
||||
{
|
||||
type:"weakenLoop",
|
||||
path: "/tmp/weakenLoop.js",
|
||||
ram: 1.75,
|
||||
content: `export async function main(ns) {
|
||||
if(ns.args.length < 3){
|
||||
ns.print("[ERROR] args required");
|
||||
ns.print("run cmd [sleepDuration] [hostname] [effectStock]")
|
||||
ns.exit();
|
||||
return;
|
||||
}
|
||||
const sleepDuration = parseInt(ns.args[0]);
|
||||
const hostname = ns.args[1].toString();
|
||||
const stock = ns.args[2] == "true";
|
||||
for(;;){
|
||||
await ns.weaken(hostname,{
|
||||
stock,
|
||||
});
|
||||
}
|
||||
}`,
|
||||
}
|
||||
]
|
||||
|
||||
export async function scpBatchFilePack(ns: NS,hostname :string): Promise<void> {
|
||||
const list = batchFilePack.map(entry=>entry.path);
|
||||
export async function scpBatchFilePack(ns: NS, hostname: string): Promise<void> {
|
||||
const list = batchFilePack.map(entry => entry.path);
|
||||
await installBatchFilePack(ns);
|
||||
await ns.scp(list,hostname);
|
||||
await ns.scp(list, hostname);
|
||||
}
|
||||
|
||||
export async function installBatchFilePack(ns: NS): Promise<void> {
|
||||
@ -62,8 +97,8 @@ export function isBatchFilePackInstalled(ns: NS, hostname?: string): boolean {
|
||||
return batchFilePack.every(entry => ns.fileExists(entry.path, hostname))
|
||||
}
|
||||
|
||||
export interface ExecOption{
|
||||
hostname: string;
|
||||
export interface ExecOption {
|
||||
hostname: string;
|
||||
/**
|
||||
* @default 1
|
||||
*/
|
||||
@ -75,21 +110,191 @@ export interface ExecOption{
|
||||
/**
|
||||
* target hostname to operate "hack", "weaken" or "grow"
|
||||
*/
|
||||
target: number;
|
||||
target: string;
|
||||
stock?: boolean;
|
||||
}
|
||||
|
||||
function execBatchfile(ns: NS, path: string, option:ExecOption): number {
|
||||
function execBatchfile(ns: NS, path: string, option: ExecOption): number {
|
||||
return ns.exec(path, option.hostname, option.numThread,
|
||||
option.sleepDuration ?? 0, option.target, option.stock ?? false);
|
||||
}
|
||||
|
||||
export function execHack(ns: NS,option: ExecOption): number{
|
||||
return execBatchfile(ns,"/tmp/hack.js",option);
|
||||
export function execHack(ns: NS, option: ExecOption): number {
|
||||
return execBatchfile(ns, "/tmp/hack.js", option);
|
||||
}
|
||||
export function execGrow(ns: NS,option: ExecOption): number{
|
||||
return execBatchfile(ns,"/tmp/grow.js",option);
|
||||
export function execGrow(ns: NS, option: ExecOption): number {
|
||||
return execBatchfile(ns, "/tmp/grow.js", option);
|
||||
}
|
||||
export function execWeaken(ns: NS,option: ExecOption): number{
|
||||
return execBatchfile(ns,"/tmp/weaken.js",option);
|
||||
}
|
||||
export function execWeaken(ns: NS, option: ExecOption): number {
|
||||
return execBatchfile(ns, "/tmp/weaken.js", option);
|
||||
}
|
||||
export function execWeakenLoop(ns: NS, option: ExecOption): number {
|
||||
return execBatchfile(ns, "/tmp/weakenLoop.js", option);
|
||||
}
|
||||
export function getRamOfScript(ns: NS, type: BatchType): number{
|
||||
return batchFilePack.filter(x=>x.type == type)[0].ram;
|
||||
}
|
||||
|
||||
//type BatchType = "hack" | "grow" | "weaken";
|
||||
//
|
||||
//type Batch = {
|
||||
// type: BatchType;
|
||||
// options: ExecOption;
|
||||
//}
|
||||
type ReserveRequest = {
|
||||
hostname: string;
|
||||
usableRam: number;
|
||||
}
|
||||
|
||||
function getKeyOfHWGWBatchManager(hostname: string): string{
|
||||
return `HWGW-${hostname}`;
|
||||
}
|
||||
interface HWGW {
|
||||
HThreadCount: number;
|
||||
HWThreadCount: number;
|
||||
GThreadCount: number;
|
||||
GWThreadCount: number;
|
||||
}
|
||||
|
||||
type WorkReserved = {
|
||||
allocated:false;
|
||||
} | {
|
||||
allocated:true;
|
||||
hwgw: HWGW;
|
||||
};
|
||||
|
||||
type Resource = {
|
||||
hostname: string;
|
||||
usableRam: string;
|
||||
};
|
||||
|
||||
class HWGWBatchManager {
|
||||
willExecuted: WorkReserved[];
|
||||
server: Server;
|
||||
ns: NS;
|
||||
createdAt: number;
|
||||
|
||||
|
||||
constructor(ns: NS, hostname: string) {
|
||||
this.ns = ns;
|
||||
this.willExecuted = [];
|
||||
this.server = ns.getServer(hostname);
|
||||
this.createdAt = ns.getTimeSinceLastAug();
|
||||
|
||||
this.growArray();
|
||||
}
|
||||
private popRequest(): ReserveRequest[]{
|
||||
const key = getKeyOfHWGWBatchManager(this.server.hostname);
|
||||
const text = localStorage.getItem(key)
|
||||
if(text === null){
|
||||
return [];
|
||||
}
|
||||
localStorage.setItem(key,"");
|
||||
return JSON.parse(text) as ReserveRequest[];
|
||||
}
|
||||
private growArray(n: number): void {
|
||||
while (this.willExecuted.length <= n) {
|
||||
this.willExecuted.push({
|
||||
allocated:false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
reserveBatch(time: number): void {
|
||||
const milli = time - this.ns.getTimeSinceLastAug();
|
||||
const sec = Math.floor(milli / 1000);
|
||||
this.growArray(sec);
|
||||
this.willExecuted[sec] = true;
|
||||
}
|
||||
async tick(): Promise<void> {
|
||||
const data = this.willExecuted.shift();
|
||||
await this.sleepCorrect();
|
||||
}
|
||||
/**
|
||||
* exact time Sleep
|
||||
*/
|
||||
async sleepCorrect(): Promise<void> {
|
||||
const cur = this.ns.getTimeSinceLastAug();
|
||||
const sliceTime = 250;
|
||||
const delta = (cur - this.createdAt + sliceTime/2) % sliceTime - sliceTime/2;
|
||||
await this.ns.sleep(sliceTime - delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface HackCalculation extends HWGW {
|
||||
earnMoneyPerSec: number;
|
||||
earnExpPerSec: number;
|
||||
/**
|
||||
* cycle time in seconds.
|
||||
*/
|
||||
cycleTime: number;
|
||||
totalThreadCount: number;
|
||||
}
|
||||
|
||||
export function calculateBatchResource(ns: NS, hostname: string, hackThread: number, startMoney?: number, cores = 1): HackCalculation {
|
||||
const helper = new FormulaHelper(ns);
|
||||
const server = ns.getServer(hostname);
|
||||
startMoney ??= server.moneyMax;
|
||||
server.hackDifficulty = server.minDifficulty;
|
||||
|
||||
const percentMoneyHacked = helper.calculatePercentMoneyHacked(server);
|
||||
const hackingChance = helper.calculateHackingChance(server);
|
||||
const earnMoneyPerCycle = hackThread * percentMoneyHacked * startMoney * hackingChance;
|
||||
const earnExpPerCycle = helper.calculateHackingExpGain(server) * hackThread * hackingChance;
|
||||
const cycleTime = 1 + helper.calculateWeakenTime(server);
|
||||
|
||||
const increasedSecurityAfterHack = helper.calculateHackSecurity(hackThread) + server.minDifficulty;
|
||||
const nWeakenHackThreads = Math.ceil(helper.calculateWeakenThreadCountToTargetSecurity(
|
||||
server.minDifficulty,
|
||||
increasedSecurityAfterHack, cores));
|
||||
|
||||
const nGrowThreads = Math.ceil(helper.calculateGrowThreadCount(hostname, startMoney - earnMoneyPerCycle, startMoney, cores));
|
||||
const increasedSecurityAfterGrow = helper.calculuateGrowthSecurity(nGrowThreads, cores) + server.minDifficulty;
|
||||
|
||||
const nWeakenGrowThreads = Math.ceil(helper.calculateWeakenThreadCountToTargetSecurity(
|
||||
server.minDifficulty,
|
||||
increasedSecurityAfterGrow, cores));
|
||||
|
||||
return {
|
||||
earnMoneyPerSec: earnMoneyPerCycle / cycleTime,
|
||||
earnExpPerSec: earnExpPerCycle / cycleTime,
|
||||
cycleTime,
|
||||
totalThreadCount: hackThread + nWeakenHackThreads + nGrowThreads + nWeakenGrowThreads,
|
||||
HThreadCount: hackThread,
|
||||
HWThreadCount: nWeakenHackThreads,
|
||||
GThreadCount: nGrowThreads,
|
||||
GWThreadCount: nWeakenGrowThreads
|
||||
}
|
||||
}
|
||||
|
||||
function calculateOptimal(ns: NS, target: string, req: ReserveRequest): HWGW {
|
||||
|
||||
return {
|
||||
GThreadCount: 0,
|
||||
HThreadCount: 0,
|
||||
GWThreadCount: 0,
|
||||
HWThreadCount: 0,
|
||||
}
|
||||
}
|
||||
|
||||
export function requestHWGW(req: ReserveRequest, target: string): void {
|
||||
const key = getKeyOfHWGWBatchManager(target);
|
||||
const data = localStorage.getItem(key);
|
||||
let requests: ReserveRequest[];
|
||||
if (data) {
|
||||
requests = JSON.parse(data);
|
||||
}
|
||||
else {
|
||||
requests = [];
|
||||
}
|
||||
requests.push(req);
|
||||
localStorage.setItem(key, JSON.stringify(requests));
|
||||
}
|
||||
|
||||
//export async function batchDaemon(ns: NS): Promise<void> {
|
||||
// const mgr = new HWGWBatchManager(ns, BATCH_KEY);
|
||||
// for (; ;) {
|
||||
// await mgr.tick();
|
||||
// }
|
||||
//}
|
@ -1,4 +1,4 @@
|
||||
import { Server, Player } from "@ns";
|
||||
import { NS, Server, Player, BitNodeMultipliers } from "@ns";
|
||||
|
||||
const CONSTANTS = {
|
||||
ServerBaseGrowthRate: 1.03, // Unadjusted Growth rate
|
||||
@ -7,8 +7,13 @@ const CONSTANTS = {
|
||||
ServerWeakenAmount: 0.05, // Amount by which server's security decreases when weakened
|
||||
}
|
||||
|
||||
const BitNodeMultipliers = {
|
||||
const DefaultBitNodeMultipliers: BitNodeMultipliers = {
|
||||
HackingLevelMultiplier: 1,
|
||||
StrengthLevelMultiplier: 1,
|
||||
DefenseLevelMultiplier: 1,
|
||||
DexterityLevelMultiplier: 1,
|
||||
AgilityLevelMultiplier: 1,
|
||||
CharismaLevelMultiplier: 1,
|
||||
|
||||
ServerGrowthRate: 1,
|
||||
ServerMaxMoney: 1,
|
||||
@ -16,16 +21,62 @@ const BitNodeMultipliers = {
|
||||
ServerStartingSecurity: 1,
|
||||
ServerWeakenRate: 1,
|
||||
|
||||
HomeComputerRamCost: 1,
|
||||
|
||||
PurchasedServerCost: 1,
|
||||
PurchasedServerSoftcap: 1,
|
||||
PurchasedServerLimit: 1,
|
||||
PurchasedServerMaxRam: 1,
|
||||
|
||||
CompanyWorkMoney: 1,
|
||||
CrimeMoney: 1,
|
||||
HacknetNodeMoney: 1,
|
||||
ManualHackMoney: 1,
|
||||
ScriptHackMoney: 1,
|
||||
ScriptHackMoneyGain: 1,
|
||||
CodingContractMoney: 1,
|
||||
|
||||
ClassGymExpGain: 1,
|
||||
CompanyWorkExpGain: 1,
|
||||
CrimeExpGain: 1,
|
||||
FactionWorkExpGain: 1,
|
||||
HackExpGain: 1,
|
||||
|
||||
ScriptHackMoney: 1,
|
||||
}
|
||||
FactionPassiveRepGain: 1,
|
||||
FactionWorkRepGain: 1,
|
||||
RepToDonateToFaction: 1,
|
||||
|
||||
AugmentationMoneyCost: 1,
|
||||
AugmentationRepCost: 1,
|
||||
|
||||
InfiltrationMoney: 1,
|
||||
InfiltrationRep: 1,
|
||||
|
||||
FourSigmaMarketDataCost: 1,
|
||||
FourSigmaMarketDataApiCost: 1,
|
||||
|
||||
CorporationValuation: 1,
|
||||
CorporationSoftcap: 1,
|
||||
|
||||
BladeburnerRank: 1,
|
||||
BladeburnerSkillCost: 1,
|
||||
|
||||
GangSoftcap: 1,
|
||||
//GangUniqueAugs: 1,
|
||||
|
||||
DaedalusAugsRequirement: 30,
|
||||
|
||||
StaneksGiftPowerMultiplier: 1,
|
||||
StaneksGiftExtraSize: 0,
|
||||
|
||||
WorldDaemonDifficulty: 1,
|
||||
};
|
||||
|
||||
export function calculateIntelligenceBonus(intelligence: number, weight = 1): number {
|
||||
return 1 + (weight * Math.pow(intelligence, 0.8)) / 600;
|
||||
}
|
||||
}
|
||||
|
||||
export function calculateServerGrowth(server: Server, threads: number, p: Player, cores = 1): number {
|
||||
export function calculateServerGrowth(server: Server, threads: number, p: Player, cores = 1, bit: BitNodeMultipliers = DefaultBitNodeMultipliers): number {
|
||||
const numServerGrowthCycles = Math.max(Math.floor(threads), 0);
|
||||
|
||||
//Get adjusted growth rate, which accounts for server security
|
||||
@ -38,7 +89,7 @@ export function calculateServerGrowth(server: Server, threads: number, p: Player
|
||||
//Calculate adjusted server growth rate based on parameters
|
||||
const serverGrowthPercentage = server.serverGrowth / 100;
|
||||
const numServerGrowthCyclesAdjusted =
|
||||
numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate;
|
||||
numServerGrowthCycles * serverGrowthPercentage * bit.ServerGrowthRate;
|
||||
|
||||
//Apply serverGrowth for the calculated number of growth cycles
|
||||
const coreBonus = 1 + (cores - 1) / 16;
|
||||
@ -72,7 +123,7 @@ export function calculateHackingChance(server: Server, player: Player): number {
|
||||
* Returns the amount of hacking experience the player will gain upon
|
||||
* successfully hacking a server
|
||||
*/
|
||||
export function calculateHackingExpGain(server: Server, player: Player): number {
|
||||
export function calculateHackingExpGain(server: Server, player: Player, bit: BitNodeMultipliers = DefaultBitNodeMultipliers): number {
|
||||
const baseExpGain = 3;
|
||||
const diffFactor = 0.3;
|
||||
if (server.baseDifficulty == null) {
|
||||
@ -81,21 +132,21 @@ export function calculateHackingExpGain(server: Server, player: Player): number
|
||||
let expGain = baseExpGain;
|
||||
expGain += server.baseDifficulty * diffFactor;
|
||||
|
||||
return expGain * player.mults.hacking_exp * BitNodeMultipliers.HackExpGain;
|
||||
return expGain * player.mults.hacking_exp * bit.HackExpGain;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
export function calculatePercentMoneyHacked(server: Server, player: Player): number {
|
||||
export function calculatePercentMoneyHacked(server: Server, player: Player, bit: BitNodeMultipliers = DefaultBitNodeMultipliers): number {
|
||||
// Adjust if needed for balancing. This is the divisor for the final calculation
|
||||
const balanceFactor = 240;
|
||||
|
||||
const difficultyMult = (100 - server.hackDifficulty) / 100;
|
||||
const skillMult = (player.skills.hacking - (server.requiredHackingSkill - 1)) / player.skills.hacking;
|
||||
const percentMoneyHacked =
|
||||
(difficultyMult * skillMult * player.mults.hacking_money * BitNodeMultipliers.ScriptHackMoney) / balanceFactor;
|
||||
(difficultyMult * skillMult * player.mults.hacking_money * bit.ScriptHackMoney) / balanceFactor;
|
||||
if (percentMoneyHacked < 0) {
|
||||
return 0;
|
||||
}
|
||||
@ -143,4 +194,95 @@ export function calculateWeakenTime(server: Server, player: Player): number {
|
||||
const weakenTimeMultiplier = 4; // Relative to hacking time
|
||||
|
||||
return weakenTimeMultiplier * calculateHackingTime(server, player);
|
||||
}
|
||||
|
||||
export function canBeAccessBitNode(ns: NS): boolean {
|
||||
try {
|
||||
ns.getBitNodeMultipliers();
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function getBitNodeMultipliersSafe(ns: NS): BitNodeMultipliers {
|
||||
try {
|
||||
return ns.getBitNodeMultipliers();
|
||||
} catch (error) {
|
||||
if (typeof error === "string") {
|
||||
return DefaultBitNodeMultipliers;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export class FormulaHelper {
|
||||
ns: NS;
|
||||
constructor(ns: NS) {
|
||||
this.ns = ns;
|
||||
}
|
||||
calculateWeakenThreadCountToTargetSecurity(targetSecurity: number, curSecurity: number, cores = 1): number {
|
||||
const k = targetSecurity - targetSecurity;
|
||||
const c = this.ns.weakenAnalyze(1, cores);
|
||||
return k / c;
|
||||
}
|
||||
calculateGrowThreadCount(hostname: string, currentMoney: number, targetMoney: number, cores = 1): number {
|
||||
const g = this.ns.growthAnalyze(hostname, targetMoney / currentMoney, cores);
|
||||
return g;
|
||||
}
|
||||
calculateHackSecurity(nThread: number): number {
|
||||
const ServerFortifyAmount = 0.002;
|
||||
return ServerFortifyAmount * nThread;
|
||||
}
|
||||
calculuateGrowthSecurity(nThread: number, cores = 1): number {
|
||||
const ServerWeakenAmount = 0.004;
|
||||
const mul = getBitNodeMultipliersSafe(this.ns);
|
||||
const coreBonus = 1 + (cores - 1) / 16;
|
||||
return ServerWeakenAmount * nThread * coreBonus * mul.ServerWeakenRate;
|
||||
}
|
||||
/**
|
||||
* Returns time it takes to complete a weaken operation on a server, in seconds
|
||||
* @param server
|
||||
* @returns seconds to complete a weaken operation
|
||||
*/
|
||||
calculateWeakenTime(server: Server): number {
|
||||
const player = this.ns.getPlayer();
|
||||
return calculateWeakenTime(server, player);
|
||||
}
|
||||
calculateGrowTime(server: Server): number {
|
||||
const player = this.ns.getPlayer();
|
||||
return calculateGrowTime(server, player);
|
||||
}
|
||||
calculateHackingTime(server: Server): number {
|
||||
const player = this.ns.getPlayer();
|
||||
return calculateHackingTime(server, player);
|
||||
}
|
||||
/**
|
||||
* Hack
|
||||
* @param server server to get
|
||||
* @returns percent of earned money (0~1 value)
|
||||
* @example
|
||||
* ```ts
|
||||
* calculatePercentMoneyHacked(server) //0.2 mean 20%
|
||||
* ```
|
||||
*/
|
||||
calculatePercentMoneyHacked(server: Server): number {
|
||||
const player = this.ns.getPlayer();
|
||||
const bit = getBitNodeMultipliersSafe(this.ns);
|
||||
return calculatePercentMoneyHacked(server, player, bit);
|
||||
}
|
||||
calculateServerGrowth(server: Server, thread: number, cores = 1): number {
|
||||
const player = this.ns.getPlayer();
|
||||
const bit = getBitNodeMultipliersSafe(this.ns);
|
||||
return calculateServerGrowth(server, thread, player, cores, bit);
|
||||
}
|
||||
calculateHackingChance(server: Server): number {
|
||||
const player = this.ns.getPlayer();
|
||||
return calculateHackingChance(server, player);
|
||||
}
|
||||
calculateHackingExpGain(server: Server): number{
|
||||
const player = this.ns.getPlayer();
|
||||
const bit = getBitNodeMultipliersSafe(this.ns);
|
||||
return calculateHackingExpGain(server,player,bit);
|
||||
}
|
||||
}
|
38
src/lib/scheduler.ts
Normal file
38
src/lib/scheduler.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import {NS } from "@ns";
|
||||
|
||||
|
||||
type WorkFunc = ()=>void;
|
||||
type WorkChunk = {
|
||||
onStart: WorkFunc[];
|
||||
onFinish: WorkFunc[];
|
||||
}
|
||||
|
||||
interface Tickable {
|
||||
tick(): void;
|
||||
}
|
||||
|
||||
class PidTerminateExecutor{
|
||||
ns: NS;
|
||||
lastCheck: number;
|
||||
pidSet: Map<number, EventTarget>;
|
||||
tick(): void{
|
||||
const current = this.ns.getTimeSinceLastAug();
|
||||
const deadScripts = this.ns.getRecentScripts().filter(x=>x.timeOfDeath >= current);
|
||||
deadScripts.forEach(x=>{
|
||||
if(this.pidSet.has(x.pid)){
|
||||
const target = this.pidSet.get(x.pid);
|
||||
target?.dispatchEvent(new )
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class TimerExecutor{
|
||||
ns: NS;
|
||||
constructor(ns: NS){
|
||||
this.ns = ns;
|
||||
}
|
||||
asdf():{
|
||||
|
||||
}
|
||||
}
|
@ -39,10 +39,11 @@ function findServer(ns: NS, startServer: string, targetServer: string, depth: nu
|
||||
if(detail){
|
||||
const moneyAvailable = ns.nFormat(info.moneyAvailable,"$0.000a");
|
||||
const moneyMax = ns.nFormat(info.moneyMax,"$0.000a");
|
||||
ret.push(sprintf("%s └%s🛡️ %6.2f/%6.2f(%3d),💸 %10s/%10s",extendSymbol,
|
||||
ret.push(sprintf("%s └%s🛡️ %6.2f/%6.2f(%3d),💸 %10s/%10s 💾%d/%d",extendSymbol,
|
||||
"-".repeat(20-depth),
|
||||
info.hackDifficulty,info.minDifficulty,info.requiredHackingSkill,
|
||||
moneyAvailable,moneyMax));
|
||||
moneyAvailable,moneyMax,
|
||||
info.maxRam, info.ramUsed));
|
||||
}
|
||||
if (lock !== "impossible") {
|
||||
const s = findServer(ns, targetServer, server, depth + 1).map(x=>`${extendSymbol}${x}`);
|
||||
|
@ -2,14 +2,18 @@ import { selectRootedServerList, ServerInfo } from "lib/servers";
|
||||
import {
|
||||
calculateWeakenTime,
|
||||
calculatePercentMoneyHacked,
|
||||
calculateHackingExpGain,
|
||||
calculateServerGrowth
|
||||
} from "lib/formula";
|
||||
import { NS } from '@ns'
|
||||
import { sprintf } from "./lib/printf";
|
||||
import { parse } from "./lib/flag";
|
||||
|
||||
|
||||
// eslint-disable-next-line require-await
|
||||
export async function main(ns: NS): Promise<void> {
|
||||
const flag = parse(ns.args.map(x=>x.toString()))
|
||||
|
||||
const list = selectRootedServerList(ns);
|
||||
const player = ns.getPlayer();
|
||||
const m = list.map(x => {
|
||||
@ -18,6 +22,7 @@ export async function main(ns: NS): Promise<void> {
|
||||
} as ServerInfo;
|
||||
ns.print(optimalState.minDifficulty," ", optimalState.hackDifficulty ,"");
|
||||
const weakenTime = calculateWeakenTime(optimalState, player);
|
||||
const expGain = calculateHackingExpGain(optimalState,player);
|
||||
const earnMoney = calculatePercentMoneyHacked(optimalState, player);
|
||||
//const growPercent = calculateServerGrowth()
|
||||
return {
|
||||
@ -25,15 +30,29 @@ export async function main(ns: NS): Promise<void> {
|
||||
info: x,
|
||||
weakenTime,
|
||||
earnMoney,
|
||||
ce: earnMoney* x.moneyMax / weakenTime,
|
||||
ce: earnMoney* x.moneyMax/weakenTime,
|
||||
expCe: expGain / weakenTime,
|
||||
expGain,
|
||||
}
|
||||
});
|
||||
m.sort((a,b)=>(b.ce-a.ce));
|
||||
|
||||
m.filter(x=>x.ce > 0).forEach(x=>{
|
||||
const msg = sprintf("%20s %8s %6.1fs %10.2f",x.hostname,
|
||||
ns.nFormat(x.earnMoney * x.info.moneyMax,"$0.00a"),x.weakenTime,
|
||||
x.ce*100);
|
||||
ns.tprint(msg);
|
||||
})
|
||||
if(flag.exp){
|
||||
m.sort((a,b)=>(b.expCe-a.expCe));
|
||||
|
||||
m.filter(x=>x.expCe > 0).forEach(x=>{
|
||||
const msg = sprintf("%20s %8s %6.1fs %8s",x.hostname,
|
||||
ns.nFormat(x.expGain,"0.00a"),x.weakenTime,
|
||||
ns.nFormat(x.expCe,"0.00a"));
|
||||
ns.tprint(msg);
|
||||
})
|
||||
}
|
||||
else {
|
||||
m.sort((a,b)=>(b.ce-a.ce));
|
||||
|
||||
m.filter(x=>x.ce > 0).forEach(x=>{
|
||||
const msg = sprintf("%20s %8s %6.1fs %10s",x.hostname,
|
||||
ns.nFormat(x.earnMoney * x.info.moneyMax,"$0.00a"),x.weakenTime,
|
||||
ns.nFormat(x.ce,"$0.000a"));
|
||||
ns.tprint(msg);
|
||||
})
|
||||
}
|
||||
}
|
11
src/repl.ts
Normal file
11
src/repl.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { NS } from '@ns'
|
||||
|
||||
export async function main(ns: NS) : Promise<void> {
|
||||
const cmd = ns.args.join(" ");
|
||||
// @ts-ignore: disable-next-line
|
||||
const fn = new Function(["ns"],cmd);
|
||||
const v = await fn(ns);
|
||||
if(v !== undefined){
|
||||
ns.tprint(v)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user