From 7f4102ab05e30b0c06dd016da64bb19cdf0a18bb Mon Sep 17 00:00:00 2001 From: Massaki Archambault Date: Tue, 19 Sep 2023 17:40:32 -0400 Subject: [PATCH] solve "Generate IP Addresses" --- src/contractor.js | 211 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 168 insertions(+), 43 deletions(-) diff --git a/src/contractor.js b/src/contractor.js index 60e89e4..55e6e45 100644 --- a/src/contractor.js +++ b/src/contractor.js @@ -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() }], ["Spiralize Matrix", (data) => { @@ -230,8 +230,133 @@ export async function main(ns) { } 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) => { 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 key = data[1].split("") - let anwser = "" + let answer = "" let keyIndex = 0 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 II") //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 II") // ns.codingcontract.createDummyContract("Algorithmic Stock Trader III") @@ -367,45 +492,45 @@ export async function main(ns) { // ns.codingcontract.createDummyContract("Encryption I: Caesar Cipher") // ok // ns.codingcontract.createDummyContract("Encryption II: Vigenère Cipher") // ok - // 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')) { - const contractType = ns.codingcontract.getContractType(contract, server) - ns.print(`found contract ${contract} of type "${contractType}" on server ${server}`) - if (solvers.has(contractType)) { - const anwser = solvers.get(contractType)(ns.codingcontract.getData(contract, server)) - const reward = ns.codingcontract.attempt(anwser, contract, server) - if (anwser == "") { - ns.print(`ERROR: failed to solve contract! anwser = ${anwser}`) - break - } - else { - ns.print(reward) - } + 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 answer = solvers.get(contractType)(ns.codingcontract.getData(contract, server)) + const reward = ns.codingcontract.attempt(answer, contract, server) + if (reward == "") { + ns.print(`ERROR: failed to solve contract! answer = ${answer}`) + break } else { - ns.print(`WARNING: unknown contract type: ${contractType}`) + ns.print(reward) } } + else { + 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}`) + // } + // } + // } } \ No newline at end of file