10

Bitburner – 從自動部屬 Hacknet 入門

 2 years ago
source link: https://fredxxx123.wordpress.com/2022/03/06/bitburner-%E5%BE%9E%E8%87%AA%E5%8B%95%E9%83%A8%E5%B1%AC-hacknet-%E5%85%A5%E9%96%80/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Bitburner – 從自動部屬 Hacknet 入門

有多少錢就買甚麼 換個角度來說, 就是選擇升級/購買選項中最低價的項目

在整個撰寫的過程中, 需要到處蒐集資訊 (API document/IDE 提示/別人的程式碼…etc)

hacknet 相關的 API 都集中在一起:

找到所有的 server, 就會用到 numNodes

    const count = ns.hacknet.numNodes();
    for (let i = 0; i < count; i++) { ... }

取得購買新節點的費用: getPurchaseNodeCost

  const cost = ns.hacknet.getPurchaseNodeCost();

升級相關費用的 API 參數需求都長得一樣

cost = ns.hacknet.getLevelUpgradeCost(nodeIndex, 1);

cost = ns.hacknet.getRamUpgradeCost(nodeIndex, 1);

cost = ns.hacknet.getCoreUpgradeCost(nodeIndex, 1);

JS 相關語法:

以上這些就可以先找出最低價的項目:

/** @param {NS} ns **/
export async function main(ns) {
    // 預設以購買新 node server 為開頭
    // 紀錄最便宜的花費
    let cheapestCost = ns.hacknet.getPurchaseNodeCost();
    // 紀錄最便宜項目的node序號(如果有的話)
    let cheapestIndex = -1;
    // 紀錄最便宜項目的類型
    let cheapestType = "new";
    // 取得目前擁有的節點數量
    const count = ns.hacknet.numNodes();
    // 遍歷所有節點
    for (let i = 0; i < count; i++) {
        // upgrade level
        let cost = ns.hacknet.getLevelUpgradeCost(i, 1);
        ns.print(`node: ${i}, cost of level: ${cost}, cheapestCost: ${cheapestCost}`);
        if (cost < cheapestCost) {
            cheapestCost = cost;
            cheapestIndex = i;
            cheapestType = "level";
        }
        // upgrade ram
        cost = ns.hacknet.getRamUpgradeCost(i, 1);
        ns.print(`node: ${i}, cost of ram: ${cost}, cheapestCost: ${cheapestCost}`);
        if (cost < cheapestCost) {
            cheapestCost = cost;
            cheapestIndex = i;
            cheapestType = "ram";
        }
        // upgrade core
        cost = ns.hacknet.getCoreUpgradeCost(i, 1);
        ns.print(`node: ${i}, cost of core: ${cost}, cheapestCost: ${cheapestCost}`);
        if (cost < cheapestCost) {
            cheapestCost = cost;
            cheapestIndex = i;
            cheapestType = "core";
        }
    }
    // show hint
    ns.print(`cheapest item is node ${cheapestIndex}'s ${cheapestType}, cost is ${cheapestCost}`);
}

這段就是像在 UI 上的檢查流程

既然找到目標, 確認 log 內容也沒問題, 就可以付諸行動

這裡會用到:

JS 相關:

就可以寫成:

switch (cheapestType) {
    case "new":
        ns.hacknet.purchaseNode();
        ns.print(`buy new node`);
        break;
    case "level":
        ns.hacknet.upgradeLevel(cheapestIndex, 1);
        ns.print(`upgrade ${cheapestIndex}'s level`);
        break;
    case "ram":
        ns.hacknet.upgradeRam(cheapestIndex, 1);
        ns.print(`upgrade ${cheapestIndex}'s ram`);
        break;
    case "core":
        ns.hacknet.upgradeCore(cheapestIndex, 1);
        ns.print(`upgrade ${cheapestIndex}'s core`);
        break;
}

確認上述內容都可以正確如預期般的運作

最後就是讓它在背景持續地運作

這裡會用到:

就可以寫成:


while(true) {
  // do something here...

  // 等待 5000 毫秒(等同於 5 秒)
  await ns.sleep(5000)
}

實作-all

整個合在一起就變成:

export async function main(ns) {
    while (true) {
        // 預設以購買新 node server 為開頭
        // 紀錄最便宜的花費
        let cheapestCost = ns.hacknet.getPurchaseNodeCost();
        // 紀錄最便宜項目的node序號(如果有的話)
        let cheapestIndex = -1;
        // 紀錄最便宜項目的類型
        let cheapestType = "new";
        // 取得目前擁有的節點數量
        const count = ns.hacknet.numNodes();
        for (let i = 0; i < count; i++) {
            // upgrade level
            let cost = ns.hacknet.getLevelUpgradeCost(i, 1);
            ns.print(`node: ${i}, cost of level: ${cost}, cheapestCost: ${cheapestCost}`);
            if (cost < cheapestCost) {
                cheapestCost = cost;
                cheapestIndex = i;
                cheapestType = "level";
            }
            // upgrade ram
            cost = ns.hacknet.getRamUpgradeCost(i, 1);
            ns.print(`node: ${i}, cost of ram: ${cost}, cheapestCost: ${cheapestCost}`);
            if (cost < cheapestCost) {
                cheapestCost = cost;
                cheapestIndex = i;
                cheapestType = "ram";
            }
            // upgrade core
            cost = ns.hacknet.getCoreUpgradeCost(i, 1);
            ns.print(`node: ${i}, cost of core: ${cost}, cheapestCost: ${cheapestCost}`);
            if (cost < cheapestCost) {
                cheapestCost = cost;
                cheapestIndex = i;
                cheapestType = "core";
            }
        }
        // show hint
        ns.print(`cheapest item is node ${cheapestIndex}'s ${cheapestType}, cost is ${cheapestCost}`);
        // 確認是否有項目被找到
        if (cheapestCost < Number.MAX_VALUE) {
            switch (cheapestType) {
                case "new":
                    ns.hacknet.purchaseNode();
                    ns.print(`buy new node`);
                    break;
                case "level":
                    ns.hacknet.upgradeLevel(cheapestIndex, 1);
                    ns.print(`upgrade ${cheapestIndex}'s level`);
                    break;
                case "ram":
                    ns.hacknet.upgradeRam(cheapestIndex, 1);
                    ns.print(`upgrade ${cheapestIndex}'s ram`);
                    break;
                case "core":
                    ns.hacknet.upgradeCore(cheapestIndex, 1);
                    ns.print(`upgrade ${cheapestIndex}'s core`);
                    break;
            }
        }
        // 等待一會
        await ns.sleep(5000);
    }
}

最後…還沒結束

這是從實際操作轉成程式碼的最基本型態, 下一步就會依據此版本為基礎不但地進行改造, e.g.:

  • 升級花費不超過某個價格
  • 控制檢查頻率
  • 強化閱讀性
  • 應對一些少見的/極端的狀況
  • 其他更好的演算法

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK