Last active
June 28, 2023 17:14
-
-
Save KrunoSaho/38b584a63b776c27b398cab1e4d8bd14 to your computer and use it in GitHub Desktop.
MasterHackerController.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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