Bitburner

前言

游戏十分硬核,如果对编程不感兴趣那么游戏将会变得十分无聊。

游戏没有中文,对应文档也没有中文翻译。所以需要亿点点的英语。不过通过这个游戏可以学到英语和编程的知识也是好的。

这篇指南前两章节讲解的许多内容都在游戏的教程中给出了;

本指南适合阅读人群:有一定程序基础,可以看懂JavaScript代码最好不过了。没用过JS也不用担心,这门语言非常好学。

本指南还在不断更新中。另外,如有纰漏欢迎指正。

游戏背景&基础指令介绍

Bitburner的是一款数值增长类游戏,这类游戏可以简单地理解为点点点的游戏。点击屏幕就可以获得金币,通过金币可以升级你的吸金能力,然后点击屏幕获得更多金币。但与其他游戏不同的地方在于,Bitburner是通过编写代码来取代点点点获取金币的游戏。换言之,你的(现实生活中的)coding能力越强,就越容易获得高额奖励。

游戏发生在2077年,货币已经去中心化,你是一名黑客,你的目标就是黑别人的电脑搞钱,好了开始干吧。

游戏的画面就是一个终端的界面。我们以后大部分的游戏都将是和这个终端交互进行的。

1 重要指令介绍

1.help

在终端上输入help可以查看所有指令。help+特定指令可以查看该指令的具体用法。想不起来的时候可以经常查看。

Type 'help name' to learn more about the command

2.scan

检索可以直接与当前机器相连的主机(服务器)。

3.connect

连接可以直接与当前机器相连的主机(服务器)。

4.hack

按百分比偷取当前主机上的刀乐儿。也就是说,不停的输入这个指令会使你的收入逐渐降低。

5.grow

按百分比增长当前主机上的刀乐儿。

6.weaken

使用hack和grow会使当前主机的安全等级上升。安全等级会影响指令运行时间。使用weaken指令就可以降低安全等级。

7.nano [file ...]

打开文本编辑器。

nano hack.script 打开/创建一个名为hack的脚本文件。

8.run

运行脚本文件或可执行文件。

成为一名超底层的黑客

在终端中输入

( “[home ~/]>” 为当前终端中显示的内容 大于号之后为输入的内容。)

[home ~/]> scan

其结果为:

Hostname IP Root Access

n00dles 3.5.9.5 N

foodnstuff 26.0.9.1 N

sigma-cosmetics 84.8.0.9 N

joesguns 93.6.2.0 N

hong-fang-tea 40.9.8.5 N

harakiri-sushi 94.1.2.1 N

iron-gym 90.8.0.8 N

将会获得所有可以直接进行连接的主机,最后的N代表no,也就是ROOT ACCESS是no。选中一个倒霉蛋然后输入

[home ~/]> connect n00dles

Connected to n00dles

提示已经连接至拉面馆。这里需要注意的事:connect命令只能连接一个节点距离的服务器。假如:foodnstuff服务器还有一个子节点叫zer0,如果输入connect zer0将会提示无法连接。就算我们直接输入IP地址也是不行的。

然后分析主机

[n00dles ~/]> analyze

Analyzing system...

[||||||||||||||||||||||||||||||||||||||||||||||||||]

n00dles:

Organization name: Noodle Bar

Root Access: NO

Required hacking skill: 1

Server security level: 1.000

Chance to hack: 42.43%

Time to hack: 49.264 seconds

Total money available on server: $70.000k

Required number of open ports for NUKE: 0

SSH port: Closed

FTP port: Closed

SMTP port: Closed

HTTP port: Closed

SQL port: Closed

可以看到当前的root权限,需要的最低黑客等级,黑入机会,黑入时间等等一系列的信息。

因为Required number of open ports for NUKE: 0所以,我们不需要打开任何端口(我们目前也没办法打开任何端口)直接就可以运行nuke.exe, 这是一个发射核弹的程序,运行之后拉面馆就会化为灰烬。

这是获取root权限的程序,运行后就可以获得拉面店的所有权限,这时hack指令就可以被运行了。另外我们也可以在这台计算机上运行自己书写的脚本程序了。

[n00dles ~/]> run nuke.exe

NUKE successful! Gained root access to n00dles

运行结果显示我们获取了拉面馆的root访问权限。

事不宜迟,先黑入一波试试。

[n00dles ~/]> hack

[||||||||||||||||||||||||||||||||||||||||||||||||||]

Hack successful! Gained $288.000 and 3.300 hacking exp

Security increased from 1.000 to 1.002

读条完毕之后,显示黑入成功(也可能会失败),获得了288块钱和3.3的黑客经验。但安全等级提升了0.002。

下面试试grow

[n00dles ~/]> grow

[||||||||||||||||||||||||||||||||||||||||||||||||||]

Available money on 'n00dles' grown by 1274.637970%. Gained 3.300 hacking exp.

Security increased from 1.002 to 1.102

可用资金大概提升了12倍,但安全等级也提升了0.1。

下面该weaken出场了

[n00dles ~/]> weaken

[||||||||||||||||||||||||||||||||||||||||||||||||||]

Security decreased from 1.102 to 1.052 (min: 1.000) and Gained 3.300 hacking exp.

通过weaken指令使安全等级降低了0.05

到此为止,我们已经可以手敲指令黑入其他主机并获得利润了。但......总这么敲就太累了吧?

成为一名会写傻瓜脚本的黑客

前一章节我们可以用小手不停的敲击键盘来黑入别人的电脑获取他们的金钱了。但毕竟我们是黑客,不是富士康流水线上重复单一动作的工人。所以自动化是必不可少的。

编写脚本,首先要打开文本编辑器。

通过nano指令就可以打开文本编辑器去书写代码了。

游戏中使用的编程语言叫做NetScript。其中分为NS1和NS2两种版本。NS1是JavaScript的一个子集,在游戏中运行速度较慢。NS2则是几乎涵盖了所有JavaScript的功能,运行速度飞快。NS1代码的(游戏中的)扩展名为.script。NS2代码的扩展名为.js。 详细内容点击这里 [bitburner.readthedocs.io]

当我们黑入面馆(n00dles)的电脑之后,就可以在终端上不停的键入hack来获得源源不断地金钱,但手动hack显然不是一个聪明的举动。所以我们可以编写一个简单的循环脚本来让计算机自动帮我们输入hack。

具体操作:

在终端键入并回车打开文本编辑器

[home ~/]> nano hack.script

然后编写NS1格式的脚本文件:

while (true) hack("n00dles");

解释:while表示循环括号里面是循环的条件,条件为真时进行循环执行,条件为假时跳出循环,因为括号里时true,所以这个循环会一直执行(俗称死循环)。上面的代码将会循环执行hack。

按下ctrl+s和ctrl+b保存并关闭文本编辑器返回终端界面。

然后键入

[home ~/]> run hack.script

Running script with 1 thread(s), pid 37 and args: [].

会提示你这个脚本使用了一个线程,并且没有任何参数。然后点击左侧的Active Script可以看到当前正在运行的脚本。

很明显,当我们运行一段时间之后就会发现面馆的余额越来越少,按百分比获取金钱的hack指令每次可以获得的金钱将会越来越少,而且警戒等级也因为不停的黑入提高了,这样每次黑入的时间将会变长,我们的效率也会随之变低。all in all,一直使用hack指令将会使我们的收益逐渐降低。改变这个局面将会是必不可少的一环工作。

同样的,我们可以再建立另外两个名为grow和weaken的脚本去进行不断地增长和削弱。

grow.script

while (true) grow("n00dles");

weaken.script

while (true) weaken("n00dles");

目前为止我们可以自动的对n00dles进行黑入、增长、和削弱操作了。

需要说明的事情:目前三个脚本被运行在了本地主机home上。每个脚本都会占用一定的内存,例如上面的脚本占用了1.75GB的内存。我们本地主机只有8GB内存,所以大约运行四个脚本内存就会耗尽。为了解决内存问题,我们可以去电脑城购买更大的内存条或者干脆直接购买云端服务器。出生城市Sector-12的电脑配件商城叫alpha ent.在地图上用一个大写的T表示。Purchase x.00GB Server表示购买xGB的云端服务器。需要注意的事:如果想购买更大内存的服务器需要在线购买。最大可以购买2^20GB RAM的服务器。点击upgrade 'home' ram就可以升级本地设备的内存容量。下面的core指CPU核心数量,这个影响的是使用hack、grow、weaken的时间长短。

可是,以我们目前的经济实力,升级配置和购买服务器都不是一个很好的解决办法。

我们需要转换一个思路,既然我们已经获得了远程主机的root权限,那我们为什么不把脚本直接在想要黑入的服务器上运行呢?

在远程服务器运行脚本的操作和在本地一样:首先新建/拷贝脚本文件到目标远程服务器,然后输入 run 脚本名,即可执行其脚本文件。所以,每当我们解锁一个服务器的root权限之后,就在这台服务器上上传黑入三件套,然后运行。

要完成这个目标,目前还有两个问题,第一,如果我们想黑入其他服务器,那么这个脚本“n00dles”的部分就需要手动修改,第二,我们还需要手动拷贝脚本到目标服务器并手动运行。

第二个问题可以通过建立一个用于临时拷贝的脚本来应付一下:

在终端键入并回车打开文本编辑器

[home ~/]> nano copy.script

并在文件中写入

scp("hack.script","home","foodnstuff") scp("grow.script","home","foodnstuff") scp("weaken.script","home","foodnstuff")

//scp用法:

//scp(files: string | string[], source: string, destination: string)

解释:scp函数需要传入三个参数,第一个参数表示文件名。第二个参数表示文件所在的地址(服务器),第三个表示想要拷贝到的地址。

所以scp("hack.script","home","foodnstuff")就表示,将home主机上的hack.script文件拷贝到foodnstuff服务器上。

这样只要我们一运行copy.script就可以将hack、grow、weaken三个文件拷贝到杂货店的主机上了。

下面我们来解决主机名的问题。我们可以在home中找到一个名为hackers-starting-handbook.lit 的文件,使用 cat hackers-starting-handbook.lit 可以查看其中的内容。里面介绍了几个重要的函数。(为了更好地进行游戏中程序的编写强烈建议阅读游戏教程中的所有内容Tutorial)

例如:getHostname();就可以获得当前主机的名字。所以我们将之前的三个脚本“n00dles”的地方换成getHostname();就可以解决问题一了。但拷贝的问题还是没有完美解决。

其实,我们在终端中运行脚本文件时可以向其传递参数,传递的参数可以使用args变量来访问。稍作改变,我们的copy就变成了这样:

//var from = args[0]; var from = "home"; var to = args[0]; scp("hack.script",from,to) scp("grow.script",from,to) scp("weaken.script",from,to)

当我们在终端中输入 run copy.script foodnstuff 之后就可以在foodnstuff中看到这三个文件了。

下面只需要输入:

run hack.script

run grow.script

run weaken.script

就可以进行新的黑入操作了。等等,这要在终端上敲三行代码不会很麻烦吗?当然麻烦,所以我们可以再编写一个脚本去一键运行这三个代码。但这并不是最好的解决办法,所以这里留给大家独立思考,如何编写一个运行其他三个脚本的脚本。

提示:

run(script: string, numThreads?: number, ...args: string[]): number

Start another script on the current server.

成为一名不那么傻的黑客

上一章介绍了基础脚本的编写。虽然解决了一个又一个的问题,但写出来的脚本依旧不能很顺滑的一键部署在目标服务器上。这一章我们将编写一些更加自动化的代码。这里依然使用NS1来编写代码。

上一章中我们使用了三个不同的脚本来不断地对一个服务器进行三重打击。其实仔细思考一下会发现,这并不是最优解。考虑一下这种情况如果黑入和增长地指令所产生的安全性提高比weaken降低地数量高的话,那么整体的安全等级就会一直增长,但如果低的话我们会有一些多余的算力做了无用功,那我们是不是需要合理的规范一下这三个操作的使用呢?

简单地,只有当服务器中的存款最多的时候,一次hack才能获得最大收益。另外,只有服务器的安全等级最低的时候,一次hack才能用时最短。所以我们可以通过判断当前host的余额和安全等级来决定要做的事情。

当前安全等级大于最低安全等级时削弱它,反之,判断当前余额是否小于最大余额,小于就使它增长,反之黑入服务器。

nano hack&grow&weaken.script hostname = getHostname(); while (true) { if (getServerSecurityLevel(hostname) > getServerMinSecurityLevel(hostname)) { weaken(hostname); } else if (getServerMoneyAvailable(hostname) < getServerMaxMoney(hostname)) { grow(hostname); } else { hack(hostname); } 解释:这里的while依旧是一个死循环,但里面加入了一个条件的判断。首先判断当前的安全等级是否为最低,如果不是虚弱它。之后判断当前的可用金钱是否为最大,如果不是增长它。如果安全等级为最低并且可用金钱为最高,那么就进行黑入。

之后进行拷贝,并连接至相应服务器运行即可以部署一个完整的黑入程序了。

虽然grow面馆一次可以获得极高的涨幅,但当我们黑入其他节点时发现,一次grow竟然只有0.0几%的涨幅,不要担心,这并不是因为我们还没有解锁什么隐藏的道具,游戏的设定就是这样的。其实简单思考一下,会发现这也难不倒一名傻瓜黑客,一次运行增长万分之一,那我同样的脚本同时运行100个,那一次就有百分之一的涨幅了。

在终端中输入:

[home ~/]> run hack.script

This script is already running. Cannot run multiple instances

结果竟然不能同时运行多个相同脚本?这是怎么回事?那相同内容的脚本复制多个分别叫hack1.script、hack2.script、...、hackn.script不就行了?

先别急着蛮干,其实游戏中有个线程的概念,还记得前面的思考题么?run函数里有一个叫numthreads的参数,这个参数就是进行多线程执行的参数。

run(script: string, numThreads?: number, ...args: string[]): number

这里填写一个99就代表同样的脚本被同时运行了99个,那效率也就是单个脚本的99倍了。

但这里具体要填写多少呢?其实也很容易想到,计算一下当前主机的可用内存,并除以将要执行的脚本内存用量,就可以计算出一共可执行的脚本数量。

threads = Math.floor((getServerMaxRam(host) - getServerUsedRam(host)) / getScriptRam(script))

目前为止我们可以进行多线程的脚本部署了,但有那么多服务器,挨个手动拷贝再手动运行也不是个事儿啊。

是时候解决自动拷贝和运行的问题了。

在这之前,我们还有一个问题要解决,那就是获取root访问权限。手动获取权限也是一件麻烦事,那如何获取权限呢?

这里给出一个解决方案。

使用深度优先探索所有节点。

function DFS(current, server, ret) { var servers = scan(server); for (var j = 0; j < servers.length; j++) { if (current == servers[j]) continue; ret.push(servers[j]); DFS(server, servers[j], ret); } } function listallservers() { var ret = []; DFS("", "home", ret); return ret; } var servers = listallservers(); tprint(servers);

运行上面这个脚本文件之后将会在终端上输出所有服务器。

获得了所有服务器之后就可以进行端口的开启:

var count; var t = 0; for (var j = 0; j < servers.length; j++) { count = 0 if (fileExists("BruteSSH.exe")) { count++; brutessh(servers[j]); } if (fileExists("FTPCrack.exe")) { count++; ftpcrack(servers[j]); } if (fileExists("relaySMTP.exe")) { count++; relaysmtp(servers[j]); } if (fileExists("HTTPWorm.exe")) { count++; httpworm(servers[j]); } if (fileExists("SQLInject.exe")) { count++; sqlinject(servers[j]); } if (count >= getServerNumPortsRequired(servers[j])) { nuke(servers[j]); t++; //tprint("successful!") } else { //tprint("not enough!") } } tprint(t);

最后终端上会显示获取了root访问权限的服务器的数量。

当编写或购买了新的黑客程序之后,运行上面的脚本就会对所有服务器进行一次端口的开启。

运行了这个脚本之后会发现需要等待很久才能完成,这是因为NS1代码的执行效率不佳,所以我们之后使用NS2代码进行脚本的编写。

两种版本代码的主要区别在于,目前我们所用的类似getServerNumPortsRequired这样的函数都被封装在了NS这个类当中,使用方法:ns.getServerNumPortsRequired();

另外,还需要注意的是,类似hack()这类方法需要使用await来等待其执行完成。

所以,为了效率以后的脚本我们会使用NS2来编写。

完成了自动开启端口,那么接下来我们要完成的就是一键部署了。

使用exec方法可以在指定服务器上运行指定线程的指定脚本文件。

run.js

/** @param {NS} ns **/ export async function main(ns) { var host = ns.args[0]; var target = ns.args[1]; var script = "autoHGW.js"; var threads = (ns.getServerMaxRam(host) - ns.getServerUsedRam(host)) / ns.getScriptRam(script); if(threads < 1){ ns.tprint(`out of memory!`); return; } await ns.scp(script, ns.getHostname(), host); ns.exec(script, host, threads, target,0); }

autoHGW.js

export async function main(ns) { var hostname = args[0]; while (true) { if (ns.getServerSecurityLevel(hostname) > ns.getServerMinSecurityLevel(hostname)) { await ns.weaken(hostname); } else if (ns.getServerMoneyAvailable(hostname) < ns.getServerMaxMoney(hostname)) { await ns.grow(hostname); } else { await ns.hack(hostname); } } }

run run.js home n00dles

就会使用home上的所有内存来运行基础黑入程序。

最后通过处理servers来获得所有可用的服务器,然后在上面批量运行。

beginProc.js

/* *这里是DFS程序. */ servers = list_servers(ns).filter(s => ns.hasRootAccess(s)).concat(['home']); for (var server of servers) { ns.exec("run.js", ns.getHostname(), 1, server,target); }

成为一名斤斤计较的黑客

我们思考一个问题:如果a服务器的最低安全等级为1,当前安全等级为10,已知一次weaken可以降低0.05,那么我们需要运行weaken多少次才能将安全等级降到最低呢?

很简单对吧,如果我们可以在游戏中获取上面的这些已知条件,那我们是不是可以在游戏中真的计算出这个运行次数呢?

最低安全等级 :ns.getServerMinSecurityLevel(server);

当前安全等级: ns.getServerSecurityLevel(server);

次数 : (当前安全等级 - 最低安全等级) / 0.05

同理增长金钱的次数也可以这样计算出来

可用金钱:ns.getServerMoneyAvailable(server);

最大金钱:ns.getServerMaxMoney(server);

因为每个服务器的增长指数不一样,所以我们需要用到:growthAnalyze方法

growthAnalyze(host: string, growthAmount: number, cores?: number): number;

其中第一个参数是服务器名,第二个参数是增长数量,第三个是核心数量(选填)

增长数量指的是从现在的余额增长这个数量的倍数。所以我们想让一个服务器增长到最大,那么这个数量就将会是:最大金钱/可用金钱

即:

次数 : ns.growthAnalyze(server, 最大金钱/可用金钱)

最后hack:

hackAnalyzeThreads(host: string, hackAmount: number): number;

这个方法会返回黑入某个服务器获取hackAmount数量的金钱需要的次数(实际上是线程数,因为每次黑入会有安全等级的变化导致下一次黑入的金钱变化)

次数 : hackAnalyzeThreads(server,最大金钱);

有了这些数据我们就可以精确控制我们对一个服务器黑入的线程数量。

游戏流程(含剧透)

游戏会随着一些条件的达成而收到诸如jump3R等一些组织的信息或组织邀请(比如黑客等级达到100,黑客网络节点总等级达到100等等)。这些信息会隐式的给出一个黑客组织的名字。我们要做的就是找到这个组织的服务器并且安装后门程序(连接服务器后使用backdoor指令)。成功之后会收到黑客组织的邀请。在黑客组织工作可以获得声望,来解锁增强剂的购买选项。

增强剂是一些可以增加经验获取减少黑入时间等等效果的道具,这些道具可以理解为赛博世界中的义体或植入体。然而单纯购买这些增强剂是没有用的,我们还需要进行安装。而安装将会重置技能等级和经验、金钱、除了home以外的所有脚本、购买的服务器、购买的黑客节点、帮派的声望、股票。总而言之,安装强化剂就相当于某些游戏中的转生。

所以,游戏的流程就是:1不断升级黑客能力->2收到信息->3找到对应服务器->4安装后门->进行组织工作并购买增强剂->安装增强重生加速经验获取->返回1

主线中的四个组织名和服务器名分别为:

CyberSec : CSEC

NiteSec: avmnite-02h

Black Hand: I.I.I.I

BitRunners: run4theh111z

当购买并安装所有以上四个组织的增强剂之后,在home运行fl1ght.exe程序查看新的目标

全部完成之后会收到新的邀请:Daedalus

这个组织提供一个名为The Red Pill的物品(黑客帝国梗)。购买之后将会完成第一轮大循环。

后记

想成为一名小有名气的黑客,不去读手册是不行的。 葵花宝典 [github.com]

这里列出了所有可以使用的方法。比如:获取虚弱当前服务器安全等级的用时,就可以使用这个函数:getWeakenTime(host) 等等。

另外游戏还有股市系统,可以购买API来编写脚本进行买卖。目前对这个系统还没有详细研究,总之如果写出一个毛耸耸算法来自动进行股市交易,应该也可以获得不菲的收益。

其实上面给出的只是基本的策略,并非(当然肯定不是)最优解。更多有意思的想法欢迎大家一起交流。

Source: https://steamcommunity.com/sharedfiles/filedetails/?id=2693544193					

More Bitburner guilds