mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-05-05 23:27:55 +02:00
CONTRACTS: Display contract answers on completely failed contracts (#2440)
This commit is contained in:
@@ -82,6 +82,10 @@ export class CodingContract {
|
|||||||
this.reward = reward;
|
this.reward = reward;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAnswer() {
|
||||||
|
return CodingContractTypes[this.type].getAnswer(this.state);
|
||||||
|
}
|
||||||
|
|
||||||
getData(): unknown {
|
getData(): unknown {
|
||||||
const func = CodingContractTypes[this.type].getData;
|
const func = CodingContractTypes[this.type].getData;
|
||||||
return func ? func(this.state) : this.state;
|
return func ? func(this.state) : this.state;
|
||||||
|
|||||||
@@ -33,11 +33,13 @@ interface CodingContractType<Data, Answer, State = Data> {
|
|||||||
difficulty: number;
|
difficulty: number;
|
||||||
/** Function that generates a valid 'state' for a contract type */
|
/** Function that generates a valid 'state' for a contract type */
|
||||||
generate: () => State;
|
generate: () => State;
|
||||||
|
/** Function that returns an answer, if possible, for a given contract */
|
||||||
|
getAnswer: (data: Data) => Answer | null;
|
||||||
/**
|
/**
|
||||||
* Transforms the 'state' for a contract into its 'data'. The state is
|
* Transforms the 'state' for a contract into its 'data'. The state is
|
||||||
* stored persistently as JSON, so it must be serializable. The data is what
|
* stored persistently as JSON, so it must be serializable. The data is what
|
||||||
* is given to the user and shown in the description. If this function is
|
* is given to the user and shown in the description. If this function is
|
||||||
* ommitted, it will be the identity function (i.e. State == Data).
|
* omitted, it will be the identity function (i.e. State == Data).
|
||||||
* You can use this to make problems where the "solver" is not a function
|
* You can use this to make problems where the "solver" is not a function
|
||||||
* that can be copy-pasted to user code to solve the problem.
|
* that can be copy-pasted to user code to solve the problem.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -33,15 +33,17 @@ export const algorithmicStockTrader: Pick<
|
|||||||
return arr;
|
return arr;
|
||||||
},
|
},
|
||||||
numTries: 5,
|
numTries: 5,
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
let maxCur = 0;
|
let maxCur = 0;
|
||||||
let maxSoFar = 0;
|
let maxSoFar = 0;
|
||||||
for (let i = 1; i < data.length; ++i) {
|
for (let i = 1; i < data.length; ++i) {
|
||||||
maxCur = Math.max(0, (maxCur += data[i] - data[i - 1]));
|
maxCur = Math.max(0, (maxCur += data[i] - data[i - 1]));
|
||||||
maxSoFar = Math.max(maxCur, maxSoFar);
|
maxSoFar = Math.max(maxCur, maxSoFar);
|
||||||
}
|
}
|
||||||
|
return maxSoFar;
|
||||||
return maxSoFar === answer;
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return algorithmicStockTrader[CodingContractName.AlgorithmicStockTraderI].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
@@ -71,13 +73,16 @@ export const algorithmicStockTrader: Pick<
|
|||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
let profit = 0;
|
let profit = 0;
|
||||||
for (let p = 1; p < data.length; ++p) {
|
for (let p = 1; p < data.length; ++p) {
|
||||||
profit += Math.max(data[p] - data[p - 1], 0);
|
profit += Math.max(data[p] - data[p - 1], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return profit === answer;
|
return profit;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return algorithmicStockTrader[CodingContractName.AlgorithmicStockTraderII].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
@@ -107,7 +112,7 @@ export const algorithmicStockTrader: Pick<
|
|||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
let hold1 = Number.MIN_SAFE_INTEGER;
|
let hold1 = Number.MIN_SAFE_INTEGER;
|
||||||
let hold2 = Number.MIN_SAFE_INTEGER;
|
let hold2 = Number.MIN_SAFE_INTEGER;
|
||||||
let release1 = 0;
|
let release1 = 0;
|
||||||
@@ -119,7 +124,10 @@ export const algorithmicStockTrader: Pick<
|
|||||||
hold1 = Math.max(hold1, price * -1);
|
hold1 = Math.max(hold1, price * -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return release2 === answer;
|
return release2;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return algorithmicStockTrader[CodingContractName.AlgorithmicStockTraderIII].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
@@ -154,13 +162,13 @@ export const algorithmicStockTrader: Pick<
|
|||||||
|
|
||||||
return [k, prices];
|
return [k, prices];
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
const k: number = data[0];
|
const k: number = data[0];
|
||||||
const prices: number[] = data[1];
|
const prices: number[] = data[1];
|
||||||
|
|
||||||
const len = prices.length;
|
const len = prices.length;
|
||||||
if (len < 2) {
|
if (len < 2) {
|
||||||
return answer === 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (k > len / 2) {
|
if (k > len / 2) {
|
||||||
let res = 0;
|
let res = 0;
|
||||||
@@ -168,7 +176,7 @@ export const algorithmicStockTrader: Pick<
|
|||||||
res += Math.max(prices[i] - prices[i - 1], 0);
|
res += Math.max(prices[i] - prices[i - 1], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res === answer;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hold: number[] = [];
|
const hold: number[] = [];
|
||||||
@@ -189,7 +197,10 @@ export const algorithmicStockTrader: Pick<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rele[k] === answer;
|
return rele[k];
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return algorithmicStockTrader[CodingContractName.AlgorithmicStockTraderIV].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
|
|||||||
@@ -37,14 +37,17 @@ export const arrayJumpingGame: Pick<
|
|||||||
return arr;
|
return arr;
|
||||||
},
|
},
|
||||||
numTries: 1,
|
numTries: 1,
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
const n: number = data.length;
|
const n: number = data.length;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (let reach = 0; i < n && i <= reach; ++i) {
|
for (let reach = 0; i < n && i <= reach; ++i) {
|
||||||
reach = Math.max(i + data[i], reach);
|
reach = Math.max(i + data[i], reach);
|
||||||
}
|
}
|
||||||
const solution: boolean = i === n;
|
const solution: boolean = i === n;
|
||||||
return (solution ? 1 : 0) === answer;
|
return solution ? 1 : 0;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return arrayJumpingGame[CodingContractName.ArrayJumpingGame].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => {
|
convertAnswer: (ans) => {
|
||||||
const num = parseInt(ans);
|
const num = parseInt(ans);
|
||||||
@@ -85,7 +88,7 @@ export const arrayJumpingGame: Pick<
|
|||||||
return arr;
|
return arr;
|
||||||
},
|
},
|
||||||
numTries: 3,
|
numTries: 3,
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
const n: number = data.length;
|
const n: number = data.length;
|
||||||
let reach = 0;
|
let reach = 0;
|
||||||
let jumps = 0;
|
let jumps = 0;
|
||||||
@@ -105,7 +108,10 @@ export const arrayJumpingGame: Pick<
|
|||||||
lastJump = jumpedFrom;
|
lastJump = jumpedFrom;
|
||||||
jumps++;
|
jumps++;
|
||||||
}
|
}
|
||||||
return jumps === answer;
|
return jumps;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return arrayJumpingGame[CodingContractName.ArrayJumpingGameII].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { CodingContractTypes } from "../ContractTypes";
|
import { CodingContractTypes } from "../ContractTypes";
|
||||||
|
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||||
import { CodingContractName } from "@enums";
|
import { CodingContractName } from "@enums";
|
||||||
|
|
||||||
export const compression: Pick<
|
export const compression: Pick<
|
||||||
@@ -49,8 +50,8 @@ export const compression: Pick<
|
|||||||
|
|
||||||
return plain.substring(0, length);
|
return plain.substring(0, length);
|
||||||
},
|
},
|
||||||
solver: (plain, answer) => {
|
getAnswer: (plain) => {
|
||||||
if (plain.length === 0) return answer === "";
|
if (plain.length === 0) return "";
|
||||||
|
|
||||||
let out = "";
|
let out = "";
|
||||||
let count = 1;
|
let count = 1;
|
||||||
@@ -63,7 +64,10 @@ export const compression: Pick<
|
|||||||
count = 1;
|
count = 1;
|
||||||
}
|
}
|
||||||
out += count + plain[plain.length - 1];
|
out += count + plain[plain.length - 1];
|
||||||
return out === answer;
|
return out;
|
||||||
|
},
|
||||||
|
solver: (plain, answer) => {
|
||||||
|
return compression[CodingContractName.CompressionIRLECompression].getAnswer(plain) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => ans.replace(/\s/g, ""),
|
convertAnswer: (ans) => ans.replace(/\s/g, ""),
|
||||||
validateAnswer: (ans): ans is string => typeof ans === "string",
|
validateAnswer: (ans): ans is string => typeof ans === "string",
|
||||||
@@ -97,8 +101,11 @@ export const compression: Pick<
|
|||||||
generate: (): string => {
|
generate: (): string => {
|
||||||
return comprLZEncode(comprLZGenerate());
|
return comprLZEncode(comprLZGenerate());
|
||||||
},
|
},
|
||||||
|
getAnswer: (compr) => {
|
||||||
|
return comprLZDecode(compr) ?? "";
|
||||||
|
},
|
||||||
solver: (compr, answer) => {
|
solver: (compr, answer) => {
|
||||||
return (comprLZDecode(compr) ?? "") === answer;
|
return compression[CodingContractName.CompressionIILZDecompression].getAnswer(compr) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => ans.replace(/\s/g, ""),
|
convertAnswer: (ans) => ans.replace(/\s/g, ""),
|
||||||
validateAnswer: (ans): ans is string => typeof ans === "string",
|
validateAnswer: (ans): ans is string => typeof ans === "string",
|
||||||
@@ -135,8 +142,20 @@ export const compression: Pick<
|
|||||||
generate: (): string => {
|
generate: (): string => {
|
||||||
return comprLZGenerate();
|
return comprLZGenerate();
|
||||||
},
|
},
|
||||||
|
getAnswer: (plain) => {
|
||||||
|
return comprLZEncode(plain);
|
||||||
|
},
|
||||||
solver: (plain, answer) => {
|
solver: (plain, answer) => {
|
||||||
return answer.length <= comprLZEncode(plain).length && comprLZDecode(answer) === plain;
|
const encoded = compression[CodingContractName.CompressionIIILZCompression].getAnswer(plain);
|
||||||
|
if (encoded === null) {
|
||||||
|
exceptionAlert(
|
||||||
|
new Error(
|
||||||
|
`Unexpected null when calculating the answer for ${CodingContractName.CompressionIIILZCompression} contract. Data: ${plain}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return answer.length <= encoded.length && comprLZDecode(answer) === plain;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => ans.replace(/\s/g, ""),
|
convertAnswer: (ans) => ans.replace(/\s/g, ""),
|
||||||
validateAnswer: (ans): ans is string => typeof ans === "string",
|
validateAnswer: (ans): ans is string => typeof ans === "string",
|
||||||
|
|||||||
@@ -57,13 +57,16 @@ export const encryption: Pick<
|
|||||||
Math.floor(Math.random() * 25 + 1),
|
Math.floor(Math.random() * 25 + 1),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
// data = [plaintext, shift value]
|
// data = [plaintext, shift value]
|
||||||
// build char array, shifting via map and join to final results
|
// build char array, shifting via map and join to final results
|
||||||
const cipher = [...data[0]]
|
const cipher = [...data[0]]
|
||||||
.map((a) => (a === " " ? a : String.fromCharCode(((a.charCodeAt(0) - 65 - data[1] + 26) % 26) + 65)))
|
.map((a) => (a === " " ? a : String.fromCharCode(((a.charCodeAt(0) - 65 - data[1] + 26) % 26) + 65)))
|
||||||
.join("");
|
.join("");
|
||||||
return cipher === answer;
|
return cipher;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return encryption[CodingContractName.EncryptionICaesarCipher].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => ans,
|
convertAnswer: (ans) => ans,
|
||||||
validateAnswer: (ans): ans is string => typeof ans === "string",
|
validateAnswer: (ans): ans is string => typeof ans === "string",
|
||||||
@@ -222,7 +225,7 @@ export const encryption: Pick<
|
|||||||
keys.sort(() => Math.random() - 0.5)[0],
|
keys.sort(() => Math.random() - 0.5)[0],
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
// data = [plaintext, keyword]
|
// data = [plaintext, keyword]
|
||||||
// build char array, shifting via map and corresponding keyword letter and join to final results
|
// build char array, shifting via map and corresponding keyword letter and join to final results
|
||||||
const cipher = [...data[0]]
|
const cipher = [...data[0]]
|
||||||
@@ -232,7 +235,10 @@ export const encryption: Pick<
|
|||||||
: String.fromCharCode(((a.charCodeAt(0) - 2 * 65 + data[1].charCodeAt(i % data[1].length)) % 26) + 65);
|
: String.fromCharCode(((a.charCodeAt(0) - 2 * 65 + data[1].charCodeAt(i % data[1].length)) % 26) + 65);
|
||||||
})
|
})
|
||||||
.join("");
|
.join("");
|
||||||
return cipher === answer;
|
return cipher;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return encryption[CodingContractName.EncryptionIIVigenereCipher].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => ans,
|
convertAnswer: (ans) => ans,
|
||||||
validateAnswer: (ans): ans is string => typeof ans === "string",
|
validateAnswer: (ans): ans is string => typeof ans === "string",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { filterTruthy } from "../../utils/helpers/ArrayHelpers";
|
import { filterTruthy } from "../../utils/helpers/ArrayHelpers";
|
||||||
|
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||||
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
||||||
import { CodingContractTypes, removeBracketsFromArrayString, removeQuotesFromString } from "../ContractTypes";
|
import { CodingContractTypes, removeBracketsFromArrayString, removeQuotesFromString } from "../ContractTypes";
|
||||||
import { CodingContractName } from "@enums";
|
import { CodingContractName } from "@enums";
|
||||||
@@ -47,7 +48,7 @@ export const findAllValidMathExpressions: Pick<CodingContractTypes, CodingContra
|
|||||||
|
|
||||||
return [digits, target];
|
return [digits, target];
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
const num = data[0];
|
const num = data[0];
|
||||||
const target = data[1];
|
const target = data[1];
|
||||||
|
|
||||||
@@ -86,6 +87,20 @@ export const findAllValidMathExpressions: Pick<CodingContractTypes, CodingContra
|
|||||||
const result: string[] = [];
|
const result: string[] = [];
|
||||||
helper(result, "", num, target, 0, 0, 0);
|
helper(result, "", num, target, 0, 0, 0);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
const result = findAllValidMathExpressions[CodingContractName.FindAllValidMathExpressions].getAnswer(data);
|
||||||
|
|
||||||
|
if (result === null) {
|
||||||
|
exceptionAlert(
|
||||||
|
new Error(
|
||||||
|
`Unexpected null when calculating the answer for ${CodingContractName.FindAllValidMathExpressions} contract. Data: ${data}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (result.length !== answer.length) return false;
|
if (result.length !== answer.length) return false;
|
||||||
|
|
||||||
const solutions = new Set(answer);
|
const solutions = new Set(answer);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const findLargestPrimeFactor: Pick<CodingContractTypes, CodingContractNam
|
|||||||
generate: (): number => {
|
generate: (): number => {
|
||||||
return getRandomIntInclusive(500, 1e9);
|
return getRandomIntInclusive(500, 1e9);
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
let fac = 2;
|
let fac = 2;
|
||||||
let n: number = data;
|
let n: number = data;
|
||||||
while (n > (fac - 1) * (fac - 1)) {
|
while (n > (fac - 1) * (fac - 1)) {
|
||||||
@@ -23,7 +23,10 @@ export const findLargestPrimeFactor: Pick<CodingContractTypes, CodingContractNam
|
|||||||
++fac;
|
++fac;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (n === 1 ? fac - 1 : n) === answer;
|
return n === 1 ? fac - 1 : n;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return findLargestPrimeFactor[CodingContractName.FindLargestPrimeFactor].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { CodingContractName } from "@enums";
|
import { CodingContractName } from "@enums";
|
||||||
import { CodingContractTypes, removeBracketsFromArrayString } from "../ContractTypes";
|
import { CodingContractTypes, removeBracketsFromArrayString } from "../ContractTypes";
|
||||||
|
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||||
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
||||||
|
|
||||||
export const generateIPAddresses: Pick<CodingContractTypes, CodingContractName.GenerateIPAddresses> = {
|
export const generateIPAddresses: Pick<CodingContractTypes, CodingContractName.GenerateIPAddresses> = {
|
||||||
@@ -28,7 +29,7 @@ export const generateIPAddresses: Pick<CodingContractTypes, CodingContractName.G
|
|||||||
|
|
||||||
return str;
|
return str;
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
const ret: string[] = [];
|
const ret: string[] = [];
|
||||||
for (let a = 1; a <= 3; ++a) {
|
for (let a = 1; a <= 3; ++a) {
|
||||||
for (let b = 1; b <= 3; ++b) {
|
for (let b = 1; b <= 3; ++b) {
|
||||||
@@ -51,6 +52,18 @@ export const generateIPAddresses: Pick<CodingContractTypes, CodingContractName.G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
const ret = generateIPAddresses[CodingContractName.GenerateIPAddresses].getAnswer(data);
|
||||||
|
if (ret === null) {
|
||||||
|
exceptionAlert(
|
||||||
|
new Error(
|
||||||
|
`Unexpected null when calculating the answer for ${CodingContractName.GenerateIPAddresses} contract. Data: ${data}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return ret.length === answer.length && ret.every((ip) => answer.includes(ip));
|
return ret.length === answer.length && ret.every((ip) => answer.includes(ip));
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => {
|
convertAnswer: (ans) => {
|
||||||
|
|||||||
@@ -36,8 +36,11 @@ export const hammingCode: Pick<
|
|||||||
const y = Math.pow(2, getRandomIntInclusive(1, 57));
|
const y = Math.pow(2, getRandomIntInclusive(1, 57));
|
||||||
return getRandomIntInclusive(Math.min(x, y), Math.max(x, y));
|
return getRandomIntInclusive(Math.min(x, y), Math.max(x, y));
|
||||||
},
|
},
|
||||||
|
getAnswer: (data) => {
|
||||||
|
return HammingEncode(data);
|
||||||
|
},
|
||||||
solver: (data, answer) => {
|
solver: (data, answer) => {
|
||||||
return HammingEncode(data) === answer;
|
return hammingCode[CodingContractName.HammingCodesIntegerToEncodedBinary].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => ans,
|
convertAnswer: (ans) => ans,
|
||||||
validateAnswer: (ans): ans is string => typeof ans === "string",
|
validateAnswer: (ans): ans is string => typeof ans === "string",
|
||||||
@@ -83,8 +86,11 @@ export const hammingCode: Pick<
|
|||||||
}
|
}
|
||||||
return _buildArray.join("");
|
return _buildArray.join("");
|
||||||
},
|
},
|
||||||
|
getAnswer: (data) => {
|
||||||
|
return HammingDecode(data);
|
||||||
|
},
|
||||||
solver: (data, answer) => {
|
solver: (data, answer) => {
|
||||||
return HammingDecode(data) === answer;
|
return hammingCode[CodingContractName.HammingCodesEncodedBinaryToInteger].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||||
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
||||||
import { CodingContractTypes, convert2DArrayToString, removeBracketsFromArrayString } from "../ContractTypes";
|
import { CodingContractTypes, convert2DArrayToString, removeBracketsFromArrayString } from "../ContractTypes";
|
||||||
import { CodingContractName } from "@enums";
|
import { CodingContractName } from "@enums";
|
||||||
@@ -30,7 +31,7 @@ export const mergeOverlappingIntervals: Pick<CodingContractTypes, CodingContract
|
|||||||
return intervals;
|
return intervals;
|
||||||
},
|
},
|
||||||
numTries: 15,
|
numTries: 15,
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
const intervals: [number, number][] = data.slice();
|
const intervals: [number, number][] = data.slice();
|
||||||
intervals.sort((a: [number, number], b: [number, number]) => {
|
intervals.sort((a: [number, number], b: [number, number]) => {
|
||||||
return a[0] - b[0];
|
return a[0] - b[0];
|
||||||
@@ -50,6 +51,22 @@ export const mergeOverlappingIntervals: Pick<CodingContractTypes, CodingContract
|
|||||||
}
|
}
|
||||||
result.push([start, end]);
|
result.push([start, end]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
const result = mergeOverlappingIntervals[CodingContractName.MergeOverlappingIntervals].getAnswer(data);
|
||||||
|
|
||||||
|
if (result === null) {
|
||||||
|
exceptionAlert(
|
||||||
|
new Error(
|
||||||
|
`Unexpected null when calculating the answer for ${
|
||||||
|
CodingContractName.MergeOverlappingIntervals
|
||||||
|
} contract. Data: ${JSON.stringify(data)}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return result.length === answer.length && result.every((a, i) => a[0] === answer[i][0] && a[1] === answer[i][1]);
|
return result.length === answer.length && result.every((a, i) => a[0] === answer[i][0] && a[1] === answer[i][1]);
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => {
|
convertAnswer: (ans) => {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export const minimumPathSumInATriangle: Pick<CodingContractTypes, CodingContract
|
|||||||
|
|
||||||
return triangle;
|
return triangle;
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
const n: number = data.length;
|
const n: number = data.length;
|
||||||
const dp: number[] = data[n - 1].slice();
|
const dp: number[] = data[n - 1].slice();
|
||||||
for (let i = n - 2; i > -1; --i) {
|
for (let i = n - 2; i > -1; --i) {
|
||||||
@@ -65,7 +65,10 @@ export const minimumPathSumInATriangle: Pick<CodingContractTypes, CodingContract
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dp[0] === answer;
|
return dp[0];
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return minimumPathSumInATriangle[CodingContractName.MinimumPathSumInATriangle].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
|
|||||||
@@ -75,6 +75,9 @@ export const proper2ColoringOfAGraph: Pick<CodingContractTypes, CodingContractNa
|
|||||||
|
|
||||||
return [n + m, edges];
|
return [n + m, edges];
|
||||||
},
|
},
|
||||||
|
getAnswer: () => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
solver: (data, answer) => {
|
solver: (data, answer) => {
|
||||||
//Helper function to get neighbourhood of a vertex
|
//Helper function to get neighbourhood of a vertex
|
||||||
function neighbourhood(vertex: number): number[] {
|
function neighbourhood(vertex: number): number[] {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||||
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
||||||
import { CodingContractTypes, removeBracketsFromArrayString, removeQuotesFromString } from "../ContractTypes";
|
import { CodingContractTypes, removeBracketsFromArrayString, removeQuotesFromString } from "../ContractTypes";
|
||||||
import { CodingContractName } from "@enums";
|
import { CodingContractName } from "@enums";
|
||||||
@@ -45,7 +46,7 @@ export const sanitizeParenthesesInExpression: Pick<
|
|||||||
|
|
||||||
return chars.join("");
|
return chars.join("");
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
let left = 0;
|
let left = 0;
|
||||||
let right = 0;
|
let right = 0;
|
||||||
const res: string[] = [];
|
const res: string[] = [];
|
||||||
@@ -94,6 +95,20 @@ export const sanitizeParenthesesInExpression: Pick<
|
|||||||
|
|
||||||
dfs(0, 0, left, right, data, "", res);
|
dfs(0, 0, left, right, data, "", res);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
const res = sanitizeParenthesesInExpression[CodingContractName.SanitizeParenthesesInExpression].getAnswer(data);
|
||||||
|
|
||||||
|
if (res === null) {
|
||||||
|
exceptionAlert(
|
||||||
|
new Error(
|
||||||
|
`Unexpected null when calculating the answer for ${CodingContractName.SanitizeParenthesesInExpression} contract. Data: ${data}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (res.length !== answer.length) return false;
|
if (res.length !== answer.length) return false;
|
||||||
return res.every((sol) => answer.includes(sol));
|
return res.every((sol) => answer.includes(sol));
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ export const shortestPathInAGrid: Pick<CodingContractTypes, CodingContractName.S
|
|||||||
|
|
||||||
return grid;
|
return grid;
|
||||||
},
|
},
|
||||||
|
getAnswer: () => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
solver: (data, answer) => {
|
solver: (data, answer) => {
|
||||||
const width = data[0].length;
|
const width = data[0].length;
|
||||||
const height = data.length;
|
const height = data.length;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { CodingContractName } from "@enums";
|
import { CodingContractName } from "@enums";
|
||||||
import { removeBracketsFromArrayString, type CodingContractTypes } from "../ContractTypes";
|
import { removeBracketsFromArrayString, type CodingContractTypes } from "../ContractTypes";
|
||||||
|
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||||
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
||||||
|
|
||||||
export const spiralizeMatrix: Pick<CodingContractTypes, CodingContractName.SpiralizeMatrix> = {
|
export const spiralizeMatrix: Pick<CodingContractTypes, CodingContractName.SpiralizeMatrix> = {
|
||||||
@@ -55,7 +56,7 @@ export const spiralizeMatrix: Pick<CodingContractTypes, CodingContractName.Spira
|
|||||||
|
|
||||||
return matrix;
|
return matrix;
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
const spiral: number[] = [];
|
const spiral: number[] = [];
|
||||||
const m: number = data.length;
|
const m: number = data.length;
|
||||||
const n: number = data[0].length;
|
const n: number = data[0].length;
|
||||||
@@ -107,6 +108,22 @@ export const spiralizeMatrix: Pick<CodingContractTypes, CodingContractName.Spira
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return spiral;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
const spiral = spiralizeMatrix[CodingContractName.SpiralizeMatrix].getAnswer(data);
|
||||||
|
|
||||||
|
if (spiral === null) {
|
||||||
|
exceptionAlert(
|
||||||
|
new Error(
|
||||||
|
`Unexpected null when calculating the answer for ${
|
||||||
|
CodingContractName.SpiralizeMatrix
|
||||||
|
} contract. Data: ${JSON.stringify(data)}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return spiral.length === answer.length && spiral.every((n, i) => n === answer[i]);
|
return spiral.length === answer.length && spiral.every((n, i) => n === answer[i]);
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => {
|
convertAnswer: (ans) => {
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ ${data}`;
|
|||||||
const ans = BigInt(state[0]);
|
const ans = BigInt(state[0]);
|
||||||
return ans * ans + BigInt(state[1]);
|
return ans * ans + BigInt(state[1]);
|
||||||
},
|
},
|
||||||
|
getAnswer: () => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
solver: (state, answer) => {
|
solver: (state, answer) => {
|
||||||
return state[0] === answer.toString();
|
return state[0] === answer.toString();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -23,13 +23,16 @@ export const subarrayWithMaximumSum: Pick<CodingContractTypes, CodingContractNam
|
|||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
const nums: number[] = data.slice();
|
const nums: number[] = data.slice();
|
||||||
for (let i = 1; i < nums.length; i++) {
|
for (let i = 1; i < nums.length; i++) {
|
||||||
nums[i] = Math.max(nums[i], nums[i] + nums[i - 1]);
|
nums[i] = Math.max(nums[i], nums[i] + nums[i - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Math.max(...nums) === answer;
|
return Math.max(...nums);
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return subarrayWithMaximumSum[CodingContractName.SubarrayWithMaximumSum].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const totalPrimesInRange: Pick<CodingContractTypes, CodingContractName.To
|
|||||||
const high = low + getRandomIntInclusive(1e5, 1e6);
|
const high = low + getRandomIntInclusive(1e5, 1e6);
|
||||||
return [low, high];
|
return [low, high];
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
/** Simple implementation of Sieve of Eratosthenes
|
/** Simple implementation of Sieve of Eratosthenes
|
||||||
* https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes*/
|
* https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes*/
|
||||||
function simpleSieve(max: number): number[] {
|
function simpleSieve(max: number): number[] {
|
||||||
@@ -76,7 +76,11 @@ export const totalPrimesInRange: Pick<CodingContractTypes, CodingContractName.To
|
|||||||
|
|
||||||
//We trust the player generated the appropriate list of primes (or is more accurate at guessing primes than Gauss was at this range) and as such they deserve the reward.
|
//We trust the player generated the appropriate list of primes (or is more accurate at guessing primes than Gauss was at this range) and as such they deserve the reward.
|
||||||
const primes = primeSieve(data[0], data[1]);
|
const primes = primeSieve(data[0], data[1]);
|
||||||
return answer === primes;
|
|
||||||
|
return primes;
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return totalPrimesInRange[CodingContractName.TotalPrimesInRange].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export const totalWaysToSum: Pick<
|
|||||||
generate: (): number => {
|
generate: (): number => {
|
||||||
return getRandomIntInclusive(8, 100);
|
return getRandomIntInclusive(8, 100);
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
if (typeof data !== "number") throw new Error("solver expected number");
|
if (typeof data !== "number") throw new Error("solver expected number");
|
||||||
const ways: number[] = [1];
|
const ways: number[] = [1];
|
||||||
ways.length = data + 1;
|
ways.length = data + 1;
|
||||||
@@ -33,7 +33,10 @@ export const totalWaysToSum: Pick<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ways[data] === answer;
|
return ways[data];
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return totalWaysToSum[CodingContractName.TotalWaysToSum].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
@@ -66,7 +69,7 @@ export const totalWaysToSum: Pick<
|
|||||||
}
|
}
|
||||||
return [n, s];
|
return [n, s];
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
// https://www.geeksforgeeks.org/coin-change-dp-7/?ref=lbp
|
// https://www.geeksforgeeks.org/coin-change-dp-7/?ref=lbp
|
||||||
const n = data[0];
|
const n = data[0];
|
||||||
const s = data[1];
|
const s = data[1];
|
||||||
@@ -78,7 +81,10 @@ export const totalWaysToSum: Pick<
|
|||||||
ways[j] += ways[j - s[i]];
|
ways[j] += ways[j - s[i]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ways[n] === answer;
|
return ways[n];
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return totalWaysToSum[CodingContractName.TotalWaysToSumII].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const uniquePathsInAGrid: Pick<
|
|||||||
|
|
||||||
return [numRows, numColumns];
|
return [numRows, numColumns];
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
const n: number = data[0]; // Number of rows
|
const n: number = data[0]; // Number of rows
|
||||||
const m: number = data[1]; // Number of columns
|
const m: number = data[1]; // Number of columns
|
||||||
const currentRow: number[] = [];
|
const currentRow: number[] = [];
|
||||||
@@ -44,7 +44,10 @@ export const uniquePathsInAGrid: Pick<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentRow[n - 1] === answer;
|
return currentRow[n - 1];
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return uniquePathsInAGrid[CodingContractName.UniquePathsInAGridI].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
@@ -97,7 +100,7 @@ export const uniquePathsInAGrid: Pick<
|
|||||||
|
|
||||||
return grid;
|
return grid;
|
||||||
},
|
},
|
||||||
solver: (data, answer) => {
|
getAnswer: (data) => {
|
||||||
const obstacleGrid: number[][] = [];
|
const obstacleGrid: number[][] = [];
|
||||||
obstacleGrid.length = data.length;
|
obstacleGrid.length = data.length;
|
||||||
for (let i = 0; i < obstacleGrid.length; ++i) {
|
for (let i = 0; i < obstacleGrid.length; ++i) {
|
||||||
@@ -116,7 +119,10 @@ export const uniquePathsInAGrid: Pick<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return obstacleGrid[obstacleGrid.length - 1][obstacleGrid[0].length - 1] === answer;
|
return obstacleGrid[obstacleGrid.length - 1][obstacleGrid[0].length - 1];
|
||||||
|
},
|
||||||
|
solver: (data, answer) => {
|
||||||
|
return uniquePathsInAGrid[CodingContractName.UniquePathsInAGridII].getAnswer(data) === answer;
|
||||||
},
|
},
|
||||||
convertAnswer: (ans) => parseInt(ans, 10),
|
convertAnswer: (ans) => parseInt(ans, 10),
|
||||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ export function NetscriptCodingContract(): InternalAPI<ICodingContract> {
|
|||||||
case CodingContractResult.Failure: {
|
case CodingContractResult.Failure: {
|
||||||
if (++contract.tries >= contract.getMaxNumTries()) {
|
if (++contract.tries >= contract.getMaxNumTries()) {
|
||||||
helpers.log(ctx, () => `Coding Contract attempt '${contract.fn}' failed. Contract is now self-destructing`);
|
helpers.log(ctx, () => `Coding Contract attempt '${contract.fn}' failed. Contract is now self-destructing`);
|
||||||
|
const solution = contract.getAnswer();
|
||||||
|
if (solution !== null) {
|
||||||
|
helpers.log(ctx, () => `Coding Contract solution was: ${solution}`);
|
||||||
|
}
|
||||||
server.removeContract(contract.fn);
|
server.removeContract(contract.fn);
|
||||||
} else {
|
} else {
|
||||||
helpers.log(
|
helpers.log(
|
||||||
|
|||||||
@@ -550,6 +550,10 @@ export class Terminal {
|
|||||||
++contract.tries;
|
++contract.tries;
|
||||||
if (contract.tries >= contract.getMaxNumTries()) {
|
if (contract.tries >= contract.getMaxNumTries()) {
|
||||||
this.error("Contract FAILED - Contract is now self-destructing");
|
this.error("Contract FAILED - Contract is now self-destructing");
|
||||||
|
const solution = contract.getAnswer();
|
||||||
|
if (solution !== null) {
|
||||||
|
this.error(`Coding Contract solution was: ${solution}`);
|
||||||
|
}
|
||||||
server.removeContract(contract);
|
server.removeContract(contract);
|
||||||
} else {
|
} else {
|
||||||
this.error(`Contract FAILED - ${contract.getMaxNumTries() - contract.tries} tries remaining`);
|
this.error(`Contract FAILED - ${contract.getMaxNumTries() - contract.tries} tries remaining`);
|
||||||
|
|||||||
Reference in New Issue
Block a user