mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-20 00:04:22 +02:00
write()/read() now work for script files. You can now use angled brackets in tprint() (and create DOM elements). Added CodingContract implementation
This commit is contained in:
@@ -0,0 +1,463 @@
|
||||
import { getRandomInt } from "../../utils/helpers/getRandomInt";
|
||||
|
||||
/* tslint:disable:completed-docs no-magic-numbers arrow-return-shorthand */
|
||||
|
||||
/* Function that generates a valid 'data' for a contract type */
|
||||
export type GeneratorFunc = () => any;
|
||||
|
||||
/* Function that checks if the provided solution is the correct one */
|
||||
export type SolverFunc = (data: any, answer: string) => boolean;
|
||||
|
||||
/* Function that returns a string with the problem's description.
|
||||
Requires the 'data' of a Contract as input */
|
||||
export type DescriptionFunc = (data: any) => string;
|
||||
|
||||
export interface ICodingContractTypeMetadata {
|
||||
desc: DescriptionFunc;
|
||||
difficulty: number;
|
||||
gen: GeneratorFunc;
|
||||
name: string;
|
||||
numTries: number;
|
||||
solver: SolverFunc;
|
||||
}
|
||||
|
||||
export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
||||
{
|
||||
desc: (n: number) => {
|
||||
return ["A prime factor is a factor that is a prime number.",
|
||||
`What is the largest prime factor of ${n}?`].join(" ");
|
||||
},
|
||||
difficulty: 1,
|
||||
gen: () => {
|
||||
return getRandomInt(500, 9e9);
|
||||
},
|
||||
name: "Find Largest Prime Factor",
|
||||
numTries: 10,
|
||||
solver: (data: number, ans: string) => {
|
||||
let fac: number = 2;
|
||||
let n: number = data;
|
||||
while (n > fac) {
|
||||
if (n % fac === 0) {
|
||||
n = Math.round(n / fac);
|
||||
fac = 2;
|
||||
} else {
|
||||
++fac;
|
||||
}
|
||||
}
|
||||
|
||||
return fac === parseInt(ans, 10);
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: (n: number[]) => {
|
||||
return ["Given the following integer array, find the contiguous subarray",
|
||||
"(containing at least one number) which has the largest sum and return that sum.",
|
||||
"'Sum' refers to the sum of all the numbers in the subarray.",
|
||||
`${n.toString()}`].join(" ");
|
||||
},
|
||||
difficulty: 1,
|
||||
gen: () => {
|
||||
const len: number = getRandomInt(5, 40);
|
||||
const arr: number[] = [];
|
||||
arr.length = len;
|
||||
for (let i: number = 0; i < len; ++i) {
|
||||
arr[i] = getRandomInt(-10, 10);
|
||||
}
|
||||
|
||||
return arr;
|
||||
},
|
||||
name: "Subarray with Maximum Sum",
|
||||
numTries: 10,
|
||||
solver: (data: number[], ans: string) => {
|
||||
const nums: number[] = data.slice();
|
||||
for (let i: number = 1; i < nums.length; i++) {
|
||||
nums[i] = Math.max(nums[i], nums[i] + nums[i - 1]);
|
||||
}
|
||||
|
||||
return parseInt(ans, 10) === Math.max(...nums);
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: (n: number) => {
|
||||
return ["It is possible write four as a sum in exactly four different ways:\n\n",
|
||||
" 3 + 1\n",
|
||||
" 2 + 2\n",
|
||||
" 2 + 1 + 1\n",
|
||||
" 1 + 1 + 1 + 1\n\n",
|
||||
`How many different ways can ${n} be written as a sum of at least`,
|
||||
"two positive integers?"].join(" ");
|
||||
},
|
||||
difficulty: 1.5,
|
||||
gen: () => {
|
||||
return getRandomInt(8, 100);
|
||||
},
|
||||
name: "Total Ways to Sum",
|
||||
numTries: 10,
|
||||
solver: (data: number, ans: string) => {
|
||||
const ways: number[] = [1];
|
||||
ways.length = data + 1;
|
||||
ways.fill(0, 1);
|
||||
for (let i: number = 1; i < data; ++i) {
|
||||
for (let j: number = i; j <= data; ++j) {
|
||||
ways[j] += ways[j - i];
|
||||
}
|
||||
}
|
||||
|
||||
return ways[data] === parseInt(ans, 10);
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: (n: number[][]) => {
|
||||
let d: string = ["Given the following array of array of numbers representing a 2D matrix,",
|
||||
"return the elements of the matrix as an array in spiral order:\n\n"].join(" ");
|
||||
for (const line of n) {
|
||||
d += `${line.toString()},\n`;
|
||||
}
|
||||
d += ["\nHere is an example of what spiral order should be:",
|
||||
"\nExample:",
|
||||
" [\n",
|
||||
" [1, 2, 3],\n",
|
||||
" [4, 5, 6],\n",
|
||||
" [7, 8, 9]\n",
|
||||
" ] should result in [1, 2, 3, 6, 9, 8 ,7, 4, 5]\n\n",
|
||||
"Note that the matrix will not always be square:\n",
|
||||
" [\n",
|
||||
" [1, 2, 3, 4]\n",
|
||||
" [5, 6, 7, 8]\n",
|
||||
" [9, 10, 11, 12]\n",
|
||||
" ] should result in [1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7"].join(" ");
|
||||
|
||||
return d;
|
||||
},
|
||||
difficulty: 2,
|
||||
gen: () => {
|
||||
const m: number = getRandomInt(1, 10);
|
||||
const n: number = getRandomInt(1, 10);
|
||||
const matrix: number[][] = [];
|
||||
matrix.length = m;
|
||||
for (let i: number = 0; i < m; ++i) {
|
||||
matrix[i].length = n;
|
||||
}
|
||||
|
||||
for (let i: number = 0; i < m; ++i) {
|
||||
for (let j: number = 0; j < n; ++j) {
|
||||
matrix[i][j] = getRandomInt(1, 50);
|
||||
}
|
||||
}
|
||||
|
||||
return matrix;
|
||||
},
|
||||
name: "Spiralize Matrix",
|
||||
numTries: 10,
|
||||
solver: (data: number[][], ans: string) => {
|
||||
const spiral: number[] = [];
|
||||
const m: number = data.length;
|
||||
const n: number = data[0].length;
|
||||
let u: number = 0;
|
||||
let d: number = m - 1;
|
||||
let l: number = 0;
|
||||
let r: number = n - 1;
|
||||
let k: number = 0;
|
||||
while (true) {
|
||||
// Up
|
||||
for (let col: number = l; col <= r; col++) {
|
||||
spiral[k] = data[u][col];
|
||||
++k;
|
||||
}
|
||||
if (++u > d) { break; }
|
||||
|
||||
// Right
|
||||
for (let row: number = u; row <= d; row++) {
|
||||
spiral[k] = data[row][r];
|
||||
++k;
|
||||
}
|
||||
if (--r < l) { break; }
|
||||
|
||||
// Down
|
||||
for (let col: number = r; col >= l; col--) {
|
||||
spiral[k] = data[d][col];
|
||||
++k;
|
||||
}
|
||||
if (--d < u) { break; }
|
||||
|
||||
// Left
|
||||
for (let row: number = d; row >= u; row--) {
|
||||
spiral[k] = data[row][l];
|
||||
++k;
|
||||
}
|
||||
if (++l > r) { break; }
|
||||
}
|
||||
const playerAns: any[] = ans.split(",");
|
||||
for (let i: number = 0; i < playerAns.length; ++i) {
|
||||
playerAns[i] = parseInt(playerAns[i], 10);
|
||||
}
|
||||
if (spiral.length !== playerAns.length) { return false; }
|
||||
for (let i: number = 0; i < spiral.length; ++i) {
|
||||
if (spiral[i] !== playerAns[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: (arr: number[]) => {
|
||||
return ["You are given the following array of integers:\n\n",
|
||||
`${arr}\n\n`,
|
||||
"Each element in the array represents your maximum jump length",
|
||||
"at that position. Assuming you are initially positioned",
|
||||
"at the start of the array, determine whether you are",
|
||||
"able to reach the last index exactly.\n\n",
|
||||
"Your answer should be submitted as 1 or 0, representing true and false respectively"].join(" ");
|
||||
},
|
||||
difficulty: 2.5,
|
||||
gen: () => {
|
||||
const len: number = getRandomInt(1, 25);
|
||||
const arr: number[] = [];
|
||||
arr.length = len;
|
||||
for (let i: number = 0; i < arr.length; ++i) {
|
||||
arr[i] = getRandomInt(0, 24);
|
||||
}
|
||||
},
|
||||
name: "Array Jumping Game",
|
||||
numTries: 1,
|
||||
solver: (data: number[], ans: string) => {
|
||||
const n: number = data.length;
|
||||
let i: number = 0;
|
||||
for (let reach: number = 0; i < n && i <= reach; ++i) {
|
||||
reach = Math.max(i + data[i], reach);
|
||||
}
|
||||
const solution: boolean = (i === n);
|
||||
|
||||
if (ans === "1" && solution) { return true; }
|
||||
if (ans === "0" && !solution) { return true; }
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: (arr: number[][]) => {
|
||||
return ["Given the following array of array of numbers representing a list of",
|
||||
"intervals, merge all overlapping intervals.\n\n",
|
||||
`${arr}\n\n`,
|
||||
"Example:\n\n",
|
||||
"[[1, 3], [8, 10], [2, 6], [10, 16]]\n\n",
|
||||
"would merge into [[1, 6], [8, 16]].\n\n",
|
||||
"The intervals must be returned in ASCENDING order.",
|
||||
"You can assume that in an interval, the first number will always be",
|
||||
"smaller than the second."].join(" ");
|
||||
},
|
||||
difficulty: 3,
|
||||
gen: () => {
|
||||
const intervals: number[][] = [];
|
||||
const numIntervals: number = getRandomInt(1, 15);
|
||||
for (let i: number = 0; i < numIntervals; ++i) {
|
||||
const start: number = getRandomInt(1, 25);
|
||||
const end: number = start + getRandomInt(1, 10);
|
||||
intervals.push([start, end]);
|
||||
}
|
||||
|
||||
return intervals;
|
||||
},
|
||||
name: "Merge Overlapping Intervals",
|
||||
numTries: 15,
|
||||
solver: (data: number[][], ans: string) => {
|
||||
const intervals: number[][] = data.slice();
|
||||
intervals.sort((a: number[], b: number[]) => {
|
||||
return a[0] - b[0];
|
||||
});
|
||||
|
||||
const result: number[][] = [];
|
||||
let start: number = intervals[0][0];
|
||||
let end: number = intervals[0][1];
|
||||
for (const interval of intervals) {
|
||||
if (interval[0] <= end) {
|
||||
end = Math.max(end, interval[1]);
|
||||
} else {
|
||||
result.push([start, end]);
|
||||
start = interval[0];
|
||||
end = interval[1];
|
||||
}
|
||||
}
|
||||
result.push([start, end]);
|
||||
|
||||
const sanitizedResult: string = result
|
||||
.toString()
|
||||
.replace(/\s/g, "");
|
||||
const sanitizedAns: string = ans.replace(/\s/g, "");
|
||||
|
||||
return sanitizedResult === sanitizedAns;
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: (data: string) => {
|
||||
return ["Given the following string containing only digits, determine",
|
||||
"an array with all possible valid IP address combinations",
|
||||
"that can be created from the string:\n\n",
|
||||
`${data}\n\n`,
|
||||
"Example:\n\n",
|
||||
"'25525511135' -> ['255.255.11.135', '255.255.111.35']"].join(" ");
|
||||
},
|
||||
difficulty: 3,
|
||||
gen: () => {
|
||||
let str: string = "";
|
||||
for (let i: number = 0; i < 4; ++i) {
|
||||
const num: number = getRandomInt(0, 255);
|
||||
const convNum: string = num.toString();
|
||||
str += convNum;
|
||||
}
|
||||
|
||||
return str;
|
||||
},
|
||||
name: "Generate IP Addresses",
|
||||
numTries: 10,
|
||||
solver: (data: string, ans: string) => {
|
||||
const ret: string[] = [];
|
||||
for (let a: number = 1; a <= 3; ++a) {
|
||||
for (let b: number = 1; b <= 3; ++b) {
|
||||
for (let c: number = 1; c <= 3; ++c) {
|
||||
for (let d: number = 1; d <= 3; ++d) {
|
||||
if (a + b + c + d === data.length) {
|
||||
const A: number = parseInt(data.substring(0, a), 10);
|
||||
const B: number = parseInt(data.substring(a, a + b), 10);
|
||||
const C: number = parseInt(data.substring(a + b, a + b + c), 10);
|
||||
const D: number = parseInt(data.substring(a + b + c, a + b + c + d), 10);
|
||||
if (A <= 255 && B <= 255 && C <= 255 && D <= 255) {
|
||||
const ip: string = [A.toString(), ".",
|
||||
B.toString(), ".",
|
||||
C.toString(), ".",
|
||||
D.toString()].join("");
|
||||
if (ip.length === data.length + 3) {
|
||||
ret.push(ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let sanitizedAns: string = ans.replace(/\s/g, "");
|
||||
if (sanitizedAns.length === 0 || sanitizedAns[0] !== "[" || sanitizedAns[sanitizedAns.length - 1] !== "]") {
|
||||
return false;
|
||||
}
|
||||
sanitizedAns = sanitizedAns.slice(1, -1); // Remove []
|
||||
const ansArr: string[] = sanitizedAns.split(",");
|
||||
if (ansArr.length !== ret.length) { return false; }
|
||||
for (const ipInAns of ansArr) {
|
||||
if (!ret.includes(ipInAns)) { return false; }
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: (data: number[]) => {
|
||||
return ["You are given the following array of stock prices where the i-th element",
|
||||
"represents the stock price on day i:\n\n",
|
||||
`${data}\n\n`,
|
||||
"Determine the maximum possible profit you can earn using at most",
|
||||
"one transaction (i.e. you can only buy and sell the stock once). If no profit can be made",
|
||||
"then the answer should be 0. Note",
|
||||
"that you have to buy the stock before you can sell it"].join(" ");
|
||||
},
|
||||
difficulty: 1,
|
||||
gen: () => {
|
||||
const len: number = getRandomInt(1, 50);
|
||||
const arr: number[] = [];
|
||||
arr.length = len;
|
||||
for (let i: number = 0; i < len; ++i) {
|
||||
arr[i] = getRandomInt(1, 200);
|
||||
}
|
||||
|
||||
return arr;
|
||||
},
|
||||
name: "Algorithmic Stock Trader I",
|
||||
numTries: 5,
|
||||
solver: (data: number[], ans: string) => {
|
||||
let maxCur: number = 0;
|
||||
let maxSoFar: number = 0;
|
||||
for (let i: number = 1; i < data.length; ++i) {
|
||||
maxCur = Math.max(0, maxCur += data[i] - data[i - 1]);
|
||||
maxSoFar = Math.max(maxCur, maxSoFar);
|
||||
}
|
||||
|
||||
return maxSoFar.toString() === ans;
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: (data: number[]) => {
|
||||
return ["You are given the following array of stock prices where the i-th element",
|
||||
"represents the stock price on day i:\n\n",
|
||||
`${data}\n\n`,
|
||||
"Determine the maximum possible profit you can earn using as many",
|
||||
"transactions as you'd like. A transaction is defined as buying",
|
||||
"and then selling one share of the stock. Note that you cannot",
|
||||
"engage in multiple transactions at once. In other words, you",
|
||||
"must sell the stock before you buy it again.\n\n",
|
||||
"If no profit can be made, then the answer should be 0"].join(" ");
|
||||
},
|
||||
difficulty: 2,
|
||||
gen: () => {
|
||||
const len: number = getRandomInt(1, 50);
|
||||
const arr: number[] = [];
|
||||
arr.length = len;
|
||||
for (let i: number = 0; i < len; ++i) {
|
||||
arr[i] = getRandomInt(1, 200);
|
||||
}
|
||||
|
||||
return arr;
|
||||
},
|
||||
name: "Algorithmic Stock Trader II",
|
||||
numTries: 10,
|
||||
solver: (data: number[], ans: string) => {
|
||||
let profit: number = 0;
|
||||
for (let p: number = 1; p < data.length; ++p) {
|
||||
profit += Math.max(data[p] - data[p - 1], 0);
|
||||
}
|
||||
|
||||
return profit.toString() === ans;
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: (data: number[]) => {
|
||||
return ["You are given the following array of stock prices where the i-th element",
|
||||
"represents the stock price on day i:\n\n",
|
||||
`${data}\n\n`,
|
||||
"Determine the maximum possible profit you can earn using at most ",
|
||||
"two transactions. A transaction is defined as buying",
|
||||
"and then selling one share of the stock. Note that you cannot",
|
||||
"engage in multiple transactions at once. In other words, you",
|
||||
"must sell the stock before you buy it again.\n\n",
|
||||
"If no profit can be made, then the answer should be 0"].join(" ");
|
||||
},
|
||||
difficulty: 5,
|
||||
gen: () => {
|
||||
const len: number = getRandomInt(1, 50);
|
||||
const arr: number[] = [];
|
||||
arr.length = len;
|
||||
for (let i: number = 0; i < len; ++i) {
|
||||
arr[i] = getRandomInt(1, 200);
|
||||
}
|
||||
|
||||
return arr;
|
||||
},
|
||||
name: "Algorithmic Stock Trader III",
|
||||
numTries: 10,
|
||||
solver: (data: number[], ans: string) => {
|
||||
let hold1: number = Number.MIN_SAFE_INTEGER;
|
||||
let hold2: number = Number.MIN_SAFE_INTEGER;
|
||||
let release1: number = 0;
|
||||
let release2: number = 0;
|
||||
for (const price of data) {
|
||||
release2 = Math.max(release2, hold2 + price);
|
||||
hold2 = Math.max(hold2, release1 - price);
|
||||
release1 = Math.max(release1, hold1 + price);
|
||||
hold1 = Math.max(hold1, price * -1);
|
||||
}
|
||||
|
||||
return release2.toString() === ans;
|
||||
},
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user