Skip to content

Instantly share code, notes, and snippets.

@Column01
Last active April 22, 2024 15:06
Show Gist options
  • Save Column01/c674139c3dfd6709807e030f64170605 to your computer and use it in GitHub Desktop.
Save Column01/c674139c3dfd6709807e030f64170605 to your computer and use it in GitHub Desktop.
Batch miner for the bitburner game
//
//Main script for batch mining
//
/** @param {NS} ns */
export async function main(ns) {
ns.disableLog("sleep");
var target = ns.args[0];
if (target && ns.serverExists(target)) {
ns.tprint("Targetting server: " + target);
if (ns.getServerRequiredHackingLevel(target) <= ns.getHackingLevel()) {
// Gain access to the server if we can
ns.run("hackServer.js", 1, target);
// Actual loop that hacks the server
while (true) {
await ns.sleep(5);
// Get the server and player for calculations
var server = ns.getServer(target);
var player = ns.getPlayer();
// Calculate how much we can actually steal per thread
var percentPerThread = ns.formulas.hacking.hackPercent(server, player);
// Gather the times required to perform hacks, grows and weakens
var timeToHack = ns.getHackTime(target);
var timeToGrow = ns.getGrowTime(target);
var timeToWeaken = ns.getWeakenTime(target);
// Calculate the times for each operation so they line up properly
// (all should trigger 500ms apart)
var whenToHack = (timeToWeaken - timeToHack) - 500;
var whenToFirstWeaken = 0;
var whenToGrow = (timeToWeaken - timeToGrow) + 500;
var whenToSecondWeaken = 1000;
// Output calculated timings for each operation
ns.print("Timings calculated for each operation:");
ns.print(`Hack: ${whenToHack}\nWeaken 1: ${whenToFirstWeaken}\nGrow: ${whenToGrow}\nWeaken 2: ${whenToSecondWeaken}`);
ns.print(`Attempt to hack could yield ${ns.formatPercent(percentPerThread)}% of the total money from the target`);
// Stagger the timing of each operation to ensure they execute in the correct order
var numThreads = await calculateThreadCounts(ns, target);
var numHackThreads = numThreads["hackThreads"];
var numGrowThreads = numThreads["growThreads"];
var numFirstWeakenThreads = numThreads["firstWeakenThreads"];
var numSecondWeakenThreads = numThreads["secondWeakenThreads"];
ns.print(`Starting the weaken process. Ends in ${timeToWeaken}s`);
var firstWeakenPid = await weakenTarget(ns, whenToFirstWeaken, target, numFirstWeakenThreads);
var secondWeakenPid = await weakenTarget(ns, whenToSecondWeaken, target, numSecondWeakenThreads);
var growPid = await growTarget(ns, whenToGrow, target, numGrowThreads);
var hackPid = await hackTarget(ns, whenToHack, target, numHackThreads);
if (firstWeakenPid == 0 || secondWeakenPid == 0 || growPid == 0 || hackPid == 0) {
ns.tprint("Failed to start a process! Something bad happened...");
ns.tprint(`Weaken PIDs: ${firstWeakenPid} ${secondWeakenPid}`);
ns.tprint(`Grow PID: ${growPid}`);
ns.tprint(`Hack PID: ${hackPid}`);
ns.exit();
}
ns.print("Waiting for all threads to finish and then starting over!");
// Wait for the second weaken to finish which indicates a batch is done
do {
await ns.sleep(100);
} while (ns.isRunning(secondWeakenPid));
ns.print("All threads have compelted. Starting over in one second...");
await ns.sleep(1000);
}
} else {
ns.tprint("Server's hacking level is more than we can hack. Git gud first");
}
} else {
ns.tprint("Specified target does not exist! A target is required to batch mine!");
}
}
async function weakenTarget(ns, timeToWait, target, numThreads) {
// Weaken target security
return ns.run("weakenTarget.js", numThreads, target, timeToWait);
}
async function growTarget(ns, timeToWait, target, numThreads) {
// Grow target money
return ns.run("growTarget.js", numThreads, target, timeToWait);
}
async function hackTarget(ns, timeToWait, target, numThreads) {
// Hack target money
return ns.run("hackTarget.js", numThreads, target, timeToWait);
}
async function calculateThreadCounts(ns, target) {
var server = ns.getServer(target);
var player = ns.getPlayer();
// Gather some memory usage info
const hackRam = ns.getScriptRam("hackTarget.js");
const growRam = ns.getScriptRam("growTarget.js");
const weakenRam = ns.getScriptRam("weakenTarget.js");
const managerRam = ns.getScriptRam("batchMine.js");
const serverRam = ns.getServerMaxRam(ns.getHostname());
const maxMoney = ns.getServerMaxMoney(target)
// Calculate how much we can actually steal per thread
var percentPerThread = ns.formulas.hacking.hackPercent(server, player);
// Initialize thread counts to one
var numHackThreads = 1;
var numGrowThreads = 1;
var numFirstWeakenThreads = 1;
var numSecondWeakenThreads = 1;
// Calculate the max whole number of threads we can use
const maxThreads = Math.floor((serverRam - managerRam) / growRam);
// Initialize required ram value
var requiredRam = 0;
// Calculate how much we could steal, increasing the value each time until we hit 85% of the free RAM on the server
for (var percentToSteal = 0.01; requiredRam < (serverRam - managerRam) * 0.85; percentToSteal += 0.01) {
// Calculate how many threads we need to steal x% of the funds of the server
var numHackThreads = Math.floor(percentToSteal / percentPerThread);
// Set number of hack threads to 1 if it is 0
if (numHackThreads == 0) numHackThreads = 1;
// Analyze the hack impact on security and gather the correct number of threads to weaken it
var hackImpact = ns.hackAnalyzeSecurity(numHackThreads, target);
var numFirstWeakenThreads = Math.ceil(hackImpact / 0.05);
// Set number of weaken threads to 1 if it is 0
if (numFirstWeakenThreads == 0) numFirstWeakenThreads = 1;
var moneyToSteal = (percentPerThread * maxMoney) * numHackThreads;
// Calculate the growth threads required to grow the funds back to max
server.moneyAvailable = server.moneyAvailable - moneyToSteal;
var numGrowThreads = ns.formulas.hacking.growThreads(server, player, maxMoney);
// Set the num of threads for growth 1 if its 0
if (numGrowThreads == 0) numGrowThreads = 1;
// Analyze the hack impact on security and gather the correct number of threads to weaken it
var growImpact = ns.growthAnalyzeSecurity(numGrowThreads, target);
var numSecondWeakenThreads = Math.ceil(growImpact / 0.05);
// Set number of weaken threads to 1 if it is 0
if (numSecondWeakenThreads == 0) numSecondWeakenThreads = 1;
// Calcluate required ram. If it hits 80% of the free ram, the for loop will break, resulting in our thread counts
requiredRam = (numHackThreads * hackRam) + (numGrowThreads * growRam) + ((numFirstWeakenThreads + numSecondWeakenThreads) * weakenRam);
await ns.sleep(5);
}
return {
hackThreads: numHackThreads,
growThreads: numGrowThreads,
firstWeakenThreads: numFirstWeakenThreads,
secondWeakenThreads: numSecondWeakenThreads
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment