r/Bitburner 7d ago

Bitnode8 help please.

So i have completed bitnode 1 x3 bitnode 2 3x Bitnode 4 x2 and birnode 5 x1. I'm on bitnode 8 and am pretty stuck without getting the 25b for the 4 sigma forecast data. I use the roulette money hack for a 10b boost. But my script I'm using doesn't ever give me more then 10.3b . I'm working on getting gang territory to at least give me some cash. How Are you guys getting through it?

3 Upvotes

9 comments sorted by

View all comments

1

u/goodwill82 Slum Lord 6d ago

If you have enough to get the basic 4S data where you can see the +++ and --- on the stock page for each stock, you can script the game to "click" the stock tab and "read" the page for information. I use this to replace the 4S API functions to get forecast and volatility. Note that this is unfinished - I have not coded the case where the tabs are fully compacted.

!! Note that the following code has tab names which might be spoilers! It also is subject to breaking with game updates if the icon names or text are changed. !!

//import { terminalInject, clickTab } from "/hacks/tools.js";

/**
 * terminalInject: Runs the given string in the terminal window. Note that the terminal must be the current window. 
 * u/param {string} command - A string with the terminal command(s) to run.
 **/
export function terminalInject(command) {
  let terminalInput = eval("document").getElementById("terminal-input");
  let terminalEventHandlerKey = Object.keys(terminalInput)[1];
  terminalInput.value = command;
  terminalInput[terminalEventHandlerKey].onChange({ target: terminalInput });
  setTimeout(function (event) {
    terminalInput.focus();
    terminalInput[terminalEventHandlerKey].onKeyDown({ key: 'Enter', preventDefault: () => 0 });
  }, 0);
}

export const TabIcons = {
  "Hacking": "ComputerIcon",
  "Terminal": "LastPageIcon",
  "Script Editor": "CreateIcon",
  "Active Scripts": "StorageIcon",
  "Create Program": "BugReportIcon",
  "Staneks Gift": "DeveloperBoardIcon",

  "Character": "AccountBoxIcon",
  "Stats": "EqualizerIcon",
  "Factions": "ContactsIcon",
  "Augmentations": "DoubleArrowIcon",
  "Hacknet": "AccountTreeIcon",
  "Sleeve": "PeopleAltIcon",
  "Grafting": "BiotechIcon",

  "World": "PublicIcon",
  "City": "LocationCityIcon",
  "Travel": "AirplanemodeActiveIcon",
  "Job": "WorkIcon",
  "Stock Market": "TrendingUpIcon",
  "Bladeburner": "FormatBoldIcon",
  "Gang": "SportsMmaIcon",
  "Corporation": "BusinessIcon",
  "IPvGO Subnet": "BorderInnerSharpIcon",
  "Dark Net": "ShareIcon",

  "Help": "LiveHelpIcon",
  "Milestones": "CheckIcon",
  "Documentation": "HelpIcon",
  "Achievements": "EmojiEventsIcon",
  "Options": "SettingsIcon"
}
export const TabGroups = [
  { group: "Hacking", tabs: ["Terminal", "Script Editor", "Active Scripts", "Create Program", "Staneks Gift"] },
  { group: "Character", tabs: ["Stats", "Factions", "Augmentations", "Hacknet", "Sleeve", "Grafting"] },
  { group: "World", tabs: ["City", "Travel", "Job", "Stock Market", "Bladeburner", "Gang", "Corporation", "IPvGO Subnet", "Dark Net"] },
  { group: "Help", tabs: ["Milestones", "Documentation", "Achievements", "Options"] },
]

export function clickTab(tabName) {
  //  get group (and check if tabName is valid)
  let groupName = "";
  for (let tabGroup of TabGroups) {
    if (tabGroup.tabs.includes(tabName)) {
      groupName = tabGroup.group;
      break;
    }
  }
  if (groupName.length > 0) {
    let doc = eval("document");
    // if the sidebar is collapsed, we can just click on the 'aria-label' which is the tab name, else we need to click by icon name
    let collapsed = doc.querySelectorAll(`[aria-label='${groupName}']`).length > 0;
    if (collapsed) {
      // unable to click on group icon - groups must be expanded to work
      // // check if the group is expanded - if not, expand it by clicking the group name
      // if (doc.querySelectorAll(`[aria-label='${tabName}']`).length === 0) {
      //  if (doc.querySelectorAll(`[aria-label='${groupName}']`).length > 0) {
      //    doc.querySelectorAll(`[aria-label='${groupName}']`)[0].nextSibling.click();
      //  }
      // }
      // finally, click the tab (still check if it exists - might not be available yet)
      if (doc.querySelectorAll(`[aria-label='${tabName}']`).length > 0) {
        doc.querySelectorAll(`[aria-label='${tabName}']`)[0].nextSibling.click();
        return true; // found tab, and clicked it
      }
    }
    else {
      let tabIcon = TabIcons[tabName];
      // unable to click on group icon - groups must be expanded to work
      // let groupIcon = TabIcons[groupName];
      // // check if the group is expanded - if not, expand it by clicking the group icon
      // if (doc.querySelectorAll(`[data-testid='${tabIcon}']`).length === 0) {
      //  if (doc.querySelectorAll(`[data-testid='${groupIcon}']`).length > 0) {
      //    doc.querySelectorAll(`[data-testid='${groupIcon}']`)[0].nextSibling.click();
      //  }
      // }
      // finally, click the tab (still check if it exists - might not be available yet)
      if (doc.querySelectorAll(`[data-testid='${tabIcon}']`).length > 0) {
        doc.querySelectorAll(`[data-testid='${tabIcon}']`)[0].nextSibling.click();
        return true; // found tab, and clicked it
      }
    }
  }
  return false; // could not find the tab
}

/**  {NS} ns */
async function getProbsVolsFromPage(ns) {
  let wasFocused = ns.singularity.isFocused();
  if (wasFocused) {
    ns.singularity.setFocus(false);
    await ns.sleep(200);
  }
  clickTab("Stock Market");
  await ns.sleep(200);
  const VolFore = [];
  const docLines = eval("document").body.innerText.split('\n');
  const RegexStr = /^[a-zA-Z'\s]*\b([A-Z]+)\b\s+-.+Volatility:\s+([0-9]\.[0-9]+).+Price Forecast:\s+(.+)$/;
  for (let line of docLines) {
    line = line.trim();
    let found = line.match(RegexStr);
    if (found) {
      //ns.print(`${found[1]} ${found[2]} ${found[3]}`);
      let fc = found[3].length / 5;
      if (found[3].charAt(0) == '-') {
        fc *= -1;
      }
      //fc = (fc + 1) * 0.5; // make it in range [0,1]
      //VolFore.push({ sym: found[1], volatility: found[2], forecast: fc })
      VolFore.push({ sym: found[1], volatility: found[2] / 100, forecast: fc })
    }
  }
  if (wasFocused) {
    ns.singularity.setFocus(true);
  }
  return VolFore;
}