1
0
Fork 0

Compare commits

..

4 Commits

6 changed files with 309 additions and 110 deletions

View File

@ -1,4 +1,4 @@
import { getServerTree } from "/lib/ServerTree.js" import { getServerTree } from "../lib/ServerTree.js"
/** @param {NS} ns */ /** @param {NS} ns */
export async function main(ns) { export async function main(ns) {
@ -26,7 +26,7 @@ export async function main(ns) {
// 2nd pass: walk the tree and backdoor servers // 2nd pass: walk the tree and backdoor servers
const backdoor = async (subtree) => { const backdoor = async (subtree) => {
if (!subtree.info.backdoorInstalled) { if (!subtree.info.backdoorInstalled && subtree.info.requiredHackingSkill <= ns.getHackingLevel()) {
ns.tprintf("backdoor %s, do not change server", subtree.info.hostname) ns.tprintf("backdoor %s, do not change server", subtree.info.hostname)
await ns.singularity.installBackdoor() await ns.singularity.installBackdoor()
ns.tprint("backdoor complete") ns.tprint("backdoor complete")

View File

@ -93,7 +93,7 @@ export async function main(ns) {
} }
} }
} }
// last entry in the table is our awnser // last entry in the table is our answer
return memoizationTable.pop() return memoizationTable.pop()
}], }],
["Spiralize Matrix", (data) => { ["Spiralize Matrix", (data) => {
@ -230,8 +230,133 @@ export async function main(ns) {
} }
return result return result
}], }],
// ["Generate IP Addresses", (data) => { ["Generate IP Addresses", (data) => {
// }], Array.prototype.swap = function (a, b) {
this[a] = this.splice(b, 1, this[a])[0];
return this;
}
// https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
const permute = (a) => {
// 1. Find the largest index k such that a[k] < a[k + 1]. If no such index exists, the permutation is the last permutation.
let k = a.length - 2
while (a[k] >= a[k + 1]) {
k--
if (k < 0) {
return false
}
}
// 2. Find the largest index l greater than k such that a[k] < a[l].
let l = a.length - 1
while (a[k] >= a[l]) {
l--
}
// 3. Swap the value of a[k] with that of a[l].
a.swap(k, l);
// 4. Reverse the sequence from a[k + 1] up to and including the final element a[n].
const length = a.length - (k + 1)
for (let i = 0; i < length / 2; i++) {
a.swap(k + 1 + i, a.length - i - 1)
}
return true
}
const genIp = (data, digitPermutation) => {
let octets = []
let i = 0
for (const digitCount of digitPermutation) {
let newOctet = data.slice(i, i + digitCount)
// sanity tests
if (parseInt(newOctet) > 255) {
return null
}
if (newOctet.length != 1 && newOctet[0] === "0") {
return null
}
octets.push(newOctet)
i += digitCount
}
return octets.join(".")
}
// build the couple first permutations
// dumb, but it works
let basePermutations = []
switch (data.length) {
case 4:
basePermutations = [
[1, 1, 1, 1],
]
break
case 5:
basePermutations = [
[1, 1, 1, 2],
]
break
case 6:
basePermutations = [
[1, 1, 1, 3],
[1, 1, 2, 2],
]
break
case 7:
basePermutations = [
[1, 1, 2, 3],
[1, 2, 2, 2],
]
break
case 8:
basePermutations = [
[1, 2, 2, 3],
[1, 1, 3, 3],
[2, 2, 2, 2],
]
break
case 9:
basePermutations = [
[2, 2, 2, 3],
[1, 2, 3, 3],
]
break
case 10:
basePermutations = [
[2, 2, 3, 3],
[1, 3, 3, 3],
]
break
case 11:
basePermutations = [
[2, 3, 3, 3],
]
break
case 12:
basePermutations = [
[3, 3, 3, 3],
]
break
}
// permute
let digitPermutations = []
for (let i = basePermutations.length - 1; i >= 0; i--) {
let currentDigitPermutation = basePermutations[i]
do {
// keep a copy of the current permutation
digitPermutations.push(currentDigitPermutation.slice(0))
} while (permute(currentDigitPermutation)) // permute until we are done
}
// generate ips
let ips = []
for (const digitPermutation of digitPermutations) {
const ip = genIp(data, digitPermutation)
if (ip != null) {
ips.push(ip)
}
}
return ips
}],
["HammingCodes: Integer to Encoded Binary", (data) => { ["HammingCodes: Integer to Encoded Binary", (data) => {
const dataBits = data.toString(2).split("").map(x => parseInt(x)) const dataBits = data.toString(2).split("").map(x => parseInt(x))
@ -330,12 +455,12 @@ export async function main(ns) {
const plaintext = data[0].split("") const plaintext = data[0].split("")
const key = data[1].split("") const key = data[1].split("")
let anwser = "" let answer = ""
let keyIndex = 0 let keyIndex = 0
for (const char of plaintext) { for (const char of plaintext) {
anwser += cypher(char, key[keyIndex++ % key.length]) answer += cypher(char, key[keyIndex++ % key.length])
} }
return anwser return answer
}] }]
]) ])
@ -347,7 +472,7 @@ export async function main(ns) {
// ns.codingcontract.createDummyContract("Array Jumping Game") // ok // ns.codingcontract.createDummyContract("Array Jumping Game") // ok
// ns.codingcontract.createDummyContract("Array Jumping Game II") //ok // ns.codingcontract.createDummyContract("Array Jumping Game II") //ok
// ns.codingcontract.createDummyContract("Merge Overlapping Intervals") // ok // ns.codingcontract.createDummyContract("Merge Overlapping Intervals") // ok
// ns.codingcontract.createDummyContract("Generate IP Addresses") // ns.codingcontract.createDummyContract("Generate IP Addresses") // ok
// ns.codingcontract.createDummyContract("Algorithmic Stock Trader I") // ns.codingcontract.createDummyContract("Algorithmic Stock Trader I")
// ns.codingcontract.createDummyContract("Algorithmic Stock Trader II") // ns.codingcontract.createDummyContract("Algorithmic Stock Trader II")
// ns.codingcontract.createDummyContract("Algorithmic Stock Trader III") // ns.codingcontract.createDummyContract("Algorithmic Stock Trader III")
@ -367,36 +492,16 @@ export async function main(ns) {
// ns.codingcontract.createDummyContract("Encryption I: Caesar Cipher") // ok // ns.codingcontract.createDummyContract("Encryption I: Caesar Cipher") // ok
// ns.codingcontract.createDummyContract("Encryption II: Vigenère Cipher") // ok // ns.codingcontract.createDummyContract("Encryption II: Vigenère Cipher") // ok
// const server = "home" const server = "home"
// for (const contract of ns.ls(server, '.cct')) {
// const contractType = ns.codingcontract.getContractType(contract, server)
// ns.print(`found contract ${contract} of type "${contractType}" on server ${server}`)
// if (solvers.has(contractType)) {
// ns.print("attempting to solve")
// const anwser = solvers.get(contractType)(ns.codingcontract.getData(contract, server))
// const reward = ns.codingcontract.attempt(anwser, contract, server)
// if (reward == "") {
// ns.print(`ERROR: failed to solve contract! anwser = ${anwser}`)
// break
// }
// else {
// ns.print(reward)
// }
// }
// else {
// ns.print(`WARNING: unknown contract type: ${contractType}`)
// }
// }
for (const server of getServers()) {
for (const contract of ns.ls(server, '.cct')) { for (const contract of ns.ls(server, '.cct')) {
const contractType = ns.codingcontract.getContractType(contract, server) const contractType = ns.codingcontract.getContractType(contract, server)
ns.print(`found contract ${contract} of type "${contractType}" on server ${server}`) ns.print(`found contract ${contract} of type "${contractType}" on server ${server}`)
if (solvers.has(contractType)) { if (solvers.has(contractType)) {
const anwser = solvers.get(contractType)(ns.codingcontract.getData(contract, server)) ns.print("attempting to solve")
const reward = ns.codingcontract.attempt(anwser, contract, server) const answer = solvers.get(contractType)(ns.codingcontract.getData(contract, server))
if (anwser == "") { const reward = ns.codingcontract.attempt(answer, contract, server)
ns.print(`ERROR: failed to solve contract! anwser = ${anwser}`) if (reward == "") {
ns.print(`ERROR: failed to solve contract! answer = ${answer}`)
break break
} }
else { else {
@ -407,5 +512,25 @@ export async function main(ns) {
ns.print(`WARNING: unknown contract type: ${contractType}`) ns.print(`WARNING: unknown contract type: ${contractType}`)
} }
} }
}
// for (const server of getServers()) {
// for (const contract of ns.ls(server, '.cct')) {
// const contractType = ns.codingcontract.getContractType(contract, server)
// ns.print(`found contract ${contract} of type "${contractType}" on server ${server}`)
// if (solvers.has(contractType)) {
// const answer = solvers.get(contractType)(ns.codingcontract.getData(contract, server))
// const reward = ns.codingcontract.attempt(answer, contract, server)
// if (answer == "") {
// ns.print(`ERROR: failed to solve contract! answer = ${answer}`)
// break
// }
// else {
// ns.print(reward)
// }
// }
// else {
// ns.print(`WARNING: unknown contract type: ${contractType}`)
// }
// }
// }
} }

View File

@ -4,21 +4,21 @@ export async function main(ns) {
ns.tail() ns.tail()
ns.disableLog('ALL') ns.disableLog('ALL')
// config /** CCONFIG **/
/* Maximum number of members in a gang */ /* Maximum number of members in a gang */
const MAX_MEMBER_COUNT = 12 const MAX_MEMBER_COUNT = 12
/* Percent of training to the next ascension a member must do after ascending */ /* Percent of training to the next ascension a member must do after ascending */
const MIN_ASCENSION_PERCENT = 0.9 const MIN_ASCENSION_PERCENT = 0.95
/* Minimum power level a member must reach before transitioning to gang war/money making */ /* Minimum power level a member must reach before transitioning to gang war/money making */
const MIN_POWER_LEVEL = 15 const MIN_POWER_LEVEL = 15
/* Win chance required to start a gang war */ /* Minimum win chance required to start a gang war */
const GANG_WAR_START_TRESH = 0.6 const GANG_WAR_START_TRESH = 0.6
/* Minimum win chance before pulling out of a gang war */ /* Minimum win chance before pulling out of a gang war */
const GANG_WAR_STOP_TRESH = 0.55 const GANG_WAR_STOP_TRESH = 0.55
/* Target win chance */ /* Target win chance */
const GANG_WAR_TARGET = 0.9 const GANG_WAR_TARGET = 0.95
// enum /** CONSTANTS **/
const MAKE_MONEY = "Human Trafficking" const MAKE_MONEY = "Human Trafficking"
const VIGILANTE_JUSTICE = "Vigilante Justice" const VIGILANTE_JUSTICE = "Vigilante Justice"
const MUG_PEOPLE = "Mug People" const MUG_PEOPLE = "Mug People"
@ -28,8 +28,9 @@ export async function main(ns) {
const PHASE_CATCHUP = "catchup" const PHASE_CATCHUP = "catchup"
const PHASE_RECRUIT = "recruit" const PHASE_RECRUIT = "recruit"
const PHASE_WAR = "war" const PHASE_TRAIN = "train"
const PHASE_MONEY = "money" const PHASE_WAR = "gang war"
const PHASE_MONEY = "make money"
const memberNamePool = [ const memberNamePool = [
"CJ", "CJ",
@ -119,7 +120,6 @@ export async function main(ns) {
// Credit: Mysteyes. https://discord.com/channels/415207508303544321/415207923506216971/940379724214075442 // Credit: Mysteyes. https://discord.com/channels/415207508303544321/415207923506216971/940379724214075442
function getAscendTreshold(memberName) { function getAscendTreshold(memberName) {
const memberInfo = ns.gang.getMemberInformation(memberName)
const mult = getMinAscMult(memberName) const mult = getMinAscMult(memberName)
if (mult < 1.632) return 1.6326; if (mult < 1.632) return 1.6326;
if (mult < 2.336) return 1.4315; if (mult < 2.336) return 1.4315;
@ -137,14 +137,11 @@ export async function main(ns) {
return 1.0591; return 1.0591;
} }
function isAscensionReady(memberName) { function isRecruitmentReady(power, memberCount) {
return getMinAscensionResult(memberName) >= getAscendTreshold(memberName) // the formula here is kinda arbitrary
} // increase the number of members in the gang linearly with the power of its members
// ns.print(power * 1.5 + 3)
function isRecruitementReady(relativePower, memberCount) { return power * 1.5 + 3 > memberCount
const res = relativePower * 1.25 + 2 > memberCount // TODO
ns.print(relativePower * 1.25 + 2)
return res
} }
function getGangWarWinChance() { function getGangWarWinChance() {
@ -158,106 +155,109 @@ export async function main(ns) {
while (true) { while (true) {
const gangInfo = ns.gang.getGangInformation() const gangInfo = ns.gang.getGangInformation()
ns.print("running loop")
// check for and recruit new members if available // check for and recruit new members if available
while (ns.gang.canRecruitMember()) { while (ns.gang.canRecruitMember()) {
const availableNames = memberNamePool.filter(x => memberNamePool.includes(x)) const availableNames = memberNamePool.filter(x => memberNamePool.includes(x))
const memberName = availableNames[Math.floor(Math.random() * availableNames.length)] const memberName = availableNames[Math.floor(Math.random() * availableNames.length)]
ns.gang.recruitMember(memberName) ns.gang.recruitMember(memberName)
ns.gang.setMemberTask(memberName, TRAIN_COMBAT)
}
const gangMembers = ns.gang.getMemberNames()
// check for and ascend members who are ready
for (const memberName of gangMembers) {
if (isAscensionReady(memberName)) {
// ns.print("ascending " + memberName)
ns.gang.ascendMember(memberName)
}
} }
// gang war // gang war
if (getGangWarWinChance() >= GANG_WAR_START_TRESH) { const gangWarWinChance = getGangWarWinChance()
if (gangWarWinChance >= GANG_WAR_START_TRESH) {
// go to war // go to war
ns.gang.setTerritoryWarfare(true) ns.gang.setTerritoryWarfare(true)
} }
else if (getGangWarWinChance() <= GANG_WAR_STOP_TRESH) { else if (gangWarWinChance <= GANG_WAR_STOP_TRESH) {
// disengage // disengage
ns.gang.setTerritoryWarfare(false) ns.gang.setTerritoryWarfare(false)
} }
// score each member by their estimated power level // create an 2-dimensional array of member data. We use an array because we need it to be sorted
let memberDatas = gangMembers.map(x => [x, { // 1st dimension is for each member
"relativePower": estimateMemberPower(x), // index 0 of 2nd dimension is the name of the member
// index 1 of 2nd dimension is the data
let gangMembers = ns.gang.getMemberNames().map(x => [x, {
"power": estimateMemberPower(x),
"minSkillLevel": getMinSkillLevel(x), "minSkillLevel": getMinSkillLevel(x),
"ascensionPercent": getMinAscensionResult(x) / getAscendTreshold(x), "ascensionPercent": getMinAscensionResult(x) / getAscendTreshold(x),
"phase": undefined, "phase": undefined,
"training": false, "training": false,
"vigilante": false, "vigilante": false,
}]) }])
memberDatas.sort((a, b) => b[1]["relativePower"] - a[1]["relativePower"]) // sort by their power
const targetRelativePower = memberDatas[0][1]["relativePower"] - 2 gangMembers.sort((a, b) => b[1]["power"] - a[1]["power"])
// the highest power level is the target new members needs to catchup to
for (const memberData of memberDatas) { const targetPower = gangMembers[0][1]["power"] - 2
const memberName = memberData[0] // check if we are ready to recruit a new member
const relativePower = memberData[1]["relativePower"] const recruitmentReady = isRecruitmentReady(targetPower, gangMembers.length)
const minSkillLevel = memberData[1]["minSkillLevel"]
const ascensionPercent = memberData[1]["ascensionPercent"]
for (const member of gangMembers) {
const memberName = member[0]
const memberData = member[1]
const power = memberData["power"]
const minSkillLevel = memberData["minSkillLevel"]
const ascensionPercent = memberData["ascensionPercent"]
// compute the phase of each members // compute the phase of each members
if (relativePower < targetRelativePower) { if (power < targetPower) {
// bring up newcomers to the same level than established members // bring up newcomers to the same level than established members
memberData[1]["phase"] = PHASE_CATCHUP memberData["phase"] = PHASE_CATCHUP
} }
else if (gangMembers.length < MAX_MEMBER_COUNT && isRecruitementReady(targetRelativePower, gangMembers.length)) { else if (gangMembers.length < MAX_MEMBER_COUNT) {
// gain respect to recruit new member // gain respect to recruit new member
memberData[1]["phase"] = PHASE_RECRUIT memberData["phase"] = PHASE_RECRUIT
} }
else if (gangInfo.territory < 1 && getGangWarWinChance() < GANG_WAR_TARGET) { else if (power < MIN_POWER_LEVEL) {
// power up until useful enough
memberData["phase"] = PHASE_TRAIN
}
else if (gangInfo.territory < 1 && gangWarWinChance < GANG_WAR_TARGET) {
// prepare for gang war // prepare for gang war
memberData[1]["phase"] = PHASE_WAR memberData["phase"] = PHASE_WAR
} }
else { else {
// if everything else is done, make money // if everything else is done, make money
memberData[1]["phase"] = PHASE_MONEY memberData["phase"] = PHASE_MONEY
} }
if (memberData[1]["phase"] == PHASE_CATCHUP) { // assign tasks
// strategy is:
// catchup -> recruit <-> train -> gang war <-> make money
// reduce wanted level as needed
if (memberData["phase"] == PHASE_CATCHUP) {
ns.print("assignment: catchup") ns.print("assignment: catchup")
ns.gang.setMemberTask(memberName, TRAIN_COMBAT) ns.gang.setMemberTask(memberName, TRAIN_COMBAT)
memberData[1]["training"] = true memberData["training"] = true
} }
else if (ascensionPercent < MIN_ASCENSION_PERCENT) { // TODO: arbitrary constant to be ajusted else if (isNaN(ascensionPercent) || ascensionPercent < MIN_ASCENSION_PERCENT) { // TODO: arbitrary constant to be ajusted
ns.print("assignment: level up after ascension") ns.print("assignment: level up after ascension")
// train a member back up after ascention // train a member back up after ascention
ns.gang.setMemberTask(memberName, TRAIN_COMBAT) ns.gang.setMemberTask(memberName, TRAIN_COMBAT)
memberData[1]["training"] = true memberData["training"] = true
} }
else if (gangInfo.wantedPenalty < 0) { else if (gangInfo.wantedPenalty < 0) {
ns.print("assignment: reduce wanted level") ns.print("assignment: reduce wanted level")
// try to keep the wanted penalty at 0% // try to keep the wanted penalty at 0%
ns.gang.setMemberTask(memberName, VIGILANTE_JUSTICE) ns.gang.setMemberTask(memberName, VIGILANTE_JUSTICE)
memberData[1]["vigilante"] = true memberData["vigilante"] = true
} }
else if (memberData[1]["phase"] == PHASE_RECRUIT) { else if (memberData["phase"] == PHASE_RECRUIT && recruitmentReady) {
ns.print("assignment: gain respect to recruit new members") ns.print("assignment: gain respect to recruit new members")
if (minSkillLevel < 500) { if (minSkillLevel < 250) {
ns.gang.setMemberTask(memberName, MUG_PEOPLE) ns.gang.setMemberTask(memberName, MUG_PEOPLE)
} }
else { else {
ns.gang.setMemberTask(memberName, TERRORISM) ns.gang.setMemberTask(memberName, TERRORISM)
} }
} }
else if (relativePower < MIN_POWER_LEVEL) { else if (memberData["phase"] == PHASE_RECRUIT || memberData["phase"] == PHASE_TRAIN) {
ns.print("assignment: train") ns.print("assignment: train")
// train up to next ascention // train up to next ascention
ns.gang.setMemberTask(memberName, TRAIN_COMBAT) ns.gang.setMemberTask(memberName, TRAIN_COMBAT)
memberData[1]["training"] = true memberData["training"] = true
} }
else if (memberData[1]["phase"] == PHASE_WAR) { else if (memberData["phase"] == PHASE_WAR) {
ns.print("assignment: gang war") ns.print("assignment: gang war")
ns.gang.setMemberTask(memberName, TERRITORY_WARFARE) ns.gang.setMemberTask(memberName, TERRITORY_WARFARE)
} }
@ -267,14 +267,20 @@ export async function main(ns) {
} }
// buy equipement // buy equipement
if (memberData[1]["phase"] == PHASE_WAR || memberData[1]["phase"] == PHASE_MONEY) { if (memberData["phase"] == PHASE_WAR || memberData["phase"] == PHASE_MONEY) {
for (const equipment of equipments) { for (const equipment of equipments) {
ns.gang.purchaseEquipment(memberName, equipment) ns.gang.purchaseEquipment(memberName, equipment)
} }
} }
ns.print(getMinAscensionResult(memberName) / getAscendTreshold(memberName))
// ascend members who are ready
if (ascensionPercent >= 1 &&
!(memberData["phase"] == PHASE_RECRUIT && memberData["training"] == false)) { // avoid ascending a member that has built up respect to recruit a new member
// ns.print("ascending " + memberName)
ns.gang.ascendMember(memberName)
} }
ns.print(memberDatas) }
ns.print(gangMembers)
await ns.sleep(5000) await ns.sleep(5000)
} }
} }

50
src/gang/gang-prepare.js Normal file
View File

@ -0,0 +1,50 @@
/** @param {NS} ns */
export async function main(ns) {
ns.clearLog()
ns.tail()
ns.disableLog('sleep')
const START_SKILL_LEVEL = 80
const GYM_NAME = "powerhouse gym"
const FACTION = "Slum Snakes"
const skills = [
"strength",
"defense",
"dexterity",
"agility"
]
// skillup
for (const skill of skills) {
let player = ns.getPlayer()
if (player.skills[skill] < START_SKILL_LEVEL) {
ns.singularity.gymWorkout(GYM_NAME, skill, ns.singularity.isFocused())
while(player.skills[skill] < START_SKILL_LEVEL) {
await ns.sleep(1000)
player = ns.getPlayer()
}
}
}
// generate bad karma
ns.singularity.commitCrime("Homicide", ns.singularity.isFocused())
// join faction
if(!ns.getPlayer().factions.includes(FACTION)) {
while(!ns.singularity.checkFactionInvitations().includes(FACTION)) {
await ns.sleep(1000)
}
ns.singularity.joinFaction(FACTION)
}
// create gang
while(!ns.gang.inGang()) {
await ns.sleep(1000)
ns.gang.createGang(FACTION)
}
// Start gang management script
ns.singularity.commitCrime("Kidnap", ns.singularity.isFocused())
ns.spawn("/gang/gang-manage.js")
}

View File

@ -1,5 +1,23 @@
/** @param {NS} ns */ /** @param {NS} ns */
const importantHosts = ["CSEC", "avmnite-02h", "I.I.I.I", "run4theh111z", "w0r1d_d43m0n"] export const IMPORTANT_HOST = [
// services
"iron-gym",
"crush-fitness",
"powerhouse-fitness",
"millenium-fitness",
"snap-fitness",
"rothman-uni",
"summit-uni",
// factions
"CSEC",
"avmnite-02h",
"I.I.I.I",
"run4theh111z",
// end bitnode
"w0r1d_d43m0n"
]
class ServerTreeNode { class ServerTreeNode {
constructor(ns, serverName) { constructor(ns, serverName) {
@ -28,7 +46,7 @@ class ServerTreeNode {
} }
this.ns.tprintf( this.ns.tprintf(
"%s %s %s %4s %s", "%s %s %s %4s %s",
importantHosts.includes(this.serverName) ? "!" : " ", IMPORTANT_HOST.includes(this.serverName) ? "!" : " ",
this.info.hasAdminRights ? "Y" : "N", this.info.hasAdminRights ? "Y" : "N",
this.info.openPortCount, this.info.openPortCount,
this.info.requiredHackingSkill, this.info.requiredHackingSkill,

View File

@ -1,4 +1,4 @@
import {getServerTree} from '/lib/ServerTree.js' import {getServerTree} from './lib/ServerTree.js'
/** @param {NS} ns */ /** @param {NS} ns */
export async function main(ns) { export async function main(ns) {