init 3
This commit is contained in:
parent
d24d3a63c8
commit
374196acce
@ -5,6 +5,7 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node build.js",
|
"build": "node build.js",
|
||||||
|
"check": "tsc --noEmit",
|
||||||
"defs": "node ./updateDefs.js"
|
"defs": "node ./updateDefs.js"
|
||||||
},
|
},
|
||||||
"repository": {
|
"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> {
|
export async function main(ns : NS) : Promise<void> {
|
||||||
const stat: number[] = [];
|
const stat: number[] = [];
|
||||||
|
const M = 10;
|
||||||
for (let i = 0; i < 100; i++) {
|
for (let i = 0; i < 100; i++) {
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
await ns.sleep(0);
|
await ns.sleep(M);
|
||||||
const end = performance.now();
|
const end = performance.now();
|
||||||
stat.push(end- start);
|
stat.push(end- start);
|
||||||
}
|
}
|
||||||
const avg = stat.reduce((x,y)=>x+y)/stat.length;
|
const avg = stat.reduce((x,y)=>x+y)/stat.length;
|
||||||
const max = Math.max(...stat);
|
const max = Math.max(...stat);
|
||||||
const min = Math.min(...stat);
|
const min = Math.min(...stat);
|
||||||
ns.tprint(`avg : ${avg}`);
|
ns.tprint(`avg : ${avg - M}`);
|
||||||
ns.tprint(`max : ${max}`);
|
ns.tprint(`max : ${max - M}`);
|
||||||
ns.tprint(`min : ${min}`);
|
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;
|
path: string;
|
||||||
content: string;
|
content: string;
|
||||||
|
ram: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type FilePack = FilePackEntry[];
|
type FilePack = BatchFilePackEntry[];
|
||||||
|
|
||||||
const createScriptContent: (f: string) => string = (funcName: string) => `export async function main(ns) {
|
const createScriptContent: (f: string) => string = (funcName: string) => `export async function main(ns) {
|
||||||
if(ns.args.length < 3){
|
if(ns.args.length < 3){
|
||||||
@ -17,13 +23,15 @@ const createScriptContent: (f: string) => string = (funcName: string) => `export
|
|||||||
const sleepDuration = parseInt(ns.args[0]);
|
const sleepDuration = parseInt(ns.args[0]);
|
||||||
const hostname = ns.args[1].toString();
|
const hostname = ns.args[1].toString();
|
||||||
const stock = ns.args[2] == "true";
|
const stock = ns.args[2] == "true";
|
||||||
|
if(sleepDuration > 0){
|
||||||
await ns.sleep(sleepDuration);
|
await ns.sleep(sleepDuration);
|
||||||
|
}
|
||||||
await ns.${funcName}(hostname,{
|
await ns.${funcName}(hostname,{
|
||||||
stock,
|
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");
|
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 = [
|
export const batchFilePack: FilePack = [
|
||||||
{
|
{
|
||||||
|
type: "hack",
|
||||||
path: "/tmp/hack.js",
|
path: "/tmp/hack.js",
|
||||||
content: createScriptContent("hack")
|
content: createScriptContent("hack"),
|
||||||
|
ram:1.7,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
type: "weaken",
|
||||||
path: "/tmp/weaken.js",
|
path: "/tmp/weaken.js",
|
||||||
content: createScriptContent("weaken")
|
content: createScriptContent("weaken"),
|
||||||
|
ram: 1.75,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
type: "grow",
|
||||||
path: "/tmp/grow.js",
|
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> {
|
export async function scpBatchFilePack(ns: NS, hostname: string): Promise<void> {
|
||||||
const list = batchFilePack.map(entry=>entry.path);
|
const list = batchFilePack.map(entry => entry.path);
|
||||||
await installBatchFilePack(ns);
|
await installBatchFilePack(ns);
|
||||||
await ns.scp(list,hostname);
|
await ns.scp(list, hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function installBatchFilePack(ns: NS): Promise<void> {
|
export async function installBatchFilePack(ns: NS): Promise<void> {
|
||||||
@ -62,7 +97,7 @@ export function isBatchFilePackInstalled(ns: NS, hostname?: string): boolean {
|
|||||||
return batchFilePack.every(entry => ns.fileExists(entry.path, hostname))
|
return batchFilePack.every(entry => ns.fileExists(entry.path, hostname))
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExecOption{
|
export interface ExecOption {
|
||||||
hostname: string;
|
hostname: string;
|
||||||
/**
|
/**
|
||||||
* @default 1
|
* @default 1
|
||||||
@ -75,21 +110,191 @@ export interface ExecOption{
|
|||||||
/**
|
/**
|
||||||
* target hostname to operate "hack", "weaken" or "grow"
|
* target hostname to operate "hack", "weaken" or "grow"
|
||||||
*/
|
*/
|
||||||
target: number;
|
target: string;
|
||||||
stock?: boolean;
|
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,
|
return ns.exec(path, option.hostname, option.numThread,
|
||||||
option.sleepDuration ?? 0, option.target, option.stock ?? false);
|
option.sleepDuration ?? 0, option.target, option.stock ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function execHack(ns: NS,option: ExecOption): number{
|
export function execHack(ns: NS, option: ExecOption): number {
|
||||||
return execBatchfile(ns,"/tmp/hack.js",option);
|
return execBatchfile(ns, "/tmp/hack.js", option);
|
||||||
}
|
}
|
||||||
export function execGrow(ns: NS,option: ExecOption): number{
|
export function execGrow(ns: NS, option: ExecOption): number {
|
||||||
return execBatchfile(ns,"/tmp/grow.js",option);
|
return execBatchfile(ns, "/tmp/grow.js", option);
|
||||||
}
|
}
|
||||||
export function execWeaken(ns: NS,option: ExecOption): number{
|
export function execWeaken(ns: NS, option: ExecOption): number {
|
||||||
return execBatchfile(ns,"/tmp/weaken.js",option);
|
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 = {
|
const CONSTANTS = {
|
||||||
ServerBaseGrowthRate: 1.03, // Unadjusted Growth rate
|
ServerBaseGrowthRate: 1.03, // Unadjusted Growth rate
|
||||||
@ -7,8 +7,13 @@ const CONSTANTS = {
|
|||||||
ServerWeakenAmount: 0.05, // Amount by which server's security decreases when weakened
|
ServerWeakenAmount: 0.05, // Amount by which server's security decreases when weakened
|
||||||
}
|
}
|
||||||
|
|
||||||
const BitNodeMultipliers = {
|
const DefaultBitNodeMultipliers: BitNodeMultipliers = {
|
||||||
HackingLevelMultiplier: 1,
|
HackingLevelMultiplier: 1,
|
||||||
|
StrengthLevelMultiplier: 1,
|
||||||
|
DefenseLevelMultiplier: 1,
|
||||||
|
DexterityLevelMultiplier: 1,
|
||||||
|
AgilityLevelMultiplier: 1,
|
||||||
|
CharismaLevelMultiplier: 1,
|
||||||
|
|
||||||
ServerGrowthRate: 1,
|
ServerGrowthRate: 1,
|
||||||
ServerMaxMoney: 1,
|
ServerMaxMoney: 1,
|
||||||
@ -16,16 +21,62 @@ const BitNodeMultipliers = {
|
|||||||
ServerStartingSecurity: 1,
|
ServerStartingSecurity: 1,
|
||||||
ServerWeakenRate: 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,
|
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 {
|
export function calculateIntelligenceBonus(intelligence: number, weight = 1): number {
|
||||||
return 1 + (weight * Math.pow(intelligence, 0.8)) / 600;
|
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);
|
const numServerGrowthCycles = Math.max(Math.floor(threads), 0);
|
||||||
|
|
||||||
//Get adjusted growth rate, which accounts for server security
|
//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
|
//Calculate adjusted server growth rate based on parameters
|
||||||
const serverGrowthPercentage = server.serverGrowth / 100;
|
const serverGrowthPercentage = server.serverGrowth / 100;
|
||||||
const numServerGrowthCyclesAdjusted =
|
const numServerGrowthCyclesAdjusted =
|
||||||
numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate;
|
numServerGrowthCycles * serverGrowthPercentage * bit.ServerGrowthRate;
|
||||||
|
|
||||||
//Apply serverGrowth for the calculated number of growth cycles
|
//Apply serverGrowth for the calculated number of growth cycles
|
||||||
const coreBonus = 1 + (cores - 1) / 16;
|
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
|
* Returns the amount of hacking experience the player will gain upon
|
||||||
* successfully hacking a server
|
* 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 baseExpGain = 3;
|
||||||
const diffFactor = 0.3;
|
const diffFactor = 0.3;
|
||||||
if (server.baseDifficulty == null) {
|
if (server.baseDifficulty == null) {
|
||||||
@ -81,21 +132,21 @@ export function calculateHackingExpGain(server: Server, player: Player): number
|
|||||||
let expGain = baseExpGain;
|
let expGain = baseExpGain;
|
||||||
expGain += server.baseDifficulty * diffFactor;
|
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
|
* 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: 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
|
// Adjust if needed for balancing. This is the divisor for the final calculation
|
||||||
const balanceFactor = 240;
|
const balanceFactor = 240;
|
||||||
|
|
||||||
const difficultyMult = (100 - server.hackDifficulty) / 100;
|
const difficultyMult = (100 - server.hackDifficulty) / 100;
|
||||||
const skillMult = (player.skills.hacking - (server.requiredHackingSkill - 1)) / player.skills.hacking;
|
const skillMult = (player.skills.hacking - (server.requiredHackingSkill - 1)) / player.skills.hacking;
|
||||||
const percentMoneyHacked =
|
const percentMoneyHacked =
|
||||||
(difficultyMult * skillMult * player.mults.hacking_money * BitNodeMultipliers.ScriptHackMoney) / balanceFactor;
|
(difficultyMult * skillMult * player.mults.hacking_money * bit.ScriptHackMoney) / balanceFactor;
|
||||||
if (percentMoneyHacked < 0) {
|
if (percentMoneyHacked < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -144,3 +195,94 @@ export function calculateWeakenTime(server: Server, player: Player): number {
|
|||||||
|
|
||||||
return weakenTimeMultiplier * calculateHackingTime(server, player);
|
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){
|
if(detail){
|
||||||
const moneyAvailable = ns.nFormat(info.moneyAvailable,"$0.000a");
|
const moneyAvailable = ns.nFormat(info.moneyAvailable,"$0.000a");
|
||||||
const moneyMax = ns.nFormat(info.moneyMax,"$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),
|
"-".repeat(20-depth),
|
||||||
info.hackDifficulty,info.minDifficulty,info.requiredHackingSkill,
|
info.hackDifficulty,info.minDifficulty,info.requiredHackingSkill,
|
||||||
moneyAvailable,moneyMax));
|
moneyAvailable,moneyMax,
|
||||||
|
info.maxRam, info.ramUsed));
|
||||||
}
|
}
|
||||||
if (lock !== "impossible") {
|
if (lock !== "impossible") {
|
||||||
const s = findServer(ns, targetServer, server, depth + 1).map(x=>`${extendSymbol}${x}`);
|
const s = findServer(ns, targetServer, server, depth + 1).map(x=>`${extendSymbol}${x}`);
|
||||||
|
@ -2,14 +2,18 @@ import { selectRootedServerList, ServerInfo } from "lib/servers";
|
|||||||
import {
|
import {
|
||||||
calculateWeakenTime,
|
calculateWeakenTime,
|
||||||
calculatePercentMoneyHacked,
|
calculatePercentMoneyHacked,
|
||||||
|
calculateHackingExpGain,
|
||||||
calculateServerGrowth
|
calculateServerGrowth
|
||||||
} from "lib/formula";
|
} from "lib/formula";
|
||||||
import { NS } from '@ns'
|
import { NS } from '@ns'
|
||||||
import { sprintf } from "./lib/printf";
|
import { sprintf } from "./lib/printf";
|
||||||
|
import { parse } from "./lib/flag";
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line require-await
|
// eslint-disable-next-line require-await
|
||||||
export async function main(ns: NS): Promise<void> {
|
export async function main(ns: NS): Promise<void> {
|
||||||
|
const flag = parse(ns.args.map(x=>x.toString()))
|
||||||
|
|
||||||
const list = selectRootedServerList(ns);
|
const list = selectRootedServerList(ns);
|
||||||
const player = ns.getPlayer();
|
const player = ns.getPlayer();
|
||||||
const m = list.map(x => {
|
const m = list.map(x => {
|
||||||
@ -18,6 +22,7 @@ export async function main(ns: NS): Promise<void> {
|
|||||||
} as ServerInfo;
|
} as ServerInfo;
|
||||||
ns.print(optimalState.minDifficulty," ", optimalState.hackDifficulty ,"");
|
ns.print(optimalState.minDifficulty," ", optimalState.hackDifficulty ,"");
|
||||||
const weakenTime = calculateWeakenTime(optimalState, player);
|
const weakenTime = calculateWeakenTime(optimalState, player);
|
||||||
|
const expGain = calculateHackingExpGain(optimalState,player);
|
||||||
const earnMoney = calculatePercentMoneyHacked(optimalState, player);
|
const earnMoney = calculatePercentMoneyHacked(optimalState, player);
|
||||||
//const growPercent = calculateServerGrowth()
|
//const growPercent = calculateServerGrowth()
|
||||||
return {
|
return {
|
||||||
@ -25,15 +30,29 @@ export async function main(ns: NS): Promise<void> {
|
|||||||
info: x,
|
info: x,
|
||||||
weakenTime,
|
weakenTime,
|
||||||
earnMoney,
|
earnMoney,
|
||||||
ce: earnMoney* x.moneyMax / weakenTime,
|
ce: earnMoney* x.moneyMax/weakenTime,
|
||||||
|
expCe: expGain / weakenTime,
|
||||||
|
expGain,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
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.sort((a,b)=>(b.ce-a.ce));
|
||||||
|
|
||||||
m.filter(x=>x.ce > 0).forEach(x=>{
|
m.filter(x=>x.ce > 0).forEach(x=>{
|
||||||
const msg = sprintf("%20s %8s %6.1fs %10.2f",x.hostname,
|
const msg = sprintf("%20s %8s %6.1fs %10s",x.hostname,
|
||||||
ns.nFormat(x.earnMoney * x.info.moneyMax,"$0.00a"),x.weakenTime,
|
ns.nFormat(x.earnMoney * x.info.moneyMax,"$0.00a"),x.weakenTime,
|
||||||
x.ce*100);
|
ns.nFormat(x.ce,"$0.000a"));
|
||||||
ns.tprint(msg);
|
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