/**
* @description nicoty.sbin.servers.js - 8.85GB - Perpetually tries to buy the best server with the available cash if RAM utilisation of the network is over a threshold, unless there are 25 servers already, in which case deletes the worst server and replaces it with a better one, unless all 25 already have the maximum possible RAM.
* @license BlueOak-1.0.0
*/
import {
float_get_network_ram_utilisation,
float_get_server_ram_total,
} from "nicoty.lib.ram.server.js";
/**
* @description Constants.
* @readonly
* @property {number} BaseCostFor1GBOfRamServer - Cost of server per 1 GB of RAM.
* @property {number} PurchasedServerLimit - Maximum amount of purchased servers allowed.
* @property {number} integer_server_ram_min - Minimum RAM of purchased servers possible.
* @property {number} PurchasedServerMaxRam - Maximum RAM of purchased servers possible. 2^20.
* @see {@link https://github.com/danielyxie/bitburner/blob/master/src/Constants.ts|Bitburner's source code}.
*/
const object_constants = {
BaseCostFor1GBOfRamServer: 55000,
PurchasedServerLimit: 25,
integer_server_ram_min: 2,
PurchasedServerMaxRam: 1048576,
};
export const main = async (object_netscript) => {
/**
* @description Returns `true` if all the bought servers have maximum RAM, otherwise returns `false`.
* @param {Object} object_arguments - Contains the arguments for the function.
* @param {string[]} [object_arguments.array_servers_bought] - Contains the names of bought servers.
* @returns {boolean} `true` if all the bought servers have maximum RAM, otherwise `false`.
*/
const boolean_servers_bought_all_max = (
array_servers_bought = object_netscript.getPurchasedServers()
) =>
array_servers_bought.every(
(string_server) =>
float_get_server_ram_total({
object_netscript: object_netscript,
string_server: string_server,
}) >= object_constants.PurchasedServerMaxRam
);
/**
* @description Returns the name of the bought server with the smallest RAM.
* @param {Object} object_arguments - Contains the arguments for the function.
* @param {string[]} [object_arguments.array_servers_bought] - Contains the names of bought servers.
* @returns {string|null} The name of the bought server with the smallest RAM.
*/
const string_get_server_bought_smallest = (
array_servers_bought = object_netscript.getPurchasedServers()
) =>
array_servers_bought.reduce(
(object_server_smallest, string_server) => {
const integer_ram = float_get_server_ram_total({
object_netscript: object_netscript,
string_server: string_server,
});
return integer_ram < object_server_smallest.integer_ram
? {
string_server: string_server,
integer_ram: integer_ram,
}
: object_server_smallest;
},
{
string_server: null,
integer_ram: 1 / 0,
}
).string_server;
/**
* @description Returns the name of the bought server with the biggest RAM.
* @param {Object} object_arguments - Contains the arguments for the function.
* @param {string[]} [object_arguments.array_servers_bought] - Contains the names of bought servers.
* @returns {string|null} The name of the bought server with the biggest RAM.
*/
const string_get_server_bought_biggest = (
array_servers_bought = object_netscript.getPurchasedServers()
) =>
array_servers_bought.reduce(
(object_server_biggest, string_server) => {
const integer_ram = float_get_server_ram_total({
object_netscript: object_netscript,
string_server: string_server,
});
return integer_ram > object_server_biggest.integer_ram
? {
string_server: string_server,
integer_ram: integer_ram,
}
: object_server_biggest;
},
{
string_server: null,
integer_ram: -1 / 0,
}
).string_server;
/**
* @description Returns the RAM of the server bought with the biggest amount of RAM.
* @param {string} [string_server_bought_biggest] - The name of server bought with the biggest amount of RAM.
* @returns {number} The RAM of the server bought with the biggest amount of RAM.
*/
const integer_get_ram_server_bought_biggest = (
string_server_bought_biggest = string_get_server_bought_biggest(
object_netscript.getPurchasedServers()
)
) =>
float_get_server_ram_total({
object_netscript: object_netscript,
string_server: string_server_bought_biggest,
});
/**
* @description Returns the most amount of RAM of a server that can be bought.
* @returns {number} The most amount of RAM of a server that can be bought.
*/
const integer_get_ram_biggest_can_buy = () =>
Math.max(
object_constants.PurchasedServerMaxRam,
Math.pow(
2,
Math.trunc(
Math.log2(
object_netscript.getServerMoneyAvailable("home") /
object_constants.BaseCostFor1GBOfRamServer
) / Math.log2(2)
)
)
);
/**
* @description The first set of conditions that should be met before buying a server.
* @param {Object} object_arguments - Contains the arguments for the function.
* @param {number} [object_arguments.integer_servers_bought_amount] - The amount of servers bought.
* @param {number} [object_arguments.integer_ram_biggest_can_buy] - The amount of RAM of the server with the biggest amount of RAM that can be bought.
* @returns {boolean} `true` if the conditions are met, otherwise `false`.
* @todo Don't hardcode "home", maybe pass it it as a function parameter?
*/
const boolean_conditions_server_buy_a = ({
integer_servers_bought_amount: a = object_netscript.getPurchasedServers()
.length,
integer_ram_biggest_can_buy: b = integer_get_ram_biggest_can_buy(),
}) =>
// There are no bought servers yet.
0 === a &&
// RAM is at least equal to the minimum RAM possible for bought servers.
b >= object_constants.integer_server_ram_min &&
// RAM is at least equal to the RAM of "home" (probably a bad idea to hardcode this since the name of "home" might change in the future) or maximum RAM.
(b >=
float_get_server_ram_total({
object_netscript: object_netscript,
string_server: "home",
}) ||
b >= object_constants.PurchasedServerMaxRam);
/**
* @description The second set of conditions that should be met before buying a server.
* @param {Object} object_arguments - Contains the arguments for the function.
* @param {number} [object_arguments.integer_servers_bought_amount] - The amount of servers bought.
* @returns {boolean} `true` if the conditions are met, otherwise `false`.
*/
const boolean_conditions_server_buy_b = (
integer_servers_bought_amount = object_netscript.getPurchasedServers()
.length
) =>
// There is at least one bought server.
integer_servers_bought_amount >= 1 &&
// The amount of bought servers is less that the maximum allowed
integer_servers_bought_amount < object_constants.PurchasedServerLimit;
/**
* @description The third set of conditions that should be met before buying a server.
* @param {Object} object_arguments - Contains the arguments for the function.
* @param {number} [object_arguments.integer_ram_biggest_can_buy] - The amount of RAM of the server with the biggest amount of RAM that can be bought.
* @param {number} [object_arguments.integer_ram_server_bought_biggest] - The amount of RAM of the server bought with the biggest amount of RAM.
* @returns {boolean} `true` if the conditions are met, otherwise `false`.
*/
const boolean_conditions_server_buy_c = ({
integer_ram_biggest_can_buy: c = integer_get_ram_biggest_can_buy(),
integer_ram_server_bought_biggest: b = integer_get_ram_server_bought_biggest(
string_get_server_bought_biggest(object_netscript.getPurchasedServers())
),
}) =>
// A server with the maximum amount of RAM hasn't been bought yet. A server with RAM greater than the amount of RAM of the server bought with the biggest amount of RAM should be bought.
b < object_constants.PurchasedServerMaxRam &&
b < c;
/**
* @description The fourth set of conditions that should be met before buying a server.
* @param {Object} object_arguments - Contains the arguments for the function.
* @param {number} [object_arguments.integer_ram_biggest_can_buy] - The amount of RAM of the server with the biggest amount of RAM that can be bought.
* @param {number} [object_arguments.integer_ram_server_bought_biggest] - The amount of RAM of the server bought with the biggest amount of RAM.
* @returns {boolean} `true` if the conditions are met, otherwise `false`.
*/
const boolean_conditions_server_buy_d = ({
integer_ram_biggest_can_buy: c = integer_get_ram_biggest_can_buy(),
integer_ram_server_bought_biggest: b = integer_get_ram_server_bought_biggest(
string_get_server_bought_biggest(object_netscript.getPurchasedServers())
),
}) =>
// A server with the maximum amount of RAM has already been bought. Another one should be bought.
b == object_constants.PurchasedServerMaxRam &&
c >= object_constants.PurchasedServerMaxRam;
/**
* @description The set of conditions that should be met before buying a server.
* @param {number} float_ram_utilisation_threshold - The fraction of the network of rooted server's RAM that must be being used.
* @returns {boolean} `true` if the conditions are met, otherwise `false`.
*/
const boolean_conditions_server_buy = (float_ram_utilisation_threshold) => {
const array_servers_bought = object_netscript.getPurchasedServers(),
integer_ram_biggest_can_buy = integer_get_ram_biggest_can_buy(),
integer_ram_server_bought_biggest = integer_get_ram_server_bought_biggest(
string_get_server_bought_biggest(array_servers_bought)
);
return (
!boolean_servers_bought_all_max(array_servers_bought) &&
float_get_network_ram_utilisation(object_netscript) > float_ram_utilisation_threshold &&
(boolean_conditions_server_buy_a({
integer_servers_bought_amount: array_servers_bought.length,
integer_ram_biggest_can_buy: integer_ram_biggest_can_buy,
}) || (boolean_conditions_server_buy_b(array_servers_bought.length) &&
(boolean_conditions_server_buy_c({
integer_ram_biggest_can_buy: integer_ram_biggest_can_buy,
integer_ram_server_bought_biggest: integer_ram_server_bought_biggest,
}) || boolean_conditions_server_buy_d({
integer_ram_biggest_can_buy: integer_ram_biggest_can_buy,
integer_ram_server_bought_biggest: integer_ram_server_bought_biggest,
}))))
);
};
/**
* @description The set of conditions that should be met before deleting servers and buying better ones.
* @param {number} float_ram_utilisation_threshold - The fraction of the network of rooted server's RAM that must be being used.
* @returns {boolean} `true` if the conditions are met, otherwise `false`.
*/
const boolean_conditions_server_replace = (float_ram_utilisation_threshold) => {
const array_servers_bought = object_netscript.getPurchasedServers();
return (
// The maximum amount of servers has been bought.
array_servers_bought.length == object_constants.PurchasedServerLimit &&
// Not all servers have the maximum amount of RAM.
!boolean_servers_bought_all_max(array_servers_bought) &&
// Cash is at least equal to the price of the cheapest server bought + the next highest server after that, which is twice the price of the former, thus 3. This check is so that a server with the same RAM as before isn't bought.
object_netscript.getServerMoneyAvailable("home") >=
3 *
object_constants.BaseCostFor1GBOfRamServer *
float_get_server_ram_total({
object_netscript: object_netscript,
string_server: string_get_server_bought_smallest(
array_servers_bought
),
}) &&
// The utilisation of the network's RAM is greater than the threshold.
float_get_network_ram_utilisation(object_netscript) > float_ram_utilisation_threshold
);
};
const void_main = async () => {
const
float_period = object_netscript.args[0],
string_servers_bought_name = object_netscript.args[1],
float_ram_utilisation_threshold = object_netscript.args[2];
for (
;
;
) {
// Replace servers with better ones.
for (
;
boolean_conditions_server_replace(float_ram_utilisation_threshold);
) {
object_netscript.deleteServer(
string_get_server_bought_smallest(
object_netscript.getPurchasedServers()
)
);
const integer_ram_biggest_can_buy = integer_get_ram_biggest_can_buy();
object_netscript.purchaseServer(
`${string_servers_bought_name}-${integer_ram_biggest_can_buy}`,
integer_ram_biggest_can_buy
),
await object_netscript.sleep(float_period);
}
// Buy servers.
for (
;
boolean_conditions_server_buy(float_ram_utilisation_threshold);
) {
const integer_ram_biggest_can_buy = integer_get_ram_biggest_can_buy();
object_netscript.purchaseServer(
`${string_servers_bought_name}-${integer_ram_biggest_can_buy}`,
integer_ram_biggest_can_buy
),
await object_netscript.sleep(float_period);
}
await object_netscript.sleep(float_period);
}
};
await void_main();
};