Skip to content

Instantly share code, notes, and snippets.

@NiciusB
Last active January 1, 2024 07:57
Show Gist options
  • Save NiciusB/f5c8b6be0a5dc0d4f03a981410f962d7 to your computer and use it in GitHub Desktop.
Save NiciusB/f5c8b6be0a5dc0d4f03a981410f962d7 to your computer and use it in GitHub Desktop.
automated hack for early bitburner
/** @type {NS} ns **/
export function getAllServers(ns, rootHost = 'home') {
ns.disableLog('scan')
let pendingScan = [rootHost]
const list = new Set(pendingScan)
while (pendingScan.length) {
const hostname = pendingScan.shift()
list.add(hostname)
pendingScan.push(...ns.scan(hostname))
pendingScan = pendingScan.filter(host => !list.has(host))
}
return [...list]
}
import { getAllServers } from "get-servers.js"
/** @type {NS} ns **/
let ns
const projectedTargetsDatas = {}
export async function main(_ns) {
ns = _ns
ns.disableLog('ALL')
while (true) {
await hackRootedServers()
await ns.sleep(1000)
}
}
async function hackRootedServers() {
const allServers = getAllServers(ns)
.filter(host => host !== 'home')
const serversRootAccessIndexed = await Promise.all(allServers.map(host => tryToGetRootAccess(host)))
const possibleTargetServers = allServers
.filter((host, index) => {
return serversRootAccessIndexed[index] &&
ns.getServerMaxMoney(host) !== 0 &&
ns.getServerRequiredHackingLevel(host) <= ns.getHackingLevel()
})
// Hack from all servers
for (const remoteHost of allServers) {
if (ns.getServerMaxRam(remoteHost) === 0) {
continue
}
const targetData = await findBestServerToHackFromPossibleTargetList(possibleTargetServers)
if (targetData) {
await runLoopForServer(remoteHost, targetData)
await ns.sleep(20)
}
}
}
async function findBestServerToHackFromPossibleTargetList(possibleTargetServers) {
possibleTargetServers = JSON.parse(JSON.stringify(possibleTargetServers))
while (possibleTargetServers.length > 0) {
const targetHost = findBestServerToHack(possibleTargetServers)
possibleTargetServers.splice(possibleTargetServers.indexOf(targetHost), 1)
projectedTargetsDatas[targetHost] = projectedTargetsDatas[targetHost] ?? {
securityLevel: ns.getServerSecurityLevel(targetHost),
moneyAvailable: ns.getServerMoneyAvailable(targetHost),
}
const targetData = {
host: targetHost,
minSecurityLevel: ns.getServerMinSecurityLevel(targetHost),
maxMoney: ns.getServerMaxMoney(targetHost),
projected: projectedTargetsDatas[targetHost],
actual: {
securityLevel: ns.getServerSecurityLevel(targetHost),
moneyAvailable: ns.getServerMoneyAvailable(targetHost),
}
}
if (
!(
targetData.projected.moneyAvailable / targetData.maxMoney > 0.95 &&
targetData.actual.moneyAvailable / targetData.maxMoney < 0.5
)
) {
return targetData
}
}
}
async function tryToGetRootAccess(host) {
let openPorts = 0
if (ns.fileExists('ftpcrack.exe')) {
openPorts++
ns.ftpcrack(host)
}
if (ns.fileExists('brutessh.exe')) {
openPorts++
ns.brutessh(host)
}
if (ns.fileExists('httpworm.exe')) {
openPorts++
ns.httpworm(host)
}
if (ns.fileExists('relaysmtp.exe')) {
openPorts++
ns.relaysmtp(host)
}
if (ns.fileExists('sqlinject.exe')) {
openPorts++
ns.sqlinject(host)
}
if (ns.getServerNumPortsRequired(host) > openPorts) {
return false
}
ns.nuke(host)
if (host === 'CSEC') {
// This does not seem to be automatable for now?
// await ns.installBackdoor(host)
}
return true
}
async function runLoopForServer(remoteHost, targetData) {
const cores = 1 // TODO: look into this
let waitMs
let threads
// Weaken
const weakenPerThread = ns.weakenAnalyze(1, cores)
const maxWeakenThreads = Math.floor((targetData.projected.securityLevel - targetData.minSecurityLevel) / weakenPerThread)
if (maxWeakenThreads > 0) {
({ waitMs, threads } = await weaken(remoteHost, targetData.host, maxWeakenThreads))
if (threads) {
targetData.projected.securityLevel -= ns.weakenAnalyze(threads, cores)
targetData.projected.securityLevel = Math.max(targetData.projected.securityLevel, targetData.minSecurityLevel)
ns.print([
'Weakening'.padEnd(9),
remoteHost.padEnd(15),
targetData.host.padEnd(15),
`${Math.ceil(waitMs / 1000)}s`,
`${threads} threads`,
`${Math.round((targetData.projected.securityLevel - targetData.minSecurityLevel) * 100) / 100} lvls left`
].join(' | '))
}
return
}
// Growth
const maxGrowthThreads = ns.growthAnalyze(targetData.host, targetData.maxMoney / targetData.projected.moneyAvailable, cores)
if (maxGrowthThreads >= 1) {
({ waitMs, threads } = await grow(remoteHost, targetData.host, Math.floor(maxGrowthThreads)))
if (threads) {
targetData.projected.securityLevel += ns.growthAnalyzeSecurity(threads)
targetData.projected.moneyAvailable += threads / maxGrowthThreads * targetData.maxMoney
targetData.projected.moneyAvailable = Math.min(targetData.projected.moneyAvailable, targetData.maxMoney)
ns.print([
'Growing'.padEnd(9),
remoteHost.padEnd(15),
targetData.host.padEnd(15),
`${Math.ceil(waitMs / 1000)}s`,
`${threads} threads`,
`${Math.round(targetData.projected.moneyAvailable / targetData.maxMoney * 1000) / 10}% money`
].join(' | '))
}
return
}
// Hack
const hackProbability = ns.hackAnalyzeChance(targetData.host)
let maxHackThreads = 0
let calcMoney = targetData.projected.moneyAvailable
while (calcMoney > targetData.maxMoney * 0.5) {
calcMoney -= calcMoney * ns.hackAnalyze(targetData.host) * hackProbability
maxHackThreads++
}
maxHackThreads--
if (maxHackThreads > 0) {
({ waitMs, threads } = await hack(remoteHost, targetData.host, maxHackThreads))
if (threads) {
const moneyWon = targetData.projected.moneyAvailable * ns.hackAnalyze(targetData.host) * threads * hackProbability
targetData.projected.moneyAvailable -= moneyWon
targetData.projected.securityLevel += ns.hackAnalyzeSecurity(threads) * hackProbability
ns.print([
'Hacking'.padEnd(9),
remoteHost.padEnd(15),
targetData.host.padEnd(15),
`${Math.ceil(waitMs / 1000)}s`,
`${threads} threads`,
`${Math.round(moneyWon / 1e6 * 100) / 100}M`
].join(' | '))
}
}
}
function findBestServerToHack(servers) {
return servers
.map(host => {
const weights = {
maxMoney: 1.7,
growthRate: 0.9,
growTime: 0.8,
minSecurityLevel: 1,
}
const score =
Math.pow(ns.getServerMaxMoney(host) / 1e5, weights.maxMoney) *
Math.pow(ns.getServerGrowth(host), weights.growthRate) /
Math.pow(ns.getGrowTime(host), weights.growTime) /
Math.pow(ns.getServerMinSecurityLevel(host), weights.minSecurityLevel)
return { host, score: Math.round(score * 100) / 100 }
})
.sort((a, b) => b.score - a.score)
.map(x => {
//ns.print(`${x.host}: ${x.score}`)
return x
})[0].host
}
async function hack(remoteHost, targetHost, maxThreadsAllowed) {
const result = await execRemote(remoteHost, 'just-hack.js', maxThreadsAllowed, targetHost)
return {
waitMs: result.threads ? ns.getHackTime(targetHost) : null,
threads: result.threads,
}
}
async function grow(remoteHost, targetHost, maxThreadsAllowed) {
const result = await execRemote(remoteHost, 'just-grow.js', maxThreadsAllowed, targetHost)
return {
waitMs: result.threads ? ns.getGrowTime(targetHost) : null,
threads: result.threads,
}
}
async function weaken(remoteHost, targetHost, maxThreadsAllowed) {
const result = await execRemote(remoteHost, 'just-weaken.js', maxThreadsAllowed, targetHost)
return {
waitMs: result.threads ? ns.getWeakenTime(targetHost) : null,
threads: result.threads,
}
}
async function execRemote(remoteHost, script, maxThreadsAllowed, ...args) {
if (!ns.isRunning(script, remoteHost)) {
await ns.scp(script, 'home', remoteHost)
}
const ramNeeded = ns.getScriptRam(script)
const serverFreeRam = ns.getServerMaxRam(remoteHost) - ns.getServerUsedRam(remoteHost)
let threads = Math.min(maxThreadsAllowed, Math.floor(serverFreeRam / ramNeeded))
if (threads > 0) {
const didSucceed = ns.exec(script, remoteHost, threads, ...args, 'rand-' + Math.random().toString().slice(2))
if (didSucceed === 0) {
threads = 0
}
}
return { threads }
}
@WrayOfSunshine
Copy link

Looks good - would suggest for completion's sake you post just-grow, just-hack, and just-weaken, even though I assume they're the basic ones.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment