Skip to content

Instantly share code, notes, and snippets.

@KrunoSaho
Last active June 28, 2023 17:14
Show Gist options
  • Save KrunoSaho/38b584a63b776c27b398cab1e4d8bd14 to your computer and use it in GitHub Desktop.
Save KrunoSaho/38b584a63b776c27b398cab1e4d8bd14 to your computer and use it in GitHub Desktop.
MasterHackerController.ts
import { NS } from "../NetscriptDefinitions";
import { getThreadCount, getAllServers, breakServers } from "./Util";
type SubscriptPaths = { Path: string; Cost: number };
type ScriptInformation = { Hack: SubscriptPaths; Grow: SubscriptPaths; Weaken: SubscriptPaths };
type Operations = "hack" | "grow" | "weaken";
type Operation = (
operation: Operations,
srcServer: string,
targetServer: string,
threads: number
) => void;
enum WorkerTypes {
AnyThreads,
HighThreads,
}
enum ScriptTypes {
Hack = "hacks/SimpleHack.js",
Grow = "hacks/SimpleGrow.js",
Weaken = "hacks/SimpleWeaken.js",
}
export async function main(ns: NS) {
ns.disableLog("sleep");
ns.disableLog("scan");
ns.disableLog("scp");
ns.disableLog("getServerSecurityLevel");
ns.disableLog("getServerUsedRam");
ns.disableLog("getServerMaxRam");
ns.disableLog("getServerMinSecurityLevel");
ns.disableLog("getServerSecurityLevel");
ns.disableLog("getServerRequiredHackingLevel");
ns.disableLog("getHackingLevel");
ns.disableLog("getServerMaxMoney");
ns.disableLog("getScriptRam");
ns.disableLog("getServerMoneyAvailable");
ns.disableLog("exec");
eval("ns.bypass(document);");
// Log
ns.tail();
ns.resizeTail(350, 700);
ns.moveTail(2200, 600);
ns.clearLog();
const scriptData = {
Hack: {
Path: "hacks/SimpleHack.js",
Cost: 1.7,
} as SubscriptPaths,
Grow: {
Path: "hacks/SimpleGrow.js",
Cost: 1.75,
} as SubscriptPaths,
Weaken: {
Path: "hacks/SimpleWeaken.js",
Cost: 1.75,
} as SubscriptPaths,
} as ScriptInformation;
const scripts = getScriptRunner(ns, scriptData);
while (true) {
const [myNodes, otherNodes] = prepare(ns);
await mastermindTheWork(ns, scripts, myNodes, otherNodes);
await ns.sleep(20);
}
}
///////////////////////////////////////////
// The Workhorse
///////////////////////////////////////////
function getWorkers(ns: NS, myNodes: string[]) {
const orderedByRamServers = myNodes.sort(
(a, b) => ns.getServerMaxRam(b) - ns.getServerMaxRam(a)
);
let lastDelta = 0;
const highThreadCountServers: string[] = [];
for (const server of orderedByRamServers) {
for (const server2 of orderedByRamServers) {
if (server === server2) continue;
const delta = ns.getServerMaxRam(server) - ns.getServerMaxRam(server2);
if (delta >= lastDelta && !highThreadCountServers.includes(server)) {
lastDelta = delta;
highThreadCountServers.push(server);
}
}
}
let unusedHighThreadServers: string[] = highThreadCountServers;
let usedHighThreadServers: string[] = [];
let unusedServers: string[] = myNodes.filter((s) => !usedHighThreadServers.includes(s));
let usedServers: string[] = [];
if (myNodes.length === 1) {
unusedServers = [...myNodes];
unusedHighThreadServers = [...myNodes];
}
const getRegularServer = () => {
if (unusedServers.length === 0) {
unusedServers = usedServers;
usedServers = [];
}
const myServer = unusedServers.pop() as string;
usedServers.push(myServer);
return myServer;
};
const getHighThreadServer = () => {
if (unusedHighThreadServers.length === 0) {
unusedHighThreadServers = usedHighThreadServers;
usedHighThreadServers = [];
}
const myServer = unusedHighThreadServers.pop() as string;
usedHighThreadServers.push(myServer);
return myServer;
};
// Prep work
return (request: WorkerTypes) => {
if (request === WorkerTypes.AnyThreads) {
const server = getRegularServer();
return server;
}
const server = getHighThreadServer();
return server;
};
}
async function mastermindTheWork(
ns: NS,
script: Operation,
myNodes: string[],
targetNodes: string[]
) {
// Prep work
const getWorker = getWorkers(ns, myNodes);
// Do the work
const serverData = targetNodes.map((targetServer) => {
const server = ns.getServer(targetServer);
return {
...server,
};
});
for (let targetServer of targetNodes) {
const server = ns.getServer(targetServer);
const serverMaxMoney = server.moneyMax as number;
if (!ns.hasRootAccess(targetServer)) continue;
if (ns.getServerSecurityLevel(targetServer) > ns.getServerMinSecurityLevel(targetServer)) {
let workerType = WorkerTypes.AnyThreads;
if (Math.random() <= 0.1) workerType = WorkerTypes.HighThreads;
if (serverMaxMoney > 1_000_000_000) workerType = WorkerTypes.HighThreads;
const worker = getWorker(workerType);
const maxThreads = getThreadCount(ns, ScriptTypes.Weaken, worker);
script("weaken", worker, targetServer, maxThreads);
}
const securityLowEnough =
Math.floor(ns.getServerMoneyAvailable(targetServer)) ===
Math.floor(ns.getServerMaxMoney(targetServer));
if (securityLowEnough || Math.random() <= 0.2) {
const worker = getWorker(WorkerTypes.HighThreads);
const maxThreads = getThreadCount(ns, ScriptTypes.Hack, worker);
if (maxThreads === 1) continue;
script("hack", worker, targetServer, maxThreads);
const maxThreadsWeaken = getThreadCount(ns, ScriptTypes.Weaken, worker);
script("weaken", worker, targetServer, maxThreadsWeaken);
}
const worker = getWorker(WorkerTypes.AnyThreads);
const maxThreads = getThreadCount(ns, ScriptTypes.Grow, worker);
script("grow", getWorker(WorkerTypes.AnyThreads), targetServer, maxThreads);
script("weaken", getWorker(WorkerTypes.AnyThreads), targetServer, maxThreads);
}
}
///////////////////////////////////////////
// Prep. Work
///////////////////////////////////////////
function prepare(ns: NS) {
const myServers = ns.getPurchasedServers();
copyHackFilesToServers(ns, myServers);
myServers.push("home");
const baseCostScript = 1.75; // TODO: Make this dynamic
const allServers = getAllServers(ns.scan, "home", [])
.filter((s) => !myServers.includes(s) && s != "home")
.filter((s) => ns.getServerSecurityLevel(s) <= 100)
.filter((s) => Math.floor(ns.getServerMaxRam(s)) >= baseCostScript)
.filter((s) => ns.getServerRequiredHackingLevel(s) <= ns.getHackingLevel())
.filter((s) => ns.getServerMaxMoney(s) > 0)
.sort((_) => Math.random() - Math.random());
// Break security on all servers
breakServers(ns, "home", allServers);
// Newly broken servers can be added here
const backDooredServers = allServers.filter((s) => ns.hasRootAccess(s));
copyHackFilesToServers(ns, backDooredServers);
myServers.push(...backDooredServers);
myServers.sort((a, b) => Math.random() - Math.random());
// The workhorse
return [myServers, allServers];
}
function copyHackFilesToServers(ns: NS, backDooredServers: string[]) {
const files = [
"hacks/SimpleHack.js",
"hacks/SimpleGrow.js",
"hacks/SimpleWeaken.js",
"hacks/AllInOne.js",
];
for (const server of backDooredServers) {
if (!ns.scp(files, server, "home")) {
ns.print(`ERROR: copyHackFilesToServers => Failed to copy files to ${server}`);
}
}
}
function getScriptRunner(ns: NS, scriptData: ScriptInformation) {
const basicFn = (scriptPath) => (node: string, threads: number, target: string) =>
ns.exec(scriptPath, node, threads, target);
const [weaken, grow, hack] = [
basicFn(scriptData.Weaken.Path),
basicFn(scriptData.Grow.Path),
basicFn(scriptData.Hack.Path),
];
return (operation: Operations, myServer: string, targetServer: string, threads: number) => {
const opGrow = operation === "grow";
const opHack = operation === "hack";
const op = opGrow ? grow : opHack ? hack : weaken;
if (threads > 0) {
let colour = "\x1b[36m";
if (opGrow) {
colour = "\x1b[33m";
}
if (opHack) {
colour = "\x1b[31m";
}
ns.print(
`${colour}${operation} on ${myServer} -> ${targetServer} with ${threads} threads
\x1b[0m`
);
op(myServer, threads, targetServer);
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment