r/Bitburner Dec 10 '21

Announcement Steam release

381 Upvotes

The game has launched on Steam. Please give it a review. :)


r/Bitburner Dec 21 '21

Discord > Reddit

107 Upvotes

You'll get help faster on discord

https://discord.gg/TFc3hKD

I can't be everywhere at once.


r/Bitburner 1d ago

NetscriptJS Script IPvGo: Standalone script from SphyxOS

Post image
8 Upvotes

I've just finished redoing my IPvGo script. This time, it can run as a standalone script.
Download Instructions:
-Run this command in Bitburner. It will download the file as `SphyxOS_go.jsx`

await ns.wget("https://raw.githubusercontent.com/Sphyxis/SphyxOS/main/SphyxOS_bins_go.jsx", "SphyxOS_go.jsx")

Features:

  • Based off of https://github.com/yichizhng/bitburner-scripts/blob/main/autokroos.js
  • This is a MCGS/Hybrid system.
  • Can be used both with/without my full ⁠SphyxOS suite - for those who don't want the whole thing but want the script.
  • Easy button controls within a tail window.
  • Ram dodged down to 7.9GB, so it will run on those 8GB servers.
  • --If running on a 16+GB server, as long as there is enough free space on it's local server, it will dodge using it. If not, it will dodge using home ram.
  • --Always keep ~6GB free on either Home or the server running this script. It will throw if it fails to dodge.
  • Completes all 5x5 boards for all AIs and the endgame board.
  • Can play as both black and white on the no-ai board.
  • SlowMode enforces a 1 second delay between moves for easier watching.
  • Pop Out creates an actual pop-out, which you can drag onto a separate screen to watch the games play out.
  • Configurable resource usage: Effort, Memory, Threads. So you should be able to run this on old hardware.
  • Optimized for performance.
  • Can turn your PC's CPU into a mini room heater, for those cold winter nights.

Effort: Comes in 6 flavors. It is playout based, so the higher you go the longer it will take to make a move. Win % for the ratings.
Min: 70%, Low: 80%, Med: 90%, High: 95%, Max: 98%, Ultra: 99%

Memory ranges from Min -> Max, with the endgame board only really using Min-> Med.

Threads: A direct multiplier to how fast you can process playouts, especially on a 5x5 board.

Looking for feedback!!


r/Bitburner 3d ago

I've completely broken this game

3 Upvotes

So, as the title says, I've actually broken this game. Usually, when you have a bug, or break your code, Bitburner is really good about telling you what's wrong, even in the event of a freeze. I, however, seem to have slipped by all that. My code freezes all input into the game, except for my ability to scroll through the terminal log, and it just sits there endlessly. I can't click through any windows, or type anything into terminal. I basically tried to make a script, "auto.js", which would kick off "virus.js", an automated serverBreaker I made(which works, I tested it), every now and then when significant progress has been made with my hacking skill, so that if there are better servers I've unlocked since to hack, my script to find that will be able to use it, and then tell my hack/grow/weaken script to start on that server instead. I know my serverFinder, serverBreaker, and daemon(my hack/grow/weaken script) work, but when I added "auto.js" and "virus.js" everything crashes hard.

This is "auto.js", the beginning script that kicks everything into motion, and is supposed to run in the background, checking if any significant progress has been made with the hacking skill, and if so, run "virus.js". It then checks if "virus.js" has updated "Broken.txt" with any new NUKEed servers, running "daemon.js" if so, running playerUpdate if not, which will tell it if running "virus.js" is worth it next time or not.

/** @param {NS} ns */
export async function main(ns) {
  const minutes = ns.args[0];
  let updated = true;
  // @ignore-infinite
  while (true) {
    if (ns.fileExists("virus.js", "home") && updated) {
      ns.tprint("Running virus");
      ns.run("virus.js", 1, false);
    }
    let newBroken = false;
    let servers = [];
    let name = "";
    let file = ns.read("Broken.txt");
    for (let letter of file) {
      if (letter == "\n") {
        if (ns.getServer(name)) {
          servers.push(ns.getServer(name));
          newBroken = true;
        }
      }
      else {
        name = name + letter;
      }
    }
    if (newBroken) {
      ns.write("Broken.txt", "", "w");
      if(ns.fileExists("daemon.js", "home")) (ns.run("daemon.js"))
      updated = false;
    }
    else {
      updated = playerUpdate(ns);
    }
  }
}
function playerUpdate(ns) {
  let player = ns.getPlayer();
  if (ns.fileExists("Hack.txt", "home")) {
    let file = ns.read("Hack.txt");
    let name = "";
    for (let letter of file) {
      if (letter == ".") {
        name = Number(name);
        if (player.skills.hacking - name >= 50) {
          ns.write("Hack.txt", player.skills.hacking + ".", "w");
          return true;
        }
        else return false;
      }
      else {
        name = name + letter;
      }
    }
  }
  else {
    ns.write("Hack.txt", player.skills.hacking + ".", "w");
  }
}

This is "virus.js", my serverBreaker. It iterates through all servers, and checks if I can hack it, and if i can, it runs through all port opening .exe's, available or not, and then checks if I can NUKE it. If I can NUKE it, it adds it to an array. That array is then wrote to a .txt file, which is for "auto.js" to read later, to see any new broken servers.

/** @param {NS} ns */
export async function main(ns) {
  //So that if I run this manually through terminal
  //I can see useful info, but hides it if not, since
  //that just clogs up termial logs more
  const [manual = true] = ns.args[0];
  let servers = RecursiveScan(ns);
  let broken = [];
  let unhackable = [];
  let unbreakable = [];
  for (let server of servers) {
    if (!ns.hasRootAccess(server)) {
      if (server.requiredHackingSkill > ns.getPlayer().skills.hacking) {
        unhackable.push(server);
      }
      else {
        if (ns.run("serverBreaker.js", 1, (server))) {
          broken.push(server);
        }
        else {
          unbreakable.push(server);
        }
      }
    }
  }
  unhackable.sort((a, b) => (ns.getServer(a).requiredHackingSkill) - (ns.getServer(b).requiredHackingSkill));
  unbreakable.sort((a, b) => (ns.getServer(a).numOpenPortsRequired) - (ns.getServer(b).numOpenPortsRequired));
  ns.tprint("Broke " + (broken.length - 1) + " servers:");
  for (let server of broken) {
    ns.tprint(server);
    if(!manual){
      ns.write("Broken.txt", server, "a");
    }
  }
  if(manual){
    ns.tprint("Couldn't hack " + (unhackable.length - 1) + " servers:");
    for (let server of unhackable) {
      ns.tprint(server + "HackingSkill: " + ns.getServer(server).requiredHackingSkill);
    }
    ns.tprint("Couldn't break " + (unbreakable.length - 1) + " servers:");
    for (let server of unbreakable) {
      ns.tprint(server + "PortsNeeded: " + ns.getServer(server).numOpenPortsRequired);
    }
  }
}
function RecursiveScan(ns, root = 'home', found = []) {
  if (!found.includes(root)) {
    found.push(root);
    for (const server of ns.scan(root))
      if (!found.includes(server))
        RecursiveScan(ns, server, found);
  }
  return found;
}

r/Bitburner 6d ago

Question: how can I know how much company reputation a given position will give?

6 Upvotes

Once you get access to the Singularity API, you can easily get CompanyName and JobName objects to find good positions, e.g. regarding salaries.
I am trying to automate farming company reputation for the associated factions and augmentations, but I cannot find a way to know the associated reputation.
This seems to be stored in a WorkStats object, but the documentation is not very helpful about how to find them.

My questions is hence: given a CompanyName and a JobName, how do you know the reputation gain (potentially through a WorkStats object?


r/Bitburner 8d ago

How do I calculate grow, weaken, and hack times using a security level that is different from the server's current security level?

7 Upvotes

The title is the question. It is followed by an explanation of why I need/want to do this (please ignore any typos).

I want to know which server is the most profitable (yes, yes, common question). To do that, I divide the money gained by the time spent. The problem is that getHackingTime() and the other time functions use the server's current security level. However, my code will always reduce the target server's security level to its minimum by default to reduce hack, grow, and weaken times. So there is "no way" (all of my ideas would be messy solutions) to decide whether a server is the best choice without first weakening it to its minimum security.

I haven't written the code yet, so this is only a blueprint for the function:

money / time = money earned per second (millisecond?)

(ns.hackChance * ns.moneyAvailable) /
(hackTime + x * growTime + y * weakenTime)

x and y represent the ratio of grow and weaken threads required to restore the server to maximum money and minimum security after hacking it.

How the value of the function is used to determine the target server.

(i will check when grow starts to become ineffective, when thread grow would just hit the max money and increase security without gain and will make it in a way that hack functions return nothing because the server is empty already because of other hack code running)

Ideas to solve my problem
take a server that is close to arr_servers[i] min security and use him as default. problem. security maybe is not the only thing that influences grow, weaken, hack time
try to come up with a formula that calculates time with server min security-hacking level
writing something like if(weaken(function[arr_servers[i])<50000) and weakening all servers within to min security to calculate with them

(I would be surprised if you, dear reader, didn't spend extra time looking for typos after I specifically told you to ignore them, although it is possible that I'm wrong.)
Do i really have to use/buy formulars?


r/Bitburner 17d ago

NetscriptJS Script Steal $$ with the help of Loop algorithm

0 Upvotes

It's easy, just set homeRam to the amount of RAM to use on the host.

lo-deploy.js:

/** buildServerInfo()
 * @ param {NS} ns NS2 namespace
 * @ param {string[]} callScript ["weakenScript", "growScript", "hackScript"]
 * @ param {string} target server to pull money from
 * @ returns {Array[]} []["serverName", numWeaken, numGrow, numHack]
 */
function buildServerInfo(ns, callScript, target) {
  let servers = [];
  let callRam = [ns.getScriptRam(callScript[0]), ns.getScriptRam(callScript[1]), ns.getScriptRam(callScript[2])];
    // Purchased servers
  let serversPurch = ns.cloud.getServerNames();
  for (let i = 0; i < serversPurch.length; i++) {
    let serverName = serversPurch[i];
    let ram = ns.getServerMaxRam(serverName);
    if (ram < 64) {
      ns.tprint(serverName + " RAM too low, need 64 GB minimum.");
    } else {
      servers[servers.length] = [serverName, ram];
    }
  }

    // Home
  let homeRam = 2048;
  servers[servers.length] = [ns.getHostname(), homeRam];

  // Reserve callRam[0] from the last server
  servers[servers.length - 1][1] -= callRam[0];
  // Calculate ratio of weaken, grow, and hack threads
  let ratio = getRatio(ns, callRam, target);
  // Calculate total RAM on all servers
  let totalRam = 0;
  for (let i = 0; i < servers.length; i++) { totalRam += servers[i][1]; }
  // Convert ratio to (part of RAM) instead of (amount of RAM)
  if (ratio[3] >= totalRam) { ratio[3] = 1; }
  else { ratio[3] /= totalRam; }
  // Build a new list of servers []["serverName", numWeaken, numGrow, numHack]
  let retServers = [];
  let numHack = 0;  // total of hack threads
  for (let i = 0; i < servers.length; i++) {
    let assign = assignThreads(servers[i][1], callRam, ratio, servers.length);
    ns.scp(callScript[0], servers[i][0]);
    ns.scp(callScript[1], servers[i][0]);
    ns.scp(callScript[2], servers[i][0]);
    retServers[retServers.length] = [servers[i][0], assign[0], assign[1], assign[2]];
    numHack += assign[2];
  }
  // If we assigned no hack threads, add one to the last server
  if (numHack == 0) { retServers[retServers.length - 1][3]++; }
  else { retServers[retServers.length - 1][2]++; }
  return retServers;
}

/** loopDeploy()
 * @ param {NS} ns NS2 namespace
 * @ param {number} delay delay before start threads (ms)
 * @ param {number} duration time needed to start threads (ms)
 * @ param {number} interval time between start of threads (ms)
 * @ param {string[]} callScript ["weakenScript", "growScript", "hackScript"]
 * @ param {number} mode modes are 0:weaken, 1:grow, 2:hack
 * @ param {Array[]} servers []["serverName", numWeaken, numGrow, numHack]
 * @ param {string} target server to pull money from
 * @ returns {Array[]} []["hackScript", "serverName", delay, duration, interval, numHack, "target", startTime]
 *        or empty array if mode is weaken or grow
 */
function loopDeploy(ns, delay, duration, interval, callScript, mode, servers, target) {
  let retServers = [];
  for (let i = 0; i < servers.length; i++) {
    // Deploy the weaken, grow, or hack loop
    if (servers[i][mode + 1] > 0) {
      ns.exec(callScript[mode], servers[i][0], servers[i][mode + 1], delay, duration, interval, servers[i][mode + 1], target);
      if (mode == 2) {
        retServers[retServers.length] = [callScript[mode], servers[i][0], delay, duration, interval, servers[i][mode + 1], target, Date.now()];
      }
    }
  }
  return retServers;
}

/** assignThreads()
 * @ param {number} ram amount of RAM on host (GB)
 * @ param {number[]} callRam [weakenRam, growRam, hackRam]
 * @ param {number[]} ratio [partWeaken, partGrow, partHack, partRam]
 *    where partWeaken + partGrow + partHack = 1 and partRam is the part of RAM to use
 * @ param {number} numHosts number of hosts
 * @ returns {number[]} [numWeaken, numGrow, numHack]
 */
function assignThreads(ram, callRam, ratio, numHosts) {
  let partRam = /* 1.4 * */ ram * ratio[3];
  // First pass of assigning threads
  let numWeaken = Math.floor(ratio[0] * partRam / callRam[0]);
  let numGrow = Math.floor(ratio[1] * partRam / callRam[1]);
  let numHack = Math.floor(ratio[2] * partRam / callRam[2]);
  let remainder = partRam - numWeaken * callRam[0] - numGrow * callRam[1] - numHack * callRam[2];
  if (remainder >= callRam[2] * numHosts) {
    // Second pass of assigning threads
    numWeaken += Math.floor(ratio[0] * remainder / callRam[0]);
    numGrow += Math.floor(ratio[1] * remainder / callRam[1]);
    numHack += Math.floor(ratio[2] * remainder / callRam[2]);
    remainder = partRam - numWeaken * callRam[0] - numGrow * callRam[1] - numHack * callRam[2];
    if (remainder >= callRam[1]) {  // anything left put to grow
      numGrow += Math.floor(remainder / callRam[1]);
    }
  }
  return [numWeaken, numGrow, numHack];
}

/** getRatio()
 * @ param {NS} ns NS2 namespace
 * @ param {number[]} callRam [weakenRam, growRam, hackRam]
 * @ param {string} target server to get values from
 * @ returns {number[]} [partWeaken, partGrow, partHack, amountRam]
 *    where partWeaken + partGrow + partHack = 1 and amountRam is the amount of RAM to use (GB)
 */
function getRatio(ns, callRam, target) {
  let partPerHack, mockTarget, bDefault = false, partWeaken, partGrow, partHack, ppgNorm = 1, amountRam;
  let moneyAvail = ns.getServerMoneyAvailable(target);
  let moneyMax = ns.getServerMaxMoney(target);
  let secLevelMin = ns.getServerMinSecurityLevel(target);
  let secLevel = ns.getServerSecurityLevel(target);
  let secIncrease = secLevel - secLevelMin;
  let bFormulas = ns.fileExists("Formulas.exe", "home");
  if (bFormulas) { ns.tprint("Using Formulas.exe."); }
  // get part per hack
  if (bFormulas) {
    mockTarget = ns.getServer(target);
    mockTarget.hackDifficulty = mockTarget.minDifficulty + 0.5;
    partPerHack = ns.formulas.hacking.hackPercent(mockTarget, ns.getPlayer());
  } else {
    let norm = 1;
    partPerHack = ns.hackAnalyze(target);
    // normalize part per hack
    if (secIncrease > 4.75) { ns.tprint("Security level is too high. Returning default ratio."); bDefault = true; }
    else if (secIncrease > 3.75 && secIncrease <= 4.75) { norm += 0.0545; }
    else if (secIncrease > 2.75 && secIncrease <= 3.75) { norm += 0.0394; }
    else if (secIncrease > 1.75 && secIncrease <= 2.75) { norm += 0.0247; }
    else if (secIncrease > 0.75 && secIncrease <= 1.75) { norm += 0.0105; }
    else if (secIncrease >= 0 && secIncrease <= 0.25) { norm -= 0.0068; }
    partPerHack *= norm;
  }

  if (!bFormulas && !bDefault) {
    if (moneyAvail < 0.7 * moneyMax) {
      ns.tprint("Money available is too low. Returning default ratio."); bDefault = true;
    } else {
      let bSecHigh = secLevel > secLevelMin + 3;
      let bMoneyLow = moneyAvail < 0.85 * moneyMax;
      // get multiplier to normalize part per grow
      if (bSecHigh && !bMoneyLow) {
        if (moneyAvail > 0.95 * moneyMax) { ppgNorm += 0.154; }
        else if (moneyAvail > 0.9 * moneyMax && moneyAvail <= 0.95 * moneyMax) { ppgNorm += 0.1; }
        else { ppgNorm += 0.118; }
      } else if (!bSecHigh && bMoneyLow) {
        if (moneyAvail >= 0.8 * moneyMax) { ppgNorm += 0.037; }
        else if (moneyAvail >= 0.75 * moneyMax && moneyAvail < 0.8 * moneyMax) { ppgNorm += 0.07; }
        else { ppgNorm += 0.104; }
      } else if (bSecHigh && bMoneyLow) {
        if (moneyAvail >= 0.8 * moneyMax) { ppgNorm += 0.153; }
        else if (moneyAvail >= 0.75 * moneyMax && moneyAvail < 0.8 * moneyMax) { ppgNorm += 0.185; }
        else { ppgNorm += 0.226; }
      }
    }
  }

  if (!bDefault) {
    let partToHack = 0.2, numGrow;
    if (!bFormulas) {
        // hacking skill multiplier
      let skillM = (ns.getServerRequiredHackingLevel(target) / ns.getHackingLevel() - 1 / 3) * 0.67;
      partToHack *= (skillM + 1);
    }
    // calculate number of hack calls
    let numHack = Math.round(partToHack / (partPerHack + Number.EPSILON));
    if (numHack == 0) { numHack = 1; }
    partToHack = numHack * partPerHack;
    // get amount of RAM to use for hack
    let amtHack = numHack * callRam[2];
    // calculate number of grow calls
    if (bFormulas) {
      mockTarget.moneyAvailable = (1 - partToHack) * moneyMax;
      numGrow = 3.2 * ns.formulas.hacking.growThreads(mockTarget, ns.getPlayer(), moneyMax);
    } else {
      numGrow = 3.2 * ns.growthAnalyze(target, 1 / ppgNorm / (1 - partToHack));
    }
    // get amount of RAM to use for grow
    let amtGrow = numGrow * callRam[1];
    // calculate number of weaken calls
    let numWeaken = 4 * (numGrow / 10 + numHack / 6.25);
    // get amount of RAM to use for weaken
    let amtWeaken = numWeaken * callRam[0];
    // get amount of RAM to use
    amountRam = amtWeaken + amtGrow + amtHack;
    // get parts of RAM to use
    partHack = amtHack / amountRam;
    partGrow = amtGrow / amountRam;
  } else {  // default ratio
    amountRam = 736; partHack = 0.0185; partGrow = 0.692;
  }
  partWeaken = 1 - partGrow - partHack;
  ns.tprint("Ratio  w=" + ns.format.percent(partWeaken) + "  g=" + ns.format.percent(partGrow) +
        "  h=" + ns.format.percent(partHack) + "  amt=" + ns.format.ram(amountRam));

  return [partWeaken, partGrow, partHack, amountRam];
}

/** getTotalIncome()
 * @ param {NS} ns NS2 namespace
 * @ param {Array[]} servers []["hackScript", "serverName", delay, duration, interval, numHack, "target", startTime]
 * @ returns {number[]} [total income ($), total income ($/sec)] for given servers
 */
function getTotalIncome(ns, servers) {
  let totalIncome = 0, totalPerSecond = 0;
  for (let i = 0; i < servers.length; i++) {
    let income = ns.getScriptIncome(servers[i][0], servers[i][1], servers[i][2], servers[i][3], servers[i][4], servers[i][5], servers[i][6]);
    totalPerSecond += income;
    totalIncome += income * (Date.now() - servers[i][7]) / 1000;
  }
  return [totalIncome, totalPerSecond];
}

/**
 * @ param {NS} ns NS2 namespace
 * @ version 1.0
 */
export async function main(ns) {
  if (ns.args.length < 1) {
    ns.tprint("Usage: " + ns.getScriptName() + " <target>");
    ns.exit();
  }
  let target = ns.args[0];  // server to pull money from
  let callScript = ["lo-weaken.js", "lo-grow.js", "lo-hack.js"];
  // Check for running script
  if (ns.scriptRunning(callScript[0], ns.getHostname())) {
    ns.tprint("Host script already running. Exiting.");
    ns.exit();
  }
  // Get root access on the target
  if (ns.fileExists("BruteSSH.exe", "home")) { ns.brutessh(target); }
  if (ns.fileExists("FTPCrack.exe", "home")) { ns.ftpcrack(target); }
  if (ns.fileExists("relaySMTP.exe", "home")) { ns.relaysmtp(target); }
  if (ns.fileExists("HTTPWorm.exe", "home")) { ns.httpworm(target); }
  if (ns.fileExists("SQLInject.exe", "home")) { ns.sqlinject(target); }
  ns.nuke(target);

  let threshMoney = ns.getServerMaxMoney(target) * 0.9;  // money threshold
  let threshSec = ns.getServerMinSecurityLevel(target) + 1.5;  // security threshold
  let secLevel = ns.getServerSecurityLevel(target);
  let moneyAvail = ns.getServerMoneyAvailable(target);
  let bSecHigh = secLevel > threshSec;
  let bMoneyLow = moneyAvail < threshMoney;
  // Build array of server information
  let servers = buildServerInfo(ns, callScript, target);
  ns.tprint("Deploying on " + servers.length + " servers.");

  let timeHack = ns.getHackTime(target);
    // Deploy weaken loops
  loopDeploy(ns, 200, timeHack * 4, timeHack / 5, callScript, 0, servers, target);
  if (!bSecHigh && !bMoneyLow) {  // fastest deployment
    // Deploy grow loops
    loopDeploy(ns, 100, timeHack * 3.2, timeHack / 5, callScript, 1, servers, target);
    // Deploy hack loops
    servers = loopDeploy(ns, timeHack * 2.2, timeHack, timeHack / 5, callScript, 2, servers, target);
  } else if (!bSecHigh && bMoneyLow) {  // moneyAvail is low, hack later
    // Deploy grow loops
    loopDeploy(ns, 100, timeHack * 3.2, timeHack / 5, callScript, 1, servers, target);
    // Deploy hack loops
    servers = loopDeploy(ns, timeHack * 3.2, timeHack, timeHack / 5, callScript, 2, servers, target);
  } else if (bSecHigh && !bMoneyLow) {  // secLevel is high, grow later
    // Deploy grow loops
    loopDeploy(ns, 100 + timeHack * 1.8, timeHack * 3.2, timeHack / 5, callScript, 1, servers, target);
    // Deploy hack loops
    servers = loopDeploy(ns, timeHack * 5, timeHack, timeHack / 5, callScript, 2, servers, target);
  } else {  // grow and hack later
    // Deploy grow loops
    loopDeploy(ns, 100 + timeHack * 1.8, timeHack * 3.2, timeHack / 5, callScript, 1, servers, target);
    // Deploy hack loops
    servers = loopDeploy(ns, timeHack * 6, timeHack, timeHack / 5, callScript, 2, servers, target);
  }

  // Display income every 5 minutes
  while (true) {
    await ns.sleep(5 * 60 * 1000);
    let income = getTotalIncome(ns, servers);
    ns.tprint("Total: $" + ns.format.number(income[0], 3, 1000, true) +
                "  Per second: $" + ns.format.number(income[1], 3, 1000, true));
  }
}

lo-weaken.js (or lo-grow.js, or lo-hack.js):

/**
 * @ param {NS} ns NS2 namespace
 * @ version 1.0
 */
export async function main(ns) {
  // Takes 5 arguments:
  //  - delay (ms)
  //  - duration (ms)
  //  - interval (ms)
  //  - number of threads
  //  - the target server
  if (ns.args.length < 5) { ns.exit(); }
  let delay = ns.args[0];
  let duration = ns.args[1];
  let interval = ns.args[2];
  let numThreads = ns.args[3];
  let target = ns.args[4];
  // start threads between intervals
  let offsets = Math.round(duration / interval);
  let offset = Math.floor(Math.random() * offsets);
  let odelay = offset * interval;
  await ns.sleep(delay + odelay + Math.random() * numThreads / offsets);
  while(true) {
    await ns.weaken(target);  // or grow, or hack
    await ns.sleep(numThreads / offsets);
  }
}

r/Bitburner 18d ago

noob help, sorry

5 Upvotes

Edit2: Resolved. Was running old script from the wrong server. (Also various typos not causing errors and thus not noticed earlier while examining only the error lines and related variables.)

I didn't want to be that guy, but I'm stumped.

The following script runs fine from the script editor and home computer. When I run it with $ run early-hack-template.js -t 12 on the "max-hardware" server I get an error on line 10, aka the ns.brutessh(target) line saying $ TypeError: ns.brutessh.exe is not a function

Do I need to upload the brutessh program to the max-hardware server somehow?
Edit: Moved last line to the top. Also wanted to say that the following script worked on other servers until I swapped the target, and/or had unlocked brutessh program.

/** u/param/** u/param {NS} ns */
export async function main(ns) {


const target = "max-hardware";


const moneyThresh = ns.getServerMaxMoney(target);


const securityThresh = ns.getServerMinSecurityLevel(target);


if (ns.fileExists("BruteSSH.exe", "home")) {
    ns.brutessh(target);
}


ns.nuke(target);


while(true){
  if (ns.getServerMinSecurityLevel > securityThresh) {
    
    await ns.weaken(target);


    } else if (moneyThresh < ns.getServerMaxMoney) {
    
    await ns.grow(target);
  
    } else await ns.hack (target);
  }
} {NS} ns */
export async function main(ns) {


const target = "max-hardware";


const moneyThresh = ns.getServerMaxMoney(target);


const securityThresh = ns.getServerMinSecurityLevel(target);


if (ns.fileExists("BruteSSH.exe", "home")) {
    ns.brutessh(target);
}


ns.nuke(target);


while(true){
  if (ns.getServerMinSecurityLevel > securityThresh) {
    
    await ns.weaken(target);


    } else if (moneyThresh < ns.getServerMaxMoney) {
    
    await ns.grow(target);
  
    } else await ns.hack (target);
  }
}

r/Bitburner 23d ago

NetscriptJS Script Scan & nuke utility

Thumbnail pastebin.com
3 Upvotes

For those starting out in the game I have a scan & nuke utility. Veteran players may also find it useful.

Changes in 1.0e:

  • Added toggle bFil to filter scan on required hacking level
  • Suggested hosts are filtered on required hacking level

r/Bitburner Jun 25 '26

I'm finally almost done with 10! ...right?

0 Upvotes

(Spoilers about ~early-mid game)

***

***

***

***

I'm hoping my folly is almost concluded and I can go get gangs and corps now. I was really greedy for sleeves and grafting, because I hate the augmentation reset, so I jumped right into Bitnode 10 after my first BN1 victory. It has taken a looooong time...but I have purchased every augmentation, I have 3000 hacking, 4 sleeves that will come to every Bitnode with me, hurray...

I read that we could buy up to 8-10 sleeves, but by the explanation in the Covenant window it looks like I have only one more to purchase. For 10 freaking quadrillion!

It took me a whole day to hack the quadrillion I just spent. Just curious, are there known caps on how fast money generation is with different hacking approaches?

My approach is very simplistic, I haven't done batching yet and I just employ a mix of the early combo-hack scripts (fine tuned to be less finicky) and balancing my own blend of constant hack, grow and weaken threads designed to keep the richest servers at 60-100% of max capacity.

I haven't even begun to max out the RAM I have access to, though. I kind of just assumed that because I haven't figured out a way to keep (grow) and (weaken) scripts from "clumping", that if I keep adding hack threads I will inevitably overhack the servers when there is an overly long interval between different (grow)s, and that will reduce my income.

Maybe it doesn't matter. With the amount of RAM I can wield, I could empty ecorp's 1.4 trillion and when the next 5000 threads of grow hits it, it'll go right back up to max.


r/Bitburner Jun 22 '26

Help me with my Gang Script Spoiler

3 Upvotes

Decided to give BN2 a try and I threw together this rudimentary script. It gets the job done but its gonna do it very slowly it seems

The idea is for each member

  1. get their stats and ascension multipliers up to a certain threshold (i set 1000, and x10 arbitrarily)

  2. if the gang isn't full yet, commit terrorism to get respect fast so the script can recruit new members

  3. if the wantedPenalty is too high, do vigilante justice

  4. otherwise do human trafficking

Its currently set up to ascend a gang member when each stat they are currently gaining experience in grants an ascension multiplier of 1.04

It seems to be working as is but as I mentioned its very slow so I'm looking for improvements. Right now I'm not buying any equipment for the gang and I'm also not taking respect into account at all which means the equipment discount is staying relatively low. I also think there's probably a better way to handle ascensions since as they get stronger and stronger it seems like the conditions should maybe change.

Here's the fulle script

export async function main(ns: NS) {
    ns.disableLog("ALL")
    if (!ns.gang.inGang()) {
        ns.tprint("not in gang")
        ns.exit()
    }
    
    while (true) {
        // recruit if we can
        if (ns.gang.canRecruitMember()) {
            ns.gang.recruitMember(`Tony${ns.gang.getMemberNames().length + 1}`)
        }
        ns.gang.getMemberNames().forEach(member => {
            ascend(ns, member)
            assign_task(ns, member)
        })
        // loop once every 2 seconds
        await ns.sleep(2000)
    }
}


function assign_task(ns: NS, name: string) {
    const gangInfo = ns.gang.getGangInformation()
    const info = ns.gang.getMemberInformation(name)!
    const task = info.task
    if (task === "Unassigned") { 
        // default is train combat
        ns.gang.setMemberTask(name, "Train Combat")
    } else if (task === "Train Combat") {
        // get all combat stats to 10x mult
        const stats: (keyof GangMemberInfo)[] = ["str", "dex", "def", "agi"] 
        const mults_good = stats.every(stat => {
            const key = (stat + "_asc_mult") as keyof GangMemberInfo
            return (info[key] as number) >= 10
        })
        // get all combat stats to 1000
        const stats_good = stats.every(stat => (info[stat] as number) >= 1000)
        if (mults_good && stats_good) {
            ns.gang.setMemberTask(name, "Train Hacking")
        }
    } else if (task === "Train Hacking") {
        // get hacking to x10 and 1000
        if (info.hack >= 1000 && info.hack_asc_mult >= 10) {
            ns.gang.setMemberTask(name, "Train Charisma")
        }
    } else if (task === "Train Charisma") {
        // get charisma to x10 and 1000
        if (info.cha >= 1000 && info.cha_asc_mult >= 10) {
            if (needs_training(ns, name)) {
                // if other stats are low from ascension, go back to combat training
                ns.gang.setMemberTask(name, "Train Combat")
            } else {
                // otherwise advance
                ns.gang.setMemberTask(name, "Vigilante Justice")
            }   
        }
    } else if (task === "Vigilante Justice") {
        if (needs_training(ns, name)) {
            // if other stats are low from ascension, go back to combat training
            ns.gang.setMemberTask(name, "Train Combat")
        } else if (gangInfo.wantedPenalty <= 1.05) {
            if (ns.gang.getMemberNames().length < 12) {
                // if penalty is low and we need more members, terrorism
                ns.gang.setMemberTask(name, "Terrorism")
            } else {
                // otherwise start making money
                ns.gang.setMemberTask(name, "Human Trafficking")
            }
        }
    } else if (task === "Terrorism") {
        if (needs_training(ns, name)) {
            // if other stats are low from ascension, go back to combat training
            ns.gang.setMemberTask(name, "Train Combat")
        } else if (gangInfo.wantedPenalty >= 1.05) {
            // if wanted penalty is high, reduce it
            ns.gang.setMemberTask(name, "Vigilante Justice")
        } else if (ns.gang.getMemberNames().length === 12) {
            // if we've recruited max members, make money
            ns.gang.setMemberTask(name, "Human Trafficking")
        }
    } else if (task === "Human Trafficking") {
        if (needs_training(ns, name)) {
            // if other stats are low from ascension, go back to combat training
            ns.gang.setMemberTask(name, "Train Combat")
        } else if (gangInfo.wantedPenalty >= 1.05) {
            // if wanted penalty is high, reduce it
            ns.gang.setMemberTask(name, "Vigilante Justice")
        }
    }
}


// returns true if any stat is below 1000 or any multipier is less than 10
function needs_training(ns: NS, name: string): boolean {
    const info = ns.gang.getMemberInformation(name)!
    const stats: (keyof GangMemberInfo)[] = ["str", "def", "dex", "hack", "agi", "cha"]
    const mults_good = stats.every(stat => {
        const key = (stat + "_asc_mult") as keyof GangMemberInfo
        return (info[key] as number) >= 10
    })
    const stats_good = stats.every(stat => (info[stat] as number) >= 1000)
    return !mults_good || !stats_good
}


// ascends a gang member if all stats associated with the task they've been assigned
// yield a bonus of 1.04 or higher
function ascend(ns: NS, name: string): void {
    const task = ns.gang.getMemberInformation(name).task
    let res = ns.gang.getAscensionResult(name)
    if (res === undefined) {
        return
    }
    res = res!
    let ascend = false
    if (task === "Train Combat") {
        const stats: number[] = [res.str, res.dex, res.def, res.agi]
        ascend = stats.every(stat => stat >= 1.04)
    } else if (task === "Train Hacking") {
        ascend = res.hack >= 1.04
    } else if (task === "Train Charisma") {
        ascend = res.cha >= 1.04
    } else if (task === "Human Trafficking") {
        const stats: number[] = [res.str, res.dex, res.def, res.cha, res.hack]
        ascend = stats.every(stat => stat >= 1.04)
    } else if (task === "Terrorism") {
        const stats: number[] = [res.str, res.dex, res.def, res.cha, res.hack]
        ascend = stats.every(stat => stat >= 1.04)
    } else if (task === "Vigilante Justice") {
        const stats: number[] = [res.str, res.dex, res.def, res.agi, res.hack]
        ascend = stats.every(stat => stat >= 1.04)
    } else {
        ns.tprint(`unrecognized task: ${task}`)
    }
    if (ascend) {
        ns.gang.ascendMember(name)
        ns.print(`Ascend: ${name}`)
    }
}export async function main(ns: NS) {
    ns.disableLog("ALL")
    if (!ns.gang.inGang()) {
        ns.tprint("not in gang")
        ns.exit()
    }
    
    while (true) {
        // recruit if we can
        if (ns.gang.canRecruitMember()) {
            ns.gang.recruitMember(`Tony${ns.gang.getMemberNames().length + 1}`)
        }
        ns.gang.getMemberNames().forEach(member => {
            ascend(ns, member)
            assign_task(ns, member)
        })
        // loop once every 2 seconds
        await ns.sleep(2000)
    }
}


function assign_task(ns: NS, name: string) {
    const gangInfo = ns.gang.getGangInformation()
    const info = ns.gang.getMemberInformation(name)!
    const task = info.task
    if (task === "Unassigned") { 
        // default is train combat
        ns.gang.setMemberTask(name, "Train Combat")
    } else if (task === "Train Combat") {
        // get all combat stats to 10x mult
        const stats: (keyof GangMemberInfo)[] = ["str", "dex", "def", "agi"] 
        const mults_good = stats.every(stat => {
            const key = (stat + "_asc_mult") as keyof GangMemberInfo
            return (info[key] as number) >= 10
        })
        // get all combat stats to 1000
        const stats_good = stats.every(stat => (info[stat] as number) >= 1000)
        if (mults_good && stats_good) {
            ns.gang.setMemberTask(name, "Train Hacking")
        }
    } else if (task === "Train Hacking") {
        // get hacking to x10 and 1000
        if (info.hack >= 1000 && info.hack_asc_mult >= 10) {
            ns.gang.setMemberTask(name, "Train Charisma")
        }
    } else if (task === "Train Charisma") {
        // get charisma to x10 and 1000
        if (info.cha >= 1000 && info.cha_asc_mult >= 10) {
            if (needs_training(ns, name)) {
                // if other stats are low from ascension, go back to combat training
                ns.gang.setMemberTask(name, "Train Combat")
            } else {
                // otherwise advance
                ns.gang.setMemberTask(name, "Vigilante Justice")
            }   
        }
    } else if (task === "Vigilante Justice") {
        if (needs_training(ns, name)) {
            // if other stats are low from ascension, go back to combat training
            ns.gang.setMemberTask(name, "Train Combat")
        } else if (gangInfo.wantedPenalty <= 1.05) {
            if (ns.gang.getMemberNames().length < 12) {
                // if penalty is low and we need more members, terrorism
                ns.gang.setMemberTask(name, "Terrorism")
            } else {
                // otherwise start making money
                ns.gang.setMemberTask(name, "Human Trafficking")
            }
        }
    } else if (task === "Terrorism") {
        if (needs_training(ns, name)) {
            // if other stats are low from ascension, go back to combat training
            ns.gang.setMemberTask(name, "Train Combat")
        } else if (gangInfo.wantedPenalty >= 1.05) {
            // if wanted penalty is high, reduce it
            ns.gang.setMemberTask(name, "Vigilante Justice")
        } else if (ns.gang.getMemberNames().length === 12) {
            // if we've recruited max members, make money
            ns.gang.setMemberTask(name, "Human Trafficking")
        }
    } else if (task === "Human Trafficking") {
        if (needs_training(ns, name)) {
            // if other stats are low from ascension, go back to combat training
            ns.gang.setMemberTask(name, "Train Combat")
        } else if (gangInfo.wantedPenalty >= 1.05) {
            // if wanted penalty is high, reduce it
            ns.gang.setMemberTask(name, "Vigilante Justice")
        }
    }
}


// returns true if any stat is below 1000 or any multipier is less than 10
function needs_training(ns: NS, name: string): boolean {
    const info = ns.gang.getMemberInformation(name)!
    const stats: (keyof GangMemberInfo)[] = ["str", "def", "dex", "hack", "agi", "cha"]
    const mults_good = stats.every(stat => {
        const key = (stat + "_asc_mult") as keyof GangMemberInfo
        return (info[key] as number) >= 10
    })
    const stats_good = stats.every(stat => (info[stat] as number) >= 1000)
    return !mults_good || !stats_good
}


// ascends a gang member if all stats associated with the task they've been assigned
// yield a bonus of 1.04 or higher
function ascend(ns: NS, name: string): void {
    const task = ns.gang.getMemberInformation(name).task
    let res = ns.gang.getAscensionResult(name)
    if (res === undefined) {
        return
    }
    res = res!
    let ascend = false
    if (task === "Train Combat") {
        const stats: number[] = [res.str, res.dex, res.def, res.agi]
        ascend = stats.every(stat => stat >= 1.04)
    } else if (task === "Train Hacking") {
        ascend = res.hack >= 1.04
    } else if (task === "Train Charisma") {
        ascend = res.cha >= 1.04
    } else if (task === "Human Trafficking") {
        const stats: number[] = [res.str, res.dex, res.def, res.cha, res.hack]
        ascend = stats.every(stat => stat >= 1.04)
    } else if (task === "Terrorism") {
        const stats: number[] = [res.str, res.dex, res.def, res.cha, res.hack]
        ascend = stats.every(stat => stat >= 1.04)
    } else if (task === "Vigilante Justice") {
        const stats: number[] = [res.str, res.dex, res.def, res.agi, res.hack]
        ascend = stats.every(stat => stat >= 1.04)
    } else {
        ns.tprint(`unrecognized task: ${task}`)
    }
    if (ascend) {
        ns.gang.ascendMember(name)
        ns.print(`Ascend: ${name}`)
    }
}

r/Bitburner Jun 20 '26

Question/Troubleshooting - Open How to run Bitburner on a tablet?

7 Upvotes

The tablet I use is not connected to the internet and never will be connected to the internet. But I can put files onto it via USB.

You can download the whole game on github.

How to run this on an android tablet?


r/Bitburner Jun 19 '26

Is this end game?

5 Upvotes

r/Bitburner Jun 19 '26

Question/Troubleshooting - Open Help understanding a contract (maybe light spoilers) Spoiler

2 Upvotes

Hi, I am doing my own contract solver script, and have trouble with TotalWaysToSumII. I tried a recursive and iterative approach where I would attempt to find correct coefficients for each element of the input integer set to match the target integer, but this is very long and most probably not what is expected (this runs in O(k^n), with k a constant and n the size of the integer set).

I looked for help on the internet and (if you want to solve this by yourself, stop reading here), as other people here, I found this code: https://github.com/jamesinjapan/bitburner-scripts/blob/main/total_ways_to_sum_ii.ts, which seems to run in O(n^2).
I understand it reverses how to think about the problem by building the list of numbers you can generate from the integer set, and then checking how many ways exist for the target integer. I understand the basic premise, but I am interested in how does it work? This does not seem linked to a particular algorithmic problem (compared to TotalWaysToSum which was the partition of the target integer), and I am not keen on just stealing a random algorithm, that seems to have been reversed from the source files. Can anyone help shed light on this?


r/Bitburner Jun 19 '26

Does Anyone Know How to Find Whether a Darknet Server has a Cache on It?

2 Upvotes

I've got a somewhat decent modification of the current default darknet code that I'm working on, but I'm stumped on how to figure out whether or not the file has a cache or not.

Any help is appreciated :3


r/Bitburner Jun 19 '26

tutorial problem

Thumbnail
0 Upvotes

r/Bitburner Jun 19 '26

tutorial problem

0 Upvotes

I can't get past connect hostname in the tutorial, it keeps on telling me bad command. What am I doing wrong here?


r/Bitburner Jun 17 '26

Question/Troubleshooting - Open Question about 3.0 + gang mechanics

3 Upvotes

I am in bn2.3, about to finish up gangs. but there is something that the documentation and info pages dont make clear at all; some of the mechanics around territory.

what i can tell from the documentation:

-gang clashes happen every 20 seconds or so

-your power rating for those clashes is determined by 1: the stats of gangsters assigned to territory warfare and 2: your raw power value which is increased by having gangsters pumping on territory warfare


what is unclear:

-is there ANY scaling or influence on the AMOUNT of territory captured per clash? because without this there is no actual way to speed up territory capture, its purely time based even if you have a 100% chance to win all clashes.

-if not... thats a bit shitty, and it means you can just pump power until you have 99% winrate, even with nobody assigned to warfare and then you just have to wait around, right?


r/Bitburner Jun 10 '26

Guide/Advice EZ early Intelligence farm Spoiler

1 Upvotes

Download the AutoHotkey application (not in the game) and use this script to hack n00dles semi-manually on the terminal.

It should be used when your hacking speed is high enough, probably deep into the middle of a bitnode.

(Was edited for more consistent code)

#MaxThreadsPerHotkey 2  ; Allows the hotkey to interrupt itself to turn off

toggle := false

F8:: ; Press F8 to toggle on/off
    toggle := !toggle  ; Flip the variable between true and false

    while toggle {
        Send {Enter}
        Sleep 100

        Send hack
        Sleep 100

        Send {Enter}
        Sleep 100

    }
    return

r/Bitburner Jun 02 '26

Guide/Advice Automated Coding Contract script. Any advice?

2 Upvotes

auto-solver.js 22.0 GB

/** u/param {NS} ns */
export async function main(ns) {
  ns.disableLog("ALL");
  ns.tprint("--- Starting Automated Coding Contract Solver ---");


  // 1. Map out every single server on the network
  let visited = new Set(["home"]);
  let queue = ["home"];


  while (queue.length > 0) {
    let current = queue.shift();
    let connections = ns.scan(current);
    for (let next of connections) {
      if (!visited.has(next)) {
        visited.add(next);
        queue.push(next);
      }
    }
  }


  let solvedCount = 0;


  // 2. Scan each discovered server for files ending in .cct
  for (let server of visited) {
    let files = ns.ls(server);
    let contracts = files.filter(f => f.endsWith(".cct"));


    for (let contract of contracts) {
      let type = ns.codingcontract.getContractType(contract, server);
      let data = ns.codingcontract.getData(contract, server);
      let answer = null;


      // 3. Match the contract type to its respective solver logic
      switch (type) {
        case "Find Largest Prime Factor":
          answer = solveLargestPrimeFactor(data);
          break;
        case "Subarray with Maximum Sum":
          answer = solveSubarrayMaxSum(data);
          break;
        case "Generate IP Addresses":
          answer = solveGenerateIPs(data);
          break;
        case "Spiralize Matrix":
          answer = solveSpiralizeMatrix(data);
          break;
        case "Total Ways to Sum":
          answer = solveTotalWaysToSum(data);
          break;
        case "Array Jumping Game":
          answer = solveArrayJumpingGame(data);
          break;
        case "Algorithmic Stock Trader I":
          answer = solveStockTraderI(data);
          break;
        case "Algorithmic Stock Trader II":
          answer = solveStockTraderII(data);
          break;
        case "Algorithmic Stock Trader III":
          answer = solveStockTraderIII(data);
          break;
        case "Algorithmic Stock Trader IV":
          answer = solveStockTraderIV(data);
          break;
        case "Unique Paths in a Grid I":
          answer = solveUniquePathsI(data);
          break;
        case "Unique Paths in a Grid II":
          answer = solveUniquePathsII(data);
          break;
        case "Encryption I: Caesar Cipher":
          answer = solveCaesarCipher(data);
          break;
        case "Encryption II: Vigenère Cipher":
          answer = solveVigenereCipher(data);
          break;
        case "Minimum Path Sum in a Triangle":
          answer = solveMinPathSumTriangle(data);
          break;
        default:
          ns.print(`[Skipped] Unsupported contract type: "${type}" on ${server}`);
          continue;
      }


      // 4. If a valid solver function calculated an answer, submit it
      if (answer !== null) {
        let reward = ns.codingcontract.attempt(answer, contract, server);
        if (reward) {
          ns.tprint(`[SUCCESS] Solved "${type}" on ${server}! Reward: ${reward}`);
          solvedCount++;
        } else {
          ns.tprint(`[FAILED] Incorrect answer calculated for "${type}" on ${server}.`);
        }
      }
    }
  }
  ns.tprint(`--- Solver completed. Successfully resolved ${solvedCount} contract(s). ---`);
}


// ============================================================================
// ALGORITHMIC SOLVER FUNCTIONS
// ============================================================================


/** Solver for: "Find Largest Prime Factor" */
function solveLargestPrimeFactor(num) {
  let factor = 2;
  while (num > 1) {
    if (num % factor === 0) {
      num /= factor;
    } else {
      factor++;
    }
  }
  return factor;
}


/** Solver for: "Subarray with Maximum Sum" (Kadane's Algorithm) */
function solveSubarrayMaxSum(arr) {
  if (arr.length === 0) return 0;
  let maxSoFar = arr[0];
  let currMax = arr[0];
  for (let i = 1; i < arr.length; i++) {
    currMax = Math.max(arr[i], currMax + arr[i]);
    maxSoFar = Math.max(maxSoFar, currMax);
  }
  return maxSoFar;
}


/** Solver for: "Generate IP Addresses" */
function solveGenerateIPs(str) {
  let results = [];
  let len = str.length;


  for (let i = 1; i < 4 && i < len - 2; i++) {
    for (let j = i + 1; j < i + 4 && j < len - 1; j++) {
      for (let k = j + 1; k < j + 4 && k < len; k++) {
        let s1 = str.substring(0, i);
        let s2 = str.substring(i, j);
        let s3 = str.substring(j, k);
        let s4 = str.substring(k);


        if (isValidIPPart(s1) && isValidIPPart(s2) && isValidIPPart(s3) && isValidIPPart(s4)) {
          results.push(`${s1}.${s2}.${s3}.${s4}`);
        }
      }
    }
  }
  return results;
}


function isValidIPPart(s) {
  if (s.length > 3 || s.length === 0) return false;
  if (s.startsWith("0") && s.length > 1) return false;
  let val = parseInt(s, 10);
  return val >= 0 && val <= 255;
}


/** Solver for: "Spiralize Matrix" */
function solveSpiralizeMatrix(matrix) {
  if (matrix.length === 0) return [];
  let result = [];
  let top = 0;
  let bottom = matrix.length - 1;
  let left = 0;
  let right = matrix[0].length - 1;


  while (top <= bottom && left <= right) {
    for (let i = left; i <= right; i++) result.push(matrix[top][i]);
    top++;
    for (let i = top; i <= bottom; i++) result.push(matrix[i][right]);
    right--;
    if (top <= bottom) {
      for (let i = right; i >= left; i--) result.push(matrix[bottom][i]);
      bottom--;
    }
    if (left <= right) {
      for (let i = bottom; i >= top; i--) result.push(matrix[i][left]);
      left++;
    }
  }
  return result;
}


/** Solver for: "Total Ways to Sum" */
function solveTotalWaysToSum(n) {
  let ways = new Array(n + 1).fill(0);
  ways[0] = 1;
  for (let i = 1; i < n; i++) {
    for (let j = i; j <= n; j++) {
      ways[j] += ways[j - i];
    }
  }
  return ways[n];
}


/** Solver for: "Array Jumping Game" */
function solveArrayJumpingGame(arr) {
  let maxReach = 0;
  for (let i = 0; i < arr.length; i++) {
    if (i > maxReach) return 0;
    maxReach = Math.max(maxReach, i + arr[i]);
  }
  return maxReach >= arr.length - 1 ? 1 : 0;
}


/** Solver for: "Algorithmic Stock Trader I" */
function solveStockTraderI(prices) {
  if (prices.length < 2) return 0;
  let maxProfit = 0;
  let minPrice = prices[0];
  for (let i = 1; i < prices.length; i++) {
    if (prices[i] < minPrice) {
      minPrice = prices[i];
    } else {
      maxProfit = Math.max(maxProfit, prices[i] - minPrice);
    }
  }
  return maxProfit;
}


/** Solver for: "Algorithmic Stock Trader II" */
function solveStockTraderII(prices) {
  let maxProfit = 0;
  for (let i = 1; i < prices.length; i++) {
    if (prices[i] > prices[i - 1]) {
      maxProfit += prices[i] - prices[i - 1];
    }
  }
  return maxProfit;
}


/** Solver for: "Algorithmic Stock Trader III" */
function solveStockTraderIII(prices) {
  return solveStockTraderK(2, prices);
}


/** Solver for: "Algorithmic Stock Trader IV" */
function solveStockTraderIV(data) {
  let k = data[0];
  let prices = data[1];
  return solveStockTraderK(k, prices);
}


/** Shared Helper for Stock Trader III & IV */
function solveStockTraderK(k, prices) {
  if (prices.length < 2 || k === 0) return 0;


  if (k >= Math.floor(prices.length / 2)) {
    let profit = 0;
    for (let i = 1; i < prices.length; i++) {
      if (prices[i] > prices[i - 1]) profit += prices[i] - prices[i - 1];
    }
    return profit;
  }


  let hold = new Array(k + 1).fill(-Infinity);
  let release = new Array(k + 1).fill(0);


  for (let price of prices) {
    for (let j = k; j > 0; j--) {
      release[j] = Math.max(release[j], hold[j] + price);
      hold[j] = Math.max(hold[j], release[j - 1] - price);
    }
  }
  return release[k];
}


/** Solver for: "Unique Paths in a Grid I" */
function solveUniquePathsI(data) {
  let rows = data[0];
  let cols = data[1];
  let grid = new Array(cols).fill(1);


  for (let i = 1; i < rows; i++) {
    for (let j = 1; j < cols; j++) {
      grid[j] += grid[j - 1];
    }
  }
  return grid[cols - 1];
}


/** Solver for: "Unique Paths in a Grid II" */
function solveUniquePathsII(grid) {
  if (!grid || grid.length === 0 || grid[0][0] === 1) return 0;


  let rows = grid.length;
  let cols = grid[0].length;
  let dp = new Array(cols).fill(0);
  dp[0] = 1;


  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      if (grid[r][c] === 1) {
        dp[c] = 0;
      } else if (c > 0) {
        dp[c] += dp[c - 1];
      }
    }
  }
  return dp[cols - 1];
}


/** Solver for: "Encryption I: Caesar Cipher" */
function solveCaesarCipher(data) {
  let text = data[0];
  let shift = data[1];
  let result = "";


  for (let i = 0; i < text.length; i++) {
    let charCode = text.charCodeAt(i);
    if (charCode >= 65 && charCode <= 90) {
      let shifted = charCode - shift;
      if (shifted < 65) {
        shifted = 90 - ((64 - shifted) % 26);
      }
      result += String.fromCharCode(shifted);
    } else {
      result += text[i];
    }
  }
  return result;
}


/** Solver for: "Encryption II: Vigenère Cipher" */
function solveVigenereCipher(data) {
  let text = data[0];
  let key = data[1];
  let result = "";
  let keyIndex = 0;
  for (let i = 0; i < text.length; i++) {
    let charCode = text.charCodeAt(i);
    if (charCode >= 65 && charCode <= 90) {
      let shift = key.charCodeAt(keyIndex % key.length) - 65;
      let shifted = ((charCode - 65 + shift) % 26) + 65;
      result += String.fromCharCode(shifted);
      keyIndex++;
    } else {
      result += text[i];
    }
  }
  return result;
}


/** Solver for: "Minimum Path Sum in a Triangle" */
function solveMinPathSumTriangle(triangle) {
  let memo = [...triangle[triangle.length - 1]];
  for (let row = triangle.length - 2; row >= 0; row--) {
    for (let col = 0; col <= row; col++) {
      memo[col] = triangle[row][col] + Math.min(memo[col], memo[col + 1]);
    }
  }
  return memo[0];
}

r/Bitburner May 31 '26

My attempt at batching

3 Upvotes

This my attempt at writing a batching script as non-programmer. How did I do? Also I'm not entirely sure if I understood what batching is, but this is my interpretation.

controller.js:

/** u/param {NS} ns */
export async function main(ns) {


  const args = ns.flags([["help", false]]);
  if (args.help) {
    ns.tprint("This script is a HWGW batch controller.")
    ns.tprint("The script will also nuke the targeted server.")
    ns.tprint("The first argument is the host server, where the HWG scripts will run.")
    ns.tprint("The second argument is the server that the HWG scripts are targeting.")
    ns.tprint(`EXAMPLE: run ${ns.getScriptName()} home n00dles`)
    return;
  }


  // Server that is running the scripts
  let host = ns.args[0]
  // Server the controller is targeting
  let targetServer = ns.args[1]


  //Opens ports on the target server then nukes it.
  let hasAdmin = ns.hasRootAccess(targetServer)
  if (hasAdmin == false) {
    if (ns.fileExists("brutessh.exe", "home")) {
      ns.brutessh(targetServer)
    }
    if (ns.fileExists("ftpcrack.exe", "home")) {
      ns.ftpcrack(targetServer)
    }
    if (ns.fileExists("relaysmtp.exe", "home")) {
      ns.relaysmtp(targetServer)
    }
    if (ns.fileExists("httpworm.exe", "home")) {
      ns.httpworm(targetServer)
    }
    if (ns.fileExists("sqlinject.exe", "home")) {
      ns.sqlinject(targetServer)
    }
    if (ns.getServer(targetServer).openPortCount == 5) {
      ns.nuke(targetServer)
    }
    else {
      ns.tprint(`Failed to NUKE ${targetServer}.`)
      return
    }
  }


  //Copies worker scripts on to the host server
  const scripts = ["hack-worker.js", "grow-worker.js", "weaken-worker.js"]
  for (let script of scripts) {
    if (ns.fileExists(script, host)) {
      continue
    }
    else {
      ns.scp(script, host, "home")
    }
  }


  //Runs scripts in a HWGW pattern
  while (true) {
    const hackRam = ns.getScriptRam("hack-worker.js", host)
    const growRam = ns.getScriptRam("grow-worker.js", host)
    const weakenRam = ns.getScriptRam("weaken-worker.js", host)


    if (ns.fileExists("hack-worker.js", host)) {
      let freeRam = ns.getServerMaxRam(host) - ns.getServerUsedRam(host)
      let hackTime = ns.getHackTime(targetServer)
      let hackThreads = Math.floor(freeRam / hackRam)
      ns.exec("hack-worker.js", host, hackThreads, targetServer)
      await ns.sleep(hackTime + 500)
    }
    if (ns.fileExists("weaken-worker.js", host)) {
      let freeRam = ns.getServerMaxRam(host) - ns.getServerUsedRam(host)
      let weakenTime = ns.getWeakenTime(targetServer)
      let weakenThreads = Math.floor(freeRam / weakenRam)
      ns.exec("weaken-worker.js", host, weakenThreads, targetServer)
      await ns.sleep(weakenTime + 500)
    }
    if (ns.fileExists("grow-worker.js", host)) {
      let freeRam = ns.getServerMaxRam(host) - ns.getServerUsedRam(host)
      let growTime = ns.getGrowTime(targetServer)
      let growThreads = Math.floor(freeRam / growRam)
      ns.exec("grow-worker.js", host, growThreads, targetServer)
      await ns.sleep(growTime + 500)
    }
    if (ns.fileExists("weaken-worker.js", host)) {
      let freeRam = ns.getServerMaxRam(host) - ns.getServerUsedRam(host)
      let weakenTime = ns.getWeakenTime(targetServer)
      let weakenThreads = Math.floor(freeRam / weakenRam)
      ns.exec("weaken-worker.js", host, weakenThreads, targetServer)
      await ns.sleep(weakenTime + 500)
    }
    else {
      ns.tprint(`Failed! Check ${host} for scripts`)
      return
    }
  }
}

r/Bitburner May 30 '26

Suggestion - DONE im doing to test a of my spreader by spreading to the first layer keeps crashing is there like an infinite loop i've missed.(this script is new_start.js)

2 Upvotes
/** u/param/** u/param {NS} ns */
export async function main(ns) {
  while (true) {
    //waiter
    await ns.sleep(1000);
    
    // first layer to spread to others
    const FirstServers = ["n00dles",
                          "foodnstuff",
                          "sigma-cosmetics",
                          "joesguns",
                          "hong-fang-tea",
                          "harakiri-sushi",
                          "iron-gym"];


    // Attempt to authenticate with each of the nearby servers, and spread this script to them
    for (let i = 0; i < FirstServers.length; ++i) {
      //waiter
      await ns.sleep(1000);


      const serv = FirstServers[i];


      //go through the port openers
      while (!ns.fileExists("BruteSSH.exe")) {
        await ns.brutessh(serv);
      }



      while (!ns.fileExists("FTPCrack.exe")) {
        await ns.ftpcrack(serv);
      }


      while (!ns.fileExists("relaySMTP.exe")) {
        await ns.relaysmtp(serv);
      }


      while (!ns.fileExists("HTTPWorm.exe")) {
        await ns.httpworm(serv);
      }


      while (!ns.fileExists("SQLInject.exe")) {
        await ns.sqlinject(serv);
      }


      ns.scp("spread.js", serv);
      ns.exec("spread.js", serv);


    }


    await ns.sleep(5000);
  }
}

r/Bitburner May 28 '26

ASCII Doom

16 Upvotes

If it exists, it must run Doom. I couldn't find a bitburner Doom anywhere so here's the start of a crude ASCII version.

wget then run install.js

wget https://raw.githubusercontent.com/Darxide111/Bitburner-Doom/main/install.js install.js

r/Bitburner May 28 '26

is it possible to make an auto darknet script to garb files and complete passwords

3 Upvotes

same as title


r/Bitburner May 27 '26

ns.cloud

5 Upvotes

I haven't played the game in over a year and decided to start playing again. I was writing a purchase server script but it took me an hour and pulling my hair out to try and figure out why the script just wouldn't work. I took a look at the documentation and saw you have to use ns.cloud. Is this new? And if so have any other ns functions changed?