Skip to content

Instantly share code, notes, and snippets.

@bglopez
Forked from 80sVectorz/rscan.js
Created May 25, 2023 17:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bglopez/1eed7603423ad7822e562a18094403ea to your computer and use it in GitHub Desktop.
Save bglopez/1eed7603423ad7822e562a18094403ea to your computer and use it in GitHub Desktop.
Recursive scan terminal command for outputing an ascii tree representation of the network.
//Bitburner script: https://github.com/bitburner-official/bitburner-src https://store.steampowered.com/app/1812820/Bitburner/
//Recursive scan terminal command for displaying an ascii art tree representation of the full network:
// rscan --detailed
// -------------------Network Tree-------------------|-|Balance|-|Hack Chance|-|Security LVL|-|Root?|
// home----------------------------------------------| $387.370m 99% 1% [X]
// ├─n00dles | $62.856k 99% 1% [X]
// │ ├─zer0------------------------------------------| $3.717m 75% 8% [X]
// │ │ ├─silver-helix | $20.868m 57% 11% [X]
// . . . . ... ... ... ...
// . . . . ... ... ... ...
//Add as command: alias rscan="run {path to rscan}"
//For more info use: rscan --help
//Created by 80sVectorz
function find_greatest_depth(tree,depth,greatest_depth){
greatest_depth = Math.max(depth,greatest_depth);
for (var i = 0; i < tree.length; i++) {
if (Array.isArray(tree[i])) {
greatest_depth=find_greatest_depth(tree[i],depth+1,greatest_depth);
}
}
return greatest_depth;
}
function find_longest_name(tree,longest_name){
for (var i = 0; i < tree.length; i++) {
if (Array.isArray(tree[i])) {
longest_name=find_longest_name(tree[i],longest_name);
} else {
longest_name=Math.max(tree[i].length,longest_name);
}
}
return longest_name;
}
function rscan(ns, prev_res,depth,passed_servers) {
var results = [];
for (var i = 0; i < prev_res.length; i++) {
if (Array.isArray(prev_res[i])) {
results.push(rscan(ns, prev_res[i],depth+1,passed_servers));
} else {
if (passed_servers.includes(prev_res[i])) {
continue;
}
results.push(prev_res[i]);
passed_servers.push(prev_res[i]);
var res = ns.scan(prev_res[i]);
if (res.length > 1) {
results.push(rscan(ns, res,depth+1,passed_servers));
}
}
}
return results;
}
function format_results(ns, results, depth, detailed,current_roots,detail_margin,n) {
var n = n;
let lines = [];
let last_node = 0;
for (var i = 0; i < results.length; i++) {
if (!Array.isArray(results[i])) {
last_node = i;
}
}
for (var i = 0; i < results.length; i++) {
if (Array.isArray(results[i])) {
var out = format_results(ns, results[i], depth + 1, detailed,current_roots,detail_margin,n);
n = out[1];
lines.push(out[0]);
} else {
n++;
var deco = `├─`;
deco = `${current_roots.slice(1,depth).join("").replaceAll("0", " ").replaceAll("1", "│ ")}${deco}`;
if (i == last_node) {
deco = deco.replace('├', '└');
current_roots[depth] = "0";
}else{
current_roots[depth] = "1";
}
if (depth == 0) {
deco = ``;
}
if(n==1 && detailed){
var balance = "|Balance|";
var hack_chance = "|Hack Chance|";
var security_lvl = "|Security LVL|";
var root_access = "|Root?|";
var center = Math.round((current_roots.length*2+detail_margin)/2);
var body = `${"-".repeat(center-6)}Network Tree`.padEnd(current_roots.length*2+detail_margin,"-");
lines.push(`\n${body}|-${balance}-${hack_chance}-${security_lvl}-${root_access}`);
}
if (detailed) {
var balance = ns.formatNumber(ns.getServerMoneyAvailable(results[i]),3).padEnd(6+1+1+6);//digits+ . +size symbol+margin
var hack_chance = ns.formatPercent(ns.hackAnalyzeChance(results[i]),0).padEnd(3+1+10);//digits+ % + margin
var security_lvl = ns.formatPercent(ns.getServerSecurityLevel(results[i]) / 100,0).padEnd(3+1+7);//digits+ % + margin
var root_access = ns.hasRootAccess(results[i]) ? "[X]" : "";
var delimeter = n%2==0 ? " " : "-";
var body = `${deco}${results[i]}`.padEnd(current_roots.length*2+detail_margin,delimeter);
lines.push(`\n${body}| \$${balance}${hack_chance}${security_lvl}${root_access}`);
} else {
lines.push(`\n${deco}${results[i]}`);
}
}
}
return [lines.join(""),n];
}
/** @param {NS} ns */
export async function main(ns) {
let passed_servers = ["home"];
let current_roots = [];
let greatest_depth = 0;
let longest_name = 0;
let detailed_mode = false;
if (ns.args.length == 0) {
detailed_mode = false;
} else if(ns.args.length == 1) {
if(["-h","--help"].includes(`${ns.args[0]}`)){
help_message(ns);
}
if(["-d","--detailed"].includes(`${ns.args[0]}`)){
detailed_mode = true;
} else {
ns.tprint("Invalid usage of rscan. for more info on rscan use: rscan --help");
ns.exit();
}
} else {
ns.tprint("Invalid usage of rscan. for more info on rscan use: rscan --help");
ns.exit();
}
var home_scan = ns.scan("home");
var results = rscan(ns, home_scan,0,passed_servers);
greatest_depth = find_greatest_depth(results,2,greatest_depth);
longest_name = find_longest_name(results,longest_name);
for(var i=0;i<greatest_depth;i++){
current_roots.push("1");
}
var output = format_results(ns, ["home"].concat([results]), 0, detailed_mode,current_roots,longest_name,0)[0];
ns.tprint(`\nRscan Results:\n ${output}`);
ns.exit();
}
function help_message(ns){
ns.tprint(
`
--------------------------------------------------------------------
Help message for rscan.js script.
Assumes the use of an alias.
--------------------------------------------------------------------
Ussage: rscan 1: help[-h|--h] detailed[-d|--detailed].
Examples:
With detailed mode: rscan --d
Without detailed mode : rscan
Show this message: rscan --help
--------------------------------------------------------------------
Terms:
Detailed mode: Show more info like balance and security lvl.
help flags -h & --h: Print this message.
`);
ns.exit();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment