Clicker Games Click-All

Nice Ted.

Anyone know a better way to buy and manage servers? If I buy a server using the script I have to guess at the price based on the ram I want, so finding a good ram value is hard, and then once purchased I dont see any way to inspect it to see how much ram it has.

If I run a script on it, I can see a rough visualization of what percentage of the ram Im using but that seems like its as good as it gets. Based on the functions available, Im wondering if anyone has created something like a UI for purchasing and browsing servers?

Ram = 55000 per GB in powers of two.
My answer to math is hard is to give the computer a ratio of how much money I want to spend and have it grow to fill that. EDIT: found the newer version. Edit and now I spot that I didn't update the documentation at the top. BUT I AM TRYING TO DOCUMENT! STOP YELLING AT ME TEACHERS IN MY PAST!

Spoiler:
//A script to provision and configure a server. Parameters: Server to target, ratio of player money to set as budget var budget = getPlayer().money * args[1]; var fleetName = args[0]; var loop = 20; //determine best machine within budget while(getPurchasedServerCost(Math.pow(2,loop)) > budget){ loop = loop - 1; } var ram = Math.pow(2,loop); var servername = fleetName + ram; var testname = servername; var increment = 1; while(serverExists(testname)){ testname = servername + "-" + increment; increment = increment + 1; } purchaseServer(testname, ram); tprint(testname + " is ready.");

But this how I ended up with the Petabyte server I've been running with this whole cycle.
I tripled my MaxThreads limits and arbitrary ran every weaken with 10,000 threads and never saw more than 25% usage with 40+ scripts running.

My latest LATEST version is integrated into my startup script that would purchase a server and offload all bronze/silver tier attack scripts to make room for gold/platinum tier onboarding on home.

But on that note: I just earned the achievement for crashing the game with a .js script. Somehow I must be eternally looping somewhere.

Edit: Oh, and to check a server just connect and type free in the console. That should tell you the total, used and available Ram numbers for the server.

fenomas wrote:

If you like this game you've reeeeallly gotta move to NS2, where you'll find everything you do is instantaneous.

Sheesh. You weren't kidding! I refactored three of my scripts into one main startup.js and added a few more features, sorting all hostnames first by ports and then hacking level instead of breaking them into tiers so I can go through the list sequentially as the onboarding script pauses until the necessary port hacks or levels are reached. Even with the added complexity and building the array on the fly it resolves almost immediately. Night and day difference. Thanks for the prodding to make the switch!
That said it does seem to make the game a little more fragile.

polypusher wrote:

Anyone know a better way to buy and manage servers? If I buy a server using the script I have to guess at the price based on the ram I want, so finding a good ram value is hard, and then once purchased I dont see any way to inspect it to see how much ram it has.

The APIs are basically all there, but I think the only good way of finding them is to use the in-game editor's code hints (or get a plugin for an external editor). That is, to mess with servers type in "ns.server" and then browse through the suggestions.

As a reference here are some utility functions I wrote for buying and selling servers. Look away if you'd consider this spoiling things!

Spoiler:
. function deleteServersBelow(price) { var count = 0 ns.getPurchasedServers().forEach(host => { var ram = ns.getServerMaxRam(host) if (ns.getPurchasedServerCost(ram) >= price) return ns.killall(host) if (ns.deleteServer(host)) count++ }) return count } function buyServersBelow(price, maxCt = 4, minRam = 8) { var ram = 1 while (ns.getPurchasedServerCost(ram * 2) < price) ram *= 2 if (ram < minRam) return 0 var count = 0 var size = Math.log2(ram) var canBuy = ns.getPurchasedServerLimit() - ns.getPurchasedServers().length for (var i = 0; i < Math.min(maxCt, canBuy); i++) { if (ns.purchaseServer(`server-${size}`, 1 << size)) count++ } return [count, size] }

Note that you don't have to micromanage the names of purchased servers - if you reuse the same name the game will append suffixes.

Also note that bbcode breaks all the angle brackets! --- edit: no it didn't!

Rezzy wrote:

Even with the added complexity and building the array on the fly it resolves almost immediately.

Yeah, modern JS is quite fast, and AFAICT the game never has more than ~80 servers at a depth of ~15. So it should be safe to assume that all logic will be instant, even it's algorithmically slow (and sorting is algorithmically fast).

That said, make sure you migrate your client scripts too! The game is probably running a few dozen of them in the background, and given how nightmarishly slow that NS1 interpreter is you'll probably notice the difference...

I made a recursive function to try and find all the nodes on the network. As a beginner coder I'd appreciate pointers. It successfully maps at least 3 deep, doesn't duplicate servers, and through a forbidList doesnt add things like my own servers and CSEC. It adds 18 servers to the list, but I count 26 with a scan-analyze 5 so I know it peters out before it should.

I call it with 'deepScan('home', newlist)'

Spoiler:

function deepScan(server, workingServerList) {
if (!workingServerList.includes(server)) {
workingServerList.push(server);
}
var result = ns.scan(server);
for (var newServer of result) {
if (!workingServerList.includes(newServer)) {
deepScan(newServer, workingServerList);
}
}
return workingServerList; }

It looks like you're ignoring the return value of your recursive deepScan call. Try:

workingServerList = deepScan(newServer, workingServerList);

Ignoring the return value is fine there; it's not used and it's the same value either way.

Poly, was that your whole function or did you remove bits related to the forbidList before posting? It looks fine to me, so I'm guessing your bug was in the stuff you removed.

(If I were a betting man I'd bet the bug is that you're skipping unwanted hosts entirely, without recursing over their neighbors, so you miss any server that can only be reached via an unwanted one. It will be easier to just recurse all hosts, then filter out ones you don't want afterward.)

As for pointers, when recursing it's usually best to track the recursion depth - both for utility and also to make sure you don't loop infinitely by mistake. E.g.:

. function recurse(thing, depth = 0, maxDepth = 15) { // do stuff if (depth >= maxDepth) return for (var neighbor of getNeighbors(thing)) { recurse(neighbor, depth + 1, maxDepth) } }

Ooh somehow breaking off ignored servers makes some sense, I'll look again tomorrow, and add in a max depth protection. I definitely had some infinite loops early (n00dles all the way down). The game caught most of them but did lock up once.

fenomas wrote:

Ignoring the return value is fine there; it's not used and it's the same value either way.

OH! Netscript 2.0 is pass-by-reference? Nifty. That simplifies this a bit - no need to return anything!

Polypusher, your code seems to work fine for me (with minor NS2 wrapper tweaks, for commandline testing), and is stupidly fast in NS2 (finishes in milliseconds) compared to NS1 (1 recursive call per second).

Spoiler:
function deepScan(ns, server, workingServerList) { if (!workingServerList.includes(server)) { workingServerList.push(server); } var result = ns.scan(server); for (var newServer of result) { if (!workingServerList.includes(newServer)) { deepScan(ns, newServer, workingServerList); } } }; /** @param {NS} ns **/ export async function main(ns) { var serverList = []; deepScan(ns, "home", serverList); ns.tprint(serverList); }

I didn't think of putting it outside main(). Can a function be made public, accessible by other scripts that way?

Also for me, if I don't return workingServerList, I get a 'not iterable' error. (this is with it inside Main)

merphle wrote:

OH! Netscript 2.0 is pass-by-reference? Nifty. That simplifies this a bit - no need to return anything!

JS is basically pass by reference for objects, and pass by value for literals (numbers, strings, booleans). But it's probably better to think of it as: when you declare an array JS creates one on the heap and gives you a reference to it, and if you pass that reference to another function, it receives a new reference to the same array.

(Edited to add: as far as I can tell there are zero differences between what the game calls "NS2" and regular modern JS. It looks like NS1 ran inside some kind of ad-hoc interpreter, but NS2 is just regular code being executed by V8.)

polypusher wrote:

I didn't think of putting it outside main(). Can a function be made public, accessible by other scripts that way?

Code outside "main()" is interesting. Basically, anything you put outside main is shared by all instances of that particular script on that particular server. E.g. if you declare a variable outside main, and then run multiple instances of that script (with different arguments), they'll run in the same scope and thus all reference the same copy of that variable.

But the same script on a different server will run in its own scope. Also if you edit/save the script file, any subsequent runs will get a new scope too.

For your second question, you can make code accessible by other scripts:

// foo.js export var helloPoly = 'what up yo' export function doSomething() { } // bar.js import { helloPoly, doSomething } from 'foo.js' export async function main(ns) { ns.tprint('imported: ', helloRezzy) }

Gee if only there was a place we could talk about this. Maybe we need a JS-only programming thread for coders who aren't yet advanced enough to know which languages are objectively good and bad.

Non-coding thing I learned today, by the way: each time you install augmentations your reputation with each faction is converted to favor, which boosts future faction gains. So before you prestige it's useful to grind out a bit of reputation on each faction you intend to grind next.

fenomas wrote:

Gee if only there was a place we could talk about this. Maybe we need a JS-only programming thread for coders who aren't yet advanced enough to know which languages are objectively good and bad.

Don't let the trolls get you down, Fenomas; and by corollary: don't feed the trolls.

...that's fair (But I do feel awkward talking this much about JS syntax in the clicker games thread.)

I've got my scripts looking at all servers now, assessing their hackability, and reacting accordingly. Awesome help yall.

So I'm at Hacking level 277. Seems like there's a huge jump from here to the next hackable server as far as hack score goes. I think the next one is 404. My hacking level is going up pretty slowly, even with paying for the best university course. Im running about 1000 threads of my hacking code for about 18 hacking points per second, with the school its about 30.

That's still a long time to reach 404, even if I expand my fleet. Am I missing something more fundamental to raising hacking score faster? I haven't messed with crime, infiltration, or stocks.

Poly: have you installed any augmentations yet? If not, poke around the "Factions" tab. (Or the milestones tab, for more specific suggestions.)

Yup augmenting is the way to go and the tutorial/help pages strongly suggest emptying out a faction of all augments before resetting.
My hacking level is hovering around 1070, with three (or four? ) factions worth of augments. I just finished grinding out enough faction points with the BitRunners to buy all their stuff this morning and will be starting cycle 5 as soon as I finish refactoring my attack and control scripts to JS and reworking my tiering logic.
Remember to burn your money before resetting. Visit a tech shop and upgrade your home server, buy stock market API, dump the money into augments from other faction shops... You don't get to keep it.

Hard to say if I should ask coding questions here where I'll bore the clicker fans who dont care about BitBurner, or in the Joy of Programming thread where I'll bore the coders who don't care about a silly game.

For now I want to ask one more here. I want to optimize and maintain a server list of ready-to-poke servers in one script and make that list available to my other scripts. I think if I do it this way, those other scripts can be much leaner and run with more threads, just pulling an updated list on each loop and rocking from there.

To try and accomplish this, my list maintenance thread creates the list, populates it with servers, and then just stays alive quietly with a while(true){ns.sleep(1000);}.

Spoiler:

export var serverList = [];

export async function main(ns) {
function deepScan(server, workingServerList) {
if (!workingServerList.includes(server)) {
workingServerList.push(server);
}
var result = ns.scan(server);

for (var newServer of result) {
if (!workingServerList.includes(newServer)) {
deepScan(newServer, workingServerList);
}
}
return workingServerList;
}

serverList = deepScan('home', serverList);

So that should be visible. The maintenance script sees it as populated but other scripts see it as empty when I import it and just try to print it.

Spoiler:

import {serverList} from 'startup.js'
export async function main(ns) {
for (var server of serverList) {
do stuff}}

Both scripts are on the same server.

Okay, scripts refactored and tested. Setting on-boarding limiter to 30 servers initially until I can assess usage and spec a server to offload to.
I will be installing 20 augments (NeuroFlux Governor @ lvl 40).

Crossing fingers and going under.

It took five minutes to go from Hacking level 1 to level 1,184. Teehee.
8 minutes to get my first billion.

merphle wrote:
fenomas wrote:

Gee if only there was a place we could talk about this. Maybe we need a JS-only programming thread for coders who aren't yet advanced enough to know which languages are objectively good and bad.

Don't let the trolls get you down, Fenomas; and by corollary: don't feed the trolls. :)

If I sincerely and publicly apologize and chastise other trolls, will you come back? I miss you, and I see how awful I was, even if it wasn't intended as a personal attack.

polypusher wrote:

Hard to say if I should ask coding questions here where I'll bore the clicker fans who dont care about BitBurner, or in the Joy of Programming thread where I'll bore the coders who don't care about a silly game.

It feels like BitBurner deserves its own thread, given its unique mechanics and details.

Mixolyde wrote:

It feels like BitBurner deserves its own thread, given its unique mechanics and details.

I was thinking that, too. I was trying to figure out how long it'll be before we burn out on the game vs how many other games pop up actively in the Clickers thread though.

I burn out on games all the time. For me it will come when I basically see the rest of what the game has to offer and the emergent interesting challenges, like this managing of a list of servers that other scripts subscribe to, get solved. So only a few more days probably.

So a dedicated thread would be nice for grouping all the chat and discovery, just probably wont have people in there all the time. Also we're not hearing from clicker game fans tired of this coding nonsense

I get the feeling that there are mechanics that unlock once you 'beat' the core loop. Fl1ght.exe requires 2000+ levels and 30 augments to complete. Let's see what happens next.

A separate thread for Bitburner would be cool - or even a "Get better at coding with games" thread? (If such there not be..)

Mixolyde wrote:

If I sincerely and publicly apologize and chastise other trolls, will you come back? I miss you, and I see how awful I was, even if it wasn't intended as a personal attack.

Hi, I see I was getting weird here, sorry about that. Please consider it history, and I'll head back to the programming thread one of these days.

(That said, if you feel like it you might dig up the WTF-JS puzzle I posted there, that you commented on, and take a second look. If you look a bit I think you'll see that the WTF-ness wasn't actually JS specific, and that similar code in python or ruby would have shown the same WTF behavior - with whatever implications that may or may not have on your opinion of JS.)

Back on topic! By which of course I mean JS.

polypusher wrote:

For now I want to ask one more here. I want to optimize and maintain a server list of ready-to-poke servers in one script and make that list available to my other scripts. I think if I do it this way, those other scripts can be much leaner and run with more threads, just pulling an updated list on each loop and rocking from there.

The reason what you tried didn't work is that (apparently) the game runs each script in a separate scope. When you run "importer.js", the JS engine parses that file and runs any import statements. Then if you run a second instance of "importer.js" the JS engine runs a second copy of "main()" in the same scope, so any imports (or other vars outside main()) get shared.

But then when you run "otherImporter.js" the game starts a new scope, parses the file and sees in import statement, and imports a new copy of the imported file. So that's why your other scripts were seeing an empty list, because each script was importing a separate array.

Long story short, as near as I can tell there's no built-in way for scripts directly share code (like each access the same array). To pass state information around I think you need to use ports, or write files, or use some other implicitly stateful mechanic. (I had a brainstorm today and I'm using script arguments for this - that is, I pass some unused arguments to the script about what it's doing, and then later I can check the state of everything by running ns.ps() on the bot servers and checking each script's arguments.)

Rezzy wrote:

I get the feeling that there are mechanics that unlock once you 'beat' the core loop. Fl1ght.exe requires 2000+ levels and 30 augments to complete. Let's see what happens next.

I'm closing in on this. I finally got my act together today and ditched my extremely wrong way of hacking - my idea of randomly choosing targets would have been okay, but I hadn't realized how quickly you get to the point where you have enough threads to hack a server down to zero funds. Once that happens, any random fluctuations in the hacking algos tend to clobber everything.

Anyway it took some doing but I made a proper scheduler, that queues up hack/grow/weaken cycles so they end one after another, and now I'm off to the races. I have it looping over the weakest servers, since that seems to rack up hacking XP the quickest, and that's the only milestone I have left.

Coding-game thread made, but I don't think its necessary to migrate all Bitburner chatter over there

fenomas wrote:

I'm closing in on this.

Nice! I was 200 hacking levels shy of the target when I left for work, and I have 40+ tuned attack scripts churning out looped attacks so I'm hoping to check out the next steps tonight.

I've been ignoring the stock market, but there's this flag to make hacking attacks affect stock prices and I'm thinking it might be time to consider adding cream and a cherry on top of this illicit money sundae.

As the thread creator, I don't mind the recent chatter. This thread comes and goes over the years.

Really, people should be more willing to start up new threads, but I understand that discoverability is an issue. polypusher did the right thing by posting a link here to get people to follow the new thread.

Confession time: I didn't think about my conversion from overwhelming brute force to 'optimize hacking threads for maximum efficiency' too much. I sat back, watched the money absolutely rocket in, and focused on solving some of the other tasks.
Until I noticed my XP gains crawling to halt. Hey! Did you know that using the absolute smallest amount of threads to achieve your goals isn't a good hacking workout?

That's when I spotted an XP exploit. It should have been obvious from the beginning, but I had been honing my scripts toward lean and mean and focusing on gaining augments.
Possibly an actual spoiler

Spoiler:

You get exp for hacking "home" and any purchased servers and so far it doesn't look like you have to pause to weaken those.
150k threads running a hack loop against home have been running for 10 minutes and gained over 200 million hacking exp for me.
This, and targeting all the $0 maxMoney servers with a simple hack/weaken loop using overwhelming force got me past the 2,500 target almost immediately.

Looking over what completing fl1ght.exe has unlocked and...

Spoiler:

I REALLY wish the Matrix reference hadn't been tainted to the point where I had to groan before begrudgingly admitting that in this context it makes total sense. siiiiiiigh