mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 06:18:42 +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;
|
||||
}
|
||||
|
||||
getAnswer() {
|
||||
return CodingContractTypes[this.type].getAnswer(this.state);
|
||||
}
|
||||
|
||||
getData(): unknown {
|
||||
const func = CodingContractTypes[this.type].getData;
|
||||
return func ? func(this.state) : this.state;
|
||||
|
||||
@@ -33,11 +33,13 @@ interface CodingContractType<Data, Answer, State = Data> {
|
||||
difficulty: number;
|
||||
/** Function that generates a valid 'state' for a contract type */
|
||||
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
|
||||
* 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
|
||||
* 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
|
||||
* that can be copy-pasted to user code to solve the problem.
|
||||
*/
|
||||
|
||||
@@ -33,15 +33,17 @@ export const algorithmicStockTrader: Pick<
|
||||
return arr;
|
||||
},
|
||||
numTries: 5,
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
let maxCur = 0;
|
||||
let maxSoFar = 0;
|
||||
for (let i = 1; i < data.length; ++i) {
|
||||
maxCur = Math.max(0, (maxCur += data[i] - data[i - 1]));
|
||||
maxSoFar = Math.max(maxCur, maxSoFar);
|
||||
}
|
||||
|
||||
return maxSoFar === answer;
|
||||
return maxSoFar;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
return algorithmicStockTrader[CodingContractName.AlgorithmicStockTraderI].getAnswer(data) === answer;
|
||||
},
|
||||
convertAnswer: (ans) => parseInt(ans, 10),
|
||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||
@@ -71,13 +73,16 @@ export const algorithmicStockTrader: Pick<
|
||||
|
||||
return arr;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
let profit = 0;
|
||||
for (let p = 1; p < data.length; ++p) {
|
||||
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),
|
||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||
@@ -107,7 +112,7 @@ export const algorithmicStockTrader: Pick<
|
||||
|
||||
return arr;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
let hold1 = Number.MIN_SAFE_INTEGER;
|
||||
let hold2 = Number.MIN_SAFE_INTEGER;
|
||||
let release1 = 0;
|
||||
@@ -119,7 +124,10 @@ export const algorithmicStockTrader: Pick<
|
||||
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),
|
||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||
@@ -154,13 +162,13 @@ export const algorithmicStockTrader: Pick<
|
||||
|
||||
return [k, prices];
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
const k: number = data[0];
|
||||
const prices: number[] = data[1];
|
||||
|
||||
const len = prices.length;
|
||||
if (len < 2) {
|
||||
return answer === 0;
|
||||
return 0;
|
||||
}
|
||||
if (k > len / 2) {
|
||||
let res = 0;
|
||||
@@ -168,7 +176,7 @@ export const algorithmicStockTrader: Pick<
|
||||
res += Math.max(prices[i] - prices[i - 1], 0);
|
||||
}
|
||||
|
||||
return res === answer;
|
||||
return res;
|
||||
}
|
||||
|
||||
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),
|
||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||
|
||||
@@ -37,14 +37,17 @@ export const arrayJumpingGame: Pick<
|
||||
return arr;
|
||||
},
|
||||
numTries: 1,
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
const n: number = data.length;
|
||||
let i = 0;
|
||||
for (let reach = 0; i < n && i <= reach; ++i) {
|
||||
reach = Math.max(i + data[i], reach);
|
||||
}
|
||||
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) => {
|
||||
const num = parseInt(ans);
|
||||
@@ -85,7 +88,7 @@ export const arrayJumpingGame: Pick<
|
||||
return arr;
|
||||
},
|
||||
numTries: 3,
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
const n: number = data.length;
|
||||
let reach = 0;
|
||||
let jumps = 0;
|
||||
@@ -105,7 +108,10 @@ export const arrayJumpingGame: Pick<
|
||||
lastJump = jumpedFrom;
|
||||
jumps++;
|
||||
}
|
||||
return jumps === answer;
|
||||
return jumps;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
return arrayJumpingGame[CodingContractName.ArrayJumpingGameII].getAnswer(data) === answer;
|
||||
},
|
||||
convertAnswer: (ans) => parseInt(ans, 10),
|
||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { CodingContractTypes } from "../ContractTypes";
|
||||
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||
import { CodingContractName } from "@enums";
|
||||
|
||||
export const compression: Pick<
|
||||
@@ -49,8 +50,8 @@ export const compression: Pick<
|
||||
|
||||
return plain.substring(0, length);
|
||||
},
|
||||
solver: (plain, answer) => {
|
||||
if (plain.length === 0) return answer === "";
|
||||
getAnswer: (plain) => {
|
||||
if (plain.length === 0) return "";
|
||||
|
||||
let out = "";
|
||||
let count = 1;
|
||||
@@ -63,7 +64,10 @@ export const compression: Pick<
|
||||
count = 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, ""),
|
||||
validateAnswer: (ans): ans is string => typeof ans === "string",
|
||||
@@ -97,8 +101,11 @@ export const compression: Pick<
|
||||
generate: (): string => {
|
||||
return comprLZEncode(comprLZGenerate());
|
||||
},
|
||||
getAnswer: (compr) => {
|
||||
return comprLZDecode(compr) ?? "";
|
||||
},
|
||||
solver: (compr, answer) => {
|
||||
return (comprLZDecode(compr) ?? "") === answer;
|
||||
return compression[CodingContractName.CompressionIILZDecompression].getAnswer(compr) === answer;
|
||||
},
|
||||
convertAnswer: (ans) => ans.replace(/\s/g, ""),
|
||||
validateAnswer: (ans): ans is string => typeof ans === "string",
|
||||
@@ -135,8 +142,20 @@ export const compression: Pick<
|
||||
generate: (): string => {
|
||||
return comprLZGenerate();
|
||||
},
|
||||
getAnswer: (plain) => {
|
||||
return comprLZEncode(plain);
|
||||
},
|
||||
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, ""),
|
||||
validateAnswer: (ans): ans is string => typeof ans === "string",
|
||||
|
||||
@@ -57,13 +57,16 @@ export const encryption: Pick<
|
||||
Math.floor(Math.random() * 25 + 1),
|
||||
];
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
// data = [plaintext, shift value]
|
||||
// build char array, shifting via map and join to final results
|
||||
const cipher = [...data[0]]
|
||||
.map((a) => (a === " " ? a : String.fromCharCode(((a.charCodeAt(0) - 65 - data[1] + 26) % 26) + 65)))
|
||||
.join("");
|
||||
return cipher === answer;
|
||||
return cipher;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
return encryption[CodingContractName.EncryptionICaesarCipher].getAnswer(data) === answer;
|
||||
},
|
||||
convertAnswer: (ans) => ans,
|
||||
validateAnswer: (ans): ans is string => typeof ans === "string",
|
||||
@@ -222,7 +225,7 @@ export const encryption: Pick<
|
||||
keys.sort(() => Math.random() - 0.5)[0],
|
||||
];
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
// data = [plaintext, keyword]
|
||||
// build char array, shifting via map and corresponding keyword letter and join to final results
|
||||
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);
|
||||
})
|
||||
.join("");
|
||||
return cipher === answer;
|
||||
return cipher;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
return encryption[CodingContractName.EncryptionIIVigenereCipher].getAnswer(data) === answer;
|
||||
},
|
||||
convertAnswer: (ans) => ans,
|
||||
validateAnswer: (ans): ans is string => typeof ans === "string",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { filterTruthy } from "../../utils/helpers/ArrayHelpers";
|
||||
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
||||
import { CodingContractTypes, removeBracketsFromArrayString, removeQuotesFromString } from "../ContractTypes";
|
||||
import { CodingContractName } from "@enums";
|
||||
@@ -47,7 +48,7 @@ export const findAllValidMathExpressions: Pick<CodingContractTypes, CodingContra
|
||||
|
||||
return [digits, target];
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
const num = data[0];
|
||||
const target = data[1];
|
||||
|
||||
@@ -86,6 +87,20 @@ export const findAllValidMathExpressions: Pick<CodingContractTypes, CodingContra
|
||||
const result: string[] = [];
|
||||
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;
|
||||
|
||||
const solutions = new Set(answer);
|
||||
|
||||
@@ -13,7 +13,7 @@ export const findLargestPrimeFactor: Pick<CodingContractTypes, CodingContractNam
|
||||
generate: (): number => {
|
||||
return getRandomIntInclusive(500, 1e9);
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
let fac = 2;
|
||||
let n: number = data;
|
||||
while (n > (fac - 1) * (fac - 1)) {
|
||||
@@ -23,7 +23,10 @@ export const findLargestPrimeFactor: Pick<CodingContractTypes, CodingContractNam
|
||||
++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),
|
||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { CodingContractName } from "@enums";
|
||||
import { CodingContractTypes, removeBracketsFromArrayString } from "../ContractTypes";
|
||||
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
||||
|
||||
export const generateIPAddresses: Pick<CodingContractTypes, CodingContractName.GenerateIPAddresses> = {
|
||||
@@ -28,7 +29,7 @@ export const generateIPAddresses: Pick<CodingContractTypes, CodingContractName.G
|
||||
|
||||
return str;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
const ret: string[] = [];
|
||||
for (let a = 1; a <= 3; ++a) {
|
||||
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));
|
||||
},
|
||||
convertAnswer: (ans) => {
|
||||
|
||||
@@ -36,8 +36,11 @@ export const hammingCode: Pick<
|
||||
const y = Math.pow(2, getRandomIntInclusive(1, 57));
|
||||
return getRandomIntInclusive(Math.min(x, y), Math.max(x, y));
|
||||
},
|
||||
getAnswer: (data) => {
|
||||
return HammingEncode(data);
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
return HammingEncode(data) === answer;
|
||||
return hammingCode[CodingContractName.HammingCodesIntegerToEncodedBinary].getAnswer(data) === answer;
|
||||
},
|
||||
convertAnswer: (ans) => ans,
|
||||
validateAnswer: (ans): ans is string => typeof ans === "string",
|
||||
@@ -83,8 +86,11 @@ export const hammingCode: Pick<
|
||||
}
|
||||
return _buildArray.join("");
|
||||
},
|
||||
getAnswer: (data) => {
|
||||
return HammingDecode(data);
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
return HammingDecode(data) === answer;
|
||||
return hammingCode[CodingContractName.HammingCodesEncodedBinaryToInteger].getAnswer(data) === answer;
|
||||
},
|
||||
convertAnswer: (ans) => parseInt(ans, 10),
|
||||
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 { CodingContractTypes, convert2DArrayToString, removeBracketsFromArrayString } from "../ContractTypes";
|
||||
import { CodingContractName } from "@enums";
|
||||
@@ -30,7 +31,7 @@ export const mergeOverlappingIntervals: Pick<CodingContractTypes, CodingContract
|
||||
return intervals;
|
||||
},
|
||||
numTries: 15,
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
const intervals: [number, number][] = data.slice();
|
||||
intervals.sort((a: [number, number], b: [number, number]) => {
|
||||
return a[0] - b[0];
|
||||
@@ -50,6 +51,22 @@ export const mergeOverlappingIntervals: Pick<CodingContractTypes, CodingContract
|
||||
}
|
||||
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]);
|
||||
},
|
||||
convertAnswer: (ans) => {
|
||||
|
||||
@@ -56,7 +56,7 @@ export const minimumPathSumInATriangle: Pick<CodingContractTypes, CodingContract
|
||||
|
||||
return triangle;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
const n: number = data.length;
|
||||
const dp: number[] = data[n - 1].slice();
|
||||
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),
|
||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||
|
||||
@@ -75,6 +75,9 @@ export const proper2ColoringOfAGraph: Pick<CodingContractTypes, CodingContractNa
|
||||
|
||||
return [n + m, edges];
|
||||
},
|
||||
getAnswer: () => {
|
||||
return null;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
//Helper function to get neighbourhood of a vertex
|
||||
function neighbourhood(vertex: number): number[] {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
||||
import { CodingContractTypes, removeBracketsFromArrayString, removeQuotesFromString } from "../ContractTypes";
|
||||
import { CodingContractName } from "@enums";
|
||||
@@ -45,7 +46,7 @@ export const sanitizeParenthesesInExpression: Pick<
|
||||
|
||||
return chars.join("");
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
let left = 0;
|
||||
let right = 0;
|
||||
const res: string[] = [];
|
||||
@@ -94,6 +95,20 @@ export const sanitizeParenthesesInExpression: Pick<
|
||||
|
||||
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;
|
||||
return res.every((sol) => answer.includes(sol));
|
||||
},
|
||||
|
||||
@@ -53,6 +53,9 @@ export const shortestPathInAGrid: Pick<CodingContractTypes, CodingContractName.S
|
||||
|
||||
return grid;
|
||||
},
|
||||
getAnswer: () => {
|
||||
return null;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
const width = data[0].length;
|
||||
const height = data.length;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { CodingContractName } from "@enums";
|
||||
import { removeBracketsFromArrayString, type CodingContractTypes } from "../ContractTypes";
|
||||
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||
import { getRandomIntInclusive } from "../../utils/helpers/getRandomIntInclusive";
|
||||
|
||||
export const spiralizeMatrix: Pick<CodingContractTypes, CodingContractName.SpiralizeMatrix> = {
|
||||
@@ -55,7 +56,7 @@ export const spiralizeMatrix: Pick<CodingContractTypes, CodingContractName.Spira
|
||||
|
||||
return matrix;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
const spiral: number[] = [];
|
||||
const m: number = data.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]);
|
||||
},
|
||||
convertAnswer: (ans) => {
|
||||
|
||||
@@ -34,6 +34,9 @@ ${data}`;
|
||||
const ans = BigInt(state[0]);
|
||||
return ans * ans + BigInt(state[1]);
|
||||
},
|
||||
getAnswer: () => {
|
||||
return null;
|
||||
},
|
||||
solver: (state, answer) => {
|
||||
return state[0] === answer.toString();
|
||||
},
|
||||
|
||||
@@ -23,13 +23,16 @@ export const subarrayWithMaximumSum: Pick<CodingContractTypes, CodingContractNam
|
||||
|
||||
return arr;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
const nums: number[] = data.slice();
|
||||
for (let i = 1; i < nums.length; i++) {
|
||||
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),
|
||||
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);
|
||||
return [low, high];
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
/** Simple implementation of Sieve of Eratosthenes
|
||||
* https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes*/
|
||||
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.
|
||||
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),
|
||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||
|
||||
@@ -22,7 +22,7 @@ export const totalWaysToSum: Pick<
|
||||
generate: (): number => {
|
||||
return getRandomIntInclusive(8, 100);
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
if (typeof data !== "number") throw new Error("solver expected number");
|
||||
const ways: number[] = [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),
|
||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||
@@ -66,7 +69,7 @@ export const totalWaysToSum: Pick<
|
||||
}
|
||||
return [n, s];
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
// https://www.geeksforgeeks.org/coin-change-dp-7/?ref=lbp
|
||||
const n = data[0];
|
||||
const s = data[1];
|
||||
@@ -78,7 +81,10 @@ export const totalWaysToSum: Pick<
|
||||
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),
|
||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||
|
||||
@@ -29,7 +29,7 @@ export const uniquePathsInAGrid: Pick<
|
||||
|
||||
return [numRows, numColumns];
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
const n: number = data[0]; // Number of rows
|
||||
const m: number = data[1]; // Number of columns
|
||||
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),
|
||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||
@@ -97,7 +100,7 @@ export const uniquePathsInAGrid: Pick<
|
||||
|
||||
return grid;
|
||||
},
|
||||
solver: (data, answer) => {
|
||||
getAnswer: (data) => {
|
||||
const obstacleGrid: number[][] = [];
|
||||
obstacleGrid.length = data.length;
|
||||
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),
|
||||
validateAnswer: (ans): ans is number => typeof ans === "number",
|
||||
|
||||
@@ -55,6 +55,10 @@ export function NetscriptCodingContract(): InternalAPI<ICodingContract> {
|
||||
case CodingContractResult.Failure: {
|
||||
if (++contract.tries >= contract.getMaxNumTries()) {
|
||||
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);
|
||||
} else {
|
||||
helpers.log(
|
||||
|
||||
@@ -550,6 +550,10 @@ export class Terminal {
|
||||
++contract.tries;
|
||||
if (contract.tries >= contract.getMaxNumTries()) {
|
||||
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);
|
||||
} else {
|
||||
this.error(`Contract FAILED - ${contract.getMaxNumTries() - contract.tries} tries remaining`);
|
||||
|
||||
Reference in New Issue
Block a user