/** @param {NS} ns */ export async function main(ns) { ns.tail(); const maxRAM = Math.pow(2, 20); // Maximum server size: 2^20 GB const minRAM = Math.pow(2, 3); // Minimum required size (8 GB) - FIXED const serverSizes = [maxRAM, ...Array.from({ length: 17 }, (_, i) => Math.pow(2, 19 - i))]; // 2^20 to 2^3 sizes // Fetch the list of purchased servers and sort them from largest to smallest let aPserv = ns.getPurchasedServers(); aPserv.sort((a, b) => ns.getServerMaxRam(b) - ns.getServerMaxRam(a)); // Step 1: Purchase missing servers await purchaseMissingServers(ns, aPserv, serverSizes, maxRAM, minRAM); // PASSED minRAM // Object to hold designated servers for each power-of-two size let designatedServers = initializeDesignatedServers(serverSizes); // Step 2: Assign servers to their respective power-of-two sizes and upgrade them if necessary assignServers(ns, aPserv, designatedServers, serverSizes); // Step 3: Upgrade remaining servers to max RAM await upgradeServersToMaxRAM(ns, designatedServers, aPserv, maxRAM); // Step 4: Write the designatedServers object to a file await writeServerListToFile(ns, designatedServers); ns.tprint("UpgradedServers.txt has been written."); } /** * Step 1: Purchase missing servers. * Ensures we have one server of each size 2^3 through 2^20, and if there are more servers needed, they are purchased at max RAM (2^20). * @param {NS} ns - Netscript API. * @param {Array} aPserv - Array of purchased server names. * @param {Array} serverSizes - Array of power-of-two server sizes. * @param {Number} maxRAM - Maximum server size (2^20). * @param {Number} minRAM - Minimum required server size (2^3 or 8 GB). */ async function purchaseMissingServers(ns, aPserv, serverSizes, maxRAM, minRAM) { const serverLimit = ns.getPurchasedServerLimit(); let nPserv = aPserv.length; // Current number of purchased servers for (let i = nPserv; i < serverLimit; i++) { let nMoney = ns.getServerMoneyAvailable("home"); // If we have fewer than 17 servers, follow the doubling pattern if (i < serverSizes.length) { let targetSize = serverSizes[serverSizes.length - i - 1]; // Start at the smallest size (2^3, then 2^4, etc.) let serverCost = ns.getPurchasedServerCost(targetSize); if (nMoney >= serverCost) { const sServer = ns.purchaseServer(`pserv-${i.toString().padStart(2, "0")}`, targetSize); ns.print(`Purchased ${sServer} with ${targetSize} GB RAM for ${serverCost}`); aPserv.push(sServer); // Add the new server to the list } else { ns.print(`Insufficient funds for pserv-${i.toString().padStart(2, "0")} (${nMoney} / ${serverCost}). Waiting...`); await ns.sleep(5000); // Wait and retry i--; // Retry this iteration once funds are available } } else { // Once we have the first 17 servers, purchase additional servers at max RAM let serverCost = ns.getPurchasedServerCost(maxRAM); if (nMoney >= serverCost) { const sServer = ns.purchaseServer(`pserv-${i.toString().padStart(2, "0")}`, maxRAM); ns.print(`Purchased ${sServer} with ${maxRAM} GB RAM for ${serverCost}`); aPserv.push(sServer); } else { ns.print(`Insufficient funds for pserv-${i.toString().padStart(2, "0")} (${nMoney} / ${serverCost}). Waiting...`); await ns.sleep(5000); // Wait and retry i--; // Retry this iteration once funds are available } } } } /** * Initializes the designatedServers object with null values for each power-of-two size. * @param {Array} serverSizes - Array of power-of-two server sizes (2^20, 2^19, etc.). * @returns {Object} - Object with each size as a key and null as the initial value. */ function initializeDesignatedServers(serverSizes) { let designatedServers = {}; serverSizes.forEach(size => designatedServers[size] = null); return designatedServers; } /** * Step 2: Assigns servers to their respective power-of-two sizes, starting from the largest. * Each server is only used once and is placed in the largest available size it can fit. * @param {NS} ns - Netscript API. * @param {Array} aPserv - Array of purchased server names, sorted by size. * @param {Object} designatedServers - Object holding the server assignments. * @param {Array} serverSizes - Array of power-of-two server sizes. */ function assignServers(ns, aPserv, designatedServers, serverSizes) { for (let size of serverSizes) { for (let i = 0; i < aPserv.length; i++) { let server = aPserv[i]; let serverRAM = ns.getServerMaxRam(server); // If this server can fill the current slot and has not already been assigned if (serverRAM >= size && !Object.values(designatedServers).includes(server)) { designatedServers[size] = server; // Assign the server to the current power-of-two size ns.print(`Assigned server ${server} with ${serverRAM} GB to ${size} GB spot.`); break; // Stop searching for this size and move to the next smaller size } } } } /** * Step 3: Upgrade remaining servers to max RAM (2^20). * @param {NS} ns - Netscript API. * @param {Object} designatedServers - Object holding the server assignments. * @param {Array} aPserv - Array of purchased servers. * @param {Number} maxRAM - Maximum server size (2^20 GB). */ async function upgradeServersToMaxRAM(ns, designatedServers, aPserv, maxRAM) { while (true) { let nMoney = ns.getServerMoneyAvailable("home"); let lowestRAMServer = null; let lowestRAM = maxRAM; // Find the server with the lowest RAM that isn't already maxed out for (let i = 0; i < aPserv.length; i++) { let serverRAM = ns.getServerMaxRam(aPserv[i]); if (serverRAM < maxRAM && !Object.values(designatedServers).includes(aPserv[i])) { lowestRAM = serverRAM; lowestRAMServer = aPserv[i]; } } // If all servers are at maxRAM, we are done if (!lowestRAMServer) { ns.tprint("All servers are fully upgraded to 2^20 GB RAM."); break; // Exit the while loop } // Upgrade the lowest RAM server to maxRAM let upgradeCost = ns.getPurchasedServerUpgradeCost(lowestRAMServer, maxRAM); if (nMoney >= upgradeCost) { ns.upgradePurchasedServer(lowestRAMServer, maxRAM); ns.print(`Upgraded ${lowestRAMServer} to ${maxRAM} GB RAM.`); } else { ns.print(`Insufficient funds to upgrade ${lowestRAMServer} to ${maxRAM}: ${nMoney} / ${upgradeCost}`); await ns.sleep(5000); // Wait and check again } } } /** * Writes the designatedServers object to a file in JSON format. * @param {NS} ns - Netscript API. * @param {Object} designatedServers - Object holding the server assignments. */ async function writeServerListToFile(ns, designatedServers) { await ns.write("UpgradedServers.txt", JSON.stringify(designatedServers, null, 2), "w"); ns.print("UpgradedServers.txt has been written with the server assignments."); }