Added 6 new Coding Contracts. Added Coding Contract information to documentation.

This commit is contained in:
danielyxie 2019-02-01 00:27:24 -08:00
parent 2968445244
commit 0e8872fad1
9 changed files with 667 additions and 37 deletions

@ -29,7 +29,7 @@ List of all Source-Files
| | * Each level of this Source-File opens up more of the Singularity Functions to use |
+------------------------------------+-------------------------------------------------------------------------------------+
| BitNode-5: Artificial Intelligence | * Unlocks :ref:`gameplay_intelligence` |
| | * Unlocks getBitNodeMultipliers() Netscript function |
| | * Unlocks :js:func:`getBitNodeMultipliers` Netscript function |
| | * Increases all of the player's hacking-related multipliers by 8%/12%/14% |
+------------------------------------+-------------------------------------------------------------------------------------+
| BitNode-6: Bladeburners | * Unlocks the Bladeburner feature in other BitNodes |

@ -76,3 +76,135 @@ Notes
^^^^^
* The *scp* Terminal command does not work on Coding Contracts
List of all Problem Types
^^^^^^^^^^^^^^^^^^^^^^^^^
The following is a list of all of the problem types that a Coding Contract can contain.
The list contains the name of (i.e. the value returned by
:js:func:`getContractType`) and a brief summary of the problem it poses.
+------------------------------------+------------------------------------------------------------------------------------------+
| Name | Problem Summary |
+====================================+==========================================================================================+
| Find Largest Prime Factor | | Given a number, find its largest prime factor. A prime factor |
| | | is a factor that is a prime number. |
+------------------------------------+------------------------------------------------------------------------------------------+
| Subarray with Maximum Sum | | Given an array of integers, find the contiguous subarray (containing |
| | | at least one number) which has the largest sum and return that sum. |
+------------------------------------+------------------------------------------------------------------------------------------+
| Total Ways to Sum | | Given a number, how many different ways can that number be written as |
| | | a sum of at least two positive integers? |
+------------------------------------+------------------------------------------------------------------------------------------+
| Spiralize Matrix | | Given an array of array of numbers representing a 2D matrix, return the |
| | | elements of that matrix in clockwise spiral order. |
| | | |
| | | Example: The spiral order of |
| | | |
| | | [1, 2, 3, 4] |
| | | [5, 6, 7, 8] |
| | | [9, 10, 11, 12] |
| | | |
| | | is [1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7] |
+------------------------------------+------------------------------------------------------------------------------------------+
| Array Jumping Game | | You are given an array of integers where each element represents the |
| | | maximum possible jump distance from that position. For example, if you |
| | | are at position i and your maximum jump length is n, then you can jump |
| | | to any position from i to i+n. |
| | | |
| | | Assuming you are initially positioned at the start of the array, determine |
| | | whether you are able to reach the last index of the array EXACTLY. |
+------------------------------------+------------------------------------------------------------------------------------------+
| Merge Overlapping Intervals | | Given an array of intervals, merge all overlapping intervals. An interval |
| | | is an array with two numbers, where the first number is always less than |
| | | the second (e.g. [1, 5]). |
| | | |
| | | The intervals must be returned in ASCENDING order. |
| | | |
| | | Example: |
| | | [[1, 3], [8, 10], [2, 6], [10, 16]] |
| | | merges into [[1, 6], [8, 16]] |
+------------------------------------+------------------------------------------------------------------------------------------+
| Generate IP Addresses | | Given a string containing only digits, return an array with all possible |
| | | valid IP address combinations that can be created from the string. |
| | | |
| | | An octet in the IP address cannot begin with '0' unless the number itself |
| | | is actually 0. For example, "192.168.010.1" is NOT a valid IP. |
| | | |
| | | Examples: |
| | | 25525511135 -> [255.255.11.135, 255.255.111.35] |
| | | 1938718066 -> [193.87.180.66] |
+------------------------------------+------------------------------------------------------------------------------------------+
| Algorithmic Stock Trader I | | You are given an array of numbers representing stock prices, where the |
| | | i-th element represents the stock price on day i. |
| | | |
| | | Determine the maximum possible profit you can earn using at most one |
| | | transaction (i.e. you can buy an sell the stock once). If no profit |
| | | can be made, then the answer should be 0. Note that you must buy the stock |
| | | before you can sell it. |
+------------------------------------+------------------------------------------------------------------------------------------+
| Algorithmic Stock Trader II | | You are given an array of numbers representing stock prices, where the |
| | | i-th element represents the stock price on day i. |
| | | |
| | | 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. If no |
| | | profit can be made, then the answer should be 0. |
+------------------------------------+------------------------------------------------------------------------------------------+
| Algorithmic Stock Trader III | | You are given an array of numbers representing stock prices, where the |
| | | i-th element represents the stock price on day i. |
| | | |
| | | 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. If no profit |
| | | can be made, then the answer should be 0. |
+------------------------------------+------------------------------------------------------------------------------------------+
| Algorithmic Stock Trader IV | | You are given an array with two elements. The first element is an integer k. |
| | | The second element is an array of numbers representing stock prices, where the |
| | | i-th element represents the stock price on day i. |
| | | |
| | | Determine the maximum possible profit you can earn using at most k 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 can buy it. If no profit can be made, then |
| | | the answer should be 0. |
+------------------------------------+------------------------------------------------------------------------------------------+
| Minimum Path Sum in a Triangle | | You are given a 2D array of numbers (array of array of numbers) that represents a |
| | | triangle (the first array has one element, and each array has one more element than |
| | | the one before it, forming a triangle). Find the minimum path sum from the top to the |
| | | bottom of the triangle. In each step of the path, you may only move to adjacent |
| | | numbers in the row below. |
+------------------------------------+------------------------------------------------------------------------------------------+
| Unique Paths in a Grid I | | You are given an array with two numbers: [m, n]. These numbers represent a |
| | | m x n grid. Assume you are initially positioned in the top-left corner of that |
| | | grid and that you are trying to reach the bottom-right corner. On each step, |
| | | you may only move down or to the right. |
| | | |
| | |
| | | Determine how many unique paths there are from start to finish. |
+------------------------------------+------------------------------------------------------------------------------------------+
| Unique Paths in a Grid II | | You are given a 2D array of numbers (array of array of numbers) representing |
| | | a grid. The 2D array contains 1's and 0's, where 1 represents an obstacle and |
| | |
| | | 0 represents a free space. |
| | | |
| | | Assume you are initially positioned in top-left corner of that grid and that you |
| | | are trying to reach the bottom-right corner. In each step, you may only move down |
| | | or to the right. Furthermore, you cannot move onto spaces which have obstacles. |
| | | |
| | | Determine how many unique paths there are from start to finish. |
+------------------------------------+------------------------------------------------------------------------------------------+
| Sanitize Parentheses in Expression | | Given a string with parentheses and letters, remove the minimum number of invalid |
| | | parentheses in order to validate the string. If there are multiple minimal ways |
| | | to validate the string, provide all of the possible results. |
| | | |
| | | The answer should be provided as an array of strings. If it is impossible to validate |
| | | the string, the result should be an array with only an empty string. |
| | | |
| | | Examples: |
| | | ()())() -> ["()()()", "(())()"] |
| | | (a)())() -> ["(a)()()", "(a())()"] |
| | | )( -> [""] |
+------------------------------------+------------------------------------------------------------------------------------------+

@ -10,9 +10,7 @@ import { getRandomInt } from "../utils/helpers/getRandomInt";
export function generateRandomContract() {
// First select a random problem type
const problemTypes = Object.keys(CodingContractTypes);
let randIndex = getRandomInt(0, problemTypes.length - 1);
let problemType = problemTypes[randIndex];
let problemType = getRandomProblemType();
// Then select a random reward type. 'Money' will always be the last reward type
const reward = getRandomReward();
@ -26,6 +24,22 @@ export function generateRandomContract() {
randServer.addContract(contract);
}
export function generateRandomContractOnHome() {
// First select a random problem type
let problemType = getRandomProblemType();
// Then select a random reward type. 'Money' will always be the last reward type
const reward = getRandomReward();
// Choose random server
const serv = Player.getHomeComputer();
let contractFn = getRandomFilename(serv, reward);
let contract = new CodingContract(contractFn, problemType, reward);
serv.addContract(contract);
}
export function generateContract(params) {
// Problem Type
let problemType;
@ -33,8 +47,7 @@ export function generateContract(params) {
if (params.problemType != null && problemTypes.includes(params.problemType)) {
problemType = params.problemType;
} else {
let randIndex = getRandomInt(0, problemTypes.length - 1);
problemType = problemTypes[randIndex];
problemType = getRandomProblemType();
}
// Reward Type - This is always random for now
@ -91,6 +104,13 @@ function sanitizeRewardType(rewardType) {
return type;
}
function getRandomProblemType() {
const problemTypes = Object.keys(CodingContractTypes);
let randIndex = getRandomInt(0, problemTypes.length - 1);
return problemTypes[randIndex];
}
function getRandomReward() {
let reward = {};
reward.type = getRandomInt(0, CodingContractRewardType.Money);

@ -1,9 +1,17 @@
import { codingContractTypesMetadata,
DescriptionFunc,
GeneratorFunc,
SolverFunc } from "./data/codingcontracttypes";
import { IMap } from "./types";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
import { KEY } from "../utils/helpers/keyCodes";
import { createElement } from "../utils/uiHelpers/createElement";
import { createPopup } from "../utils/uiHelpers/createPopup";
import { removeElementById } from "../utils/uiHelpers/removeElementById";
import { codingContractTypesMetadata, DescriptionFunc, GeneratorFunc, SolverFunc } from "./data/codingcontracttypes";
import { IMap } from "./types";
/* tslint:disable:no-magic-numbers completed-docs max-classes-per-file no-console */
@ -171,18 +179,22 @@ export class CodingContract {
const contractType: CodingContractType = CodingContractTypes[this.type];
const popupId: string = `coding-contract-prompt-popup-${this.fn}`;
const txt: HTMLElement = createElement("p", {
innerText: ["You are attempting to solve a Coding Contract. You have",
innerHTML: ["You are attempting to solve a Coding Contract. You have",
`${this.getMaxNumTries() - this.tries} tries remaining,`,
"after which the contract will self-destruct.\n\n",
`${contractType.desc(this.data)}`].join(" "),
"after which the contract will self-destruct.<br><br>",
`${contractType.desc(this.data).replace(/\n/g, "<br>")}`].join(" "),
});
let answerInput: HTMLInputElement;
let solveBtn: HTMLElement;
let cancelBtn: HTMLElement;
answerInput = createElement("input", {
onkeydown: (e: any) => {
if (e.keyCode === 13 && answerInput.value !== "") {
if (e.keyCode === KEY.ENTER && answerInput.value !== "") {
e.preventDefault();
solveBtn.click();
} else if (e.keyCode === KEY.ESC) {
e.preventDefault();
cancelBtn.click();
}
},
placeholder: "Enter Solution here",
@ -200,7 +212,7 @@ export class CodingContract {
},
innerText: "Solve",
});
const cancelBtn: HTMLElement = createElement("a", {
cancelBtn = createElement("a", {
class: "a-link-button",
clickListener: () => {
resolve(CodingContractResult.Cancelled);

@ -1,23 +1,26 @@
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
import { generateRandomContract } from "./CodingContractGenerator";
import { Programs } from "./Programs/Programs";
import { Factions } from "./Faction/Factions";
import { Player } from "./Player";
import { AllServers } from "./Server";
import { hackWorldDaemon } from "./RedPill";
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
import { CodingContractTypes } from "./CodingContracts";
import { generateContract,
generateRandomContract,
generateRandomContractOnHome } from "./CodingContractGenerator";
import { Programs } from "./Programs/Programs";
import { Factions } from "./Faction/Factions";
import { Player } from "./Player";
import { AllServers } from "./Server";
import { hackWorldDaemon } from "./RedPill";
import { StockMarket,
SymbolToStockMap } from "./StockMarket/StockMarket";
import { Stock } from "./StockMarket/Stock";
import { Terminal } from "./Terminal";
SymbolToStockMap } from "./StockMarket/StockMarket";
import { Stock } from "./StockMarket/Stock";
import { Terminal } from "./Terminal";
import { numeralWrapper } from "./ui/numeralFormat";
import { numeralWrapper } from "./ui/numeralFormat";
import { dialogBoxCreate } from "../utils/DialogBox";
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
import { createElement } from "../utils/uiHelpers/createElement";
import { createOptionElement } from "../utils/uiHelpers/createOptionElement";
import { getSelectText } from "../utils/uiHelpers/getSelectData";
import { removeElementById } from "../utils/uiHelpers/removeElementById";
import { dialogBoxCreate } from "../utils/DialogBox";
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
import { createElement } from "../utils/uiHelpers/createElement";
import { createOptionElement } from "../utils/uiHelpers/createOptionElement";
import { getSelectText } from "../utils/uiHelpers/getSelectData";
import { removeElementById } from "../utils/uiHelpers/removeElementById";
const devMenuContainerId = "dev-menu-container";
@ -429,6 +432,31 @@ export function createDevMenu() {
innerText: "Generate Random Contract",
});
const generateRandomContractOnHomeBtn = createElement("button", {
class: "std-button",
clickListener: () => {
generateRandomContractOnHome();
},
innerText: "Generate Random Contract on Home Comp",
});
const generateContractWithTypeSelector = createElement("select", { margin: "5px" });
const contractTypes = Object.keys(CodingContractTypes);
for (let i = 0; i < contractTypes.length; ++i) {
generateContractWithTypeSelector.add(createOptionElement(contractTypes[i]));
}
const generateContractWithTypeBtn = createElement("button", {
class: "std-button",
clickListener: () => {
generateContract({
problemType: getSelectText(generateContractWithTypeSelector),
server: "home",
});
},
innerText: "Generate Specified Contract Type on Home Comp",
});
// Stock Market
const stockmarketHeader = createElement("h2", {innerText: "Stock Market"});
@ -563,6 +591,10 @@ export function createDevMenu() {
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(contractsHeader);
devMenuContainer.appendChild(generateRandomContractBtn);
devMenuContainer.appendChild(generateRandomContractOnHomeBtn);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(generateContractWithTypeSelector);
devMenuContainer.appendChild(generateContractWithTypeBtn);
devMenuContainer.appendChild(stockmarketHeader);
devMenuContainer.appendChild(stockInput);
devMenuContainer.appendChild(stockPriceChangeInput);

@ -4702,8 +4702,17 @@ function NetscriptFunctions(workerScript) {
}
let data = contract.getData();
if (data.constructor === Array) {
// Pass a copy
return data.slice();
// For two dimensional arrays, we have to copy the internal arrays using
// slice() as well. As of right now, no contract has arrays that have
// more than two dimensions
const copy = data.slice();
for (let i = 0; i < copy.length; ++i) {
if (data[i].constructor === Array) {
copy[i] = data[i].slice();
}
}
return copy;
} else {
return data;
}

@ -30,6 +30,14 @@ function removeBracketsFromArrayString(str: string) {
return strCpy;
}
function removeQuotesFromString(str: string) {
let strCpy: string = str;
if (strCpy.startsWith('"') || strCpy.startsWith("'")) { strCpy = strCpy.slice(1); }
if (strCpy.endsWith('"') || strCpy.endsWith("'")) { strCpy = strCpy.slice(0, -1); }
return strCpy;
}
function convert2DArrayToString(arr: any[][]) {
const components: string[] = [];
arr.forEach((e: any) => {
@ -73,7 +81,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
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.",
"'Sum' refers to the sum of all the numbers in the subarray.\n",
`${n.toString()}`].join(" ");
},
difficulty: 1,
@ -152,8 +160,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
},
difficulty: 2,
gen: () => {
const m: number = getRandomInt(1, 10);
const n: number = getRandomInt(1, 10);
const m: number = getRandomInt(1, 15);
const n: number = getRandomInt(1, 15);
const matrix: number[][] = [];
matrix.length = m;
for (let i: number = 0; i < m; ++i) {
@ -493,4 +501,422 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
return release2.toString() === ans;
},
},
{
desc: (data: any[]) => {
const k: number = (<number>data[0]);
const prices: number[] = (<number[]>data[1]);
return ["You are given the following array with two elements:\n\n",
`[${k}, [${prices}]]\n\n`,
"The first element is an integer k. The second element is an",
"array of stock prices (which are numbers) where the i-th element",
"represents the stock price on day i.\n\n",
"Determine the maximum possible profit you can earn using at most",
"k 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 can buy it again.\n\n",
"If no profit can be made, then the answer should be 0."].join(" ");
},
difficulty: 8,
gen: () => {
const k: number = getRandomInt(2, 10);
const len: number = getRandomInt(1, 50);
const prices: number[] = [];
prices.length = len;
for (let i = 0; i < len; ++i) {
prices[i] = getRandomInt(1, 200);
}
return [k, prices];
},
name: "Algorithmic Stock Trader IV",
numTries: 10,
solver: (data: any[], ans: string) => {
const k: number = (<number>data[0]);
const prices: number[] = (<number[]>data[1]);
const len = prices.length;
if (len < 2) { return (parseInt(ans) === 0); }
if (k > len / 2) {
let res: number = 0;
for (let i = 1; i < len; ++i) {
res += Math.max(prices[i] - prices[i-1], 0);
}
return (parseInt(ans) === res);
}
const hold: number[] = [];
const rele: number[] = [];
hold.length = k + 1;
rele.length = k + 1;
for (let i = 0; i <= k; ++i) {
hold[i] = Number.MIN_SAFE_INTEGER;
rele[i] = 0;
}
let cur: number;
for (let i = 0; i < len; ++i) {
cur = prices[i];
for (let j = k; j > 0; --j) {
rele[j] = Math.max(rele[j], hold[j] + cur);
hold[j] = Math.max(hold[j], rele[j-1] - cur);
}
}
return (parseInt(ans) === rele[k]);
},
},
{
desc: (data: number[][]) => {
function createTriangleRecurse(data: number[][], level: number = 0): string {
const numLevels: number = data.length;
if (level >= numLevels) { return ""; }
const numSpaces = numLevels - level + 1;
let str: string = ["&nbsp;".repeat(numSpaces), "[", data[level].toString(), "]"].join("");
if (level < numLevels - 1) {
str += ",";
}
return str + "\n" + createTriangleRecurse(data, level+1);
}
function createTriangle(data: number[][]) {
return ["[\n", createTriangleRecurse(data), "]"].join("");
}
const triangle = createTriangle(data);
return ["Given a triangle, find the minimum path sum from top to bottom. In each step",
"of the path, you may only move to adjacent numbers in the row below.",
"The triangle is represented as a 2D array of numbers:\n\n",
`${triangle}\n\n`,
"Example: If you are given the following triangle:\n\n" +
"[\n",
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[2],\n",
"&nbsp;&nbsp;&nbsp;&nbsp;[3,4],\n",
"&nbsp;&nbsp;&nbsp;[6,5,7],\n",
"&nbsp;&nbsp;[4,1,8,3]\n",
"]\n\n",
"The minimum path sum is 11 (2 -> 3 -> 5 -> 1)."].join(" ");
},
difficulty: 5,
gen: () => {
const triangle: number[][] = [];
const levels: number = getRandomInt(1, 12);
triangle.length = levels;
for (let row = 0; row < levels; ++row) {
triangle[row] = [];
triangle[row].length = row + 1;
for (let i = 0; i < triangle[row].length; ++i) {
triangle[row][i] = getRandomInt(1, 9);
}
}
return triangle;
},
name: "Minimum Path Sum in a Triangle",
numTries: 10,
solver: (data: number[][], ans: string) => {
let n: number = data.length;
let dp: number[] = data[n-1];
for (let i = n-2; i > -1; --i) {
for (let j = 0; j < data[i].length; ++j) {
dp[j] = Math.min(dp[j], dp[j + 1]) + data[i][j];
}
}
return dp[0] === parseInt(ans);
},
},
{
desc: (data: number[]) => {
const numRows = data[0];
const numColumns = data[1];
return ["You are in a grid with",
`${numRows} rows and ${numColumns} columns, and you are`,
"positioned in the top-left corner of that grid. You are trying to",
"reach the bottom-right corner of the grid, but you can only",
"move down or right on each step. Determine how many",
"unique paths there are from start to finish.\n\n",
"NOTE: The data returned for this contract is an array",
"with the number or rows and columns:\n\n",
`[${numRows}, ${numColumns}]`].join(" ");
},
difficulty: 3,
gen: () => {
const numRows: number = getRandomInt(1, 14);
const numColumns: number = getRandomInt(1, 14);
return [numRows, numColumns];
},
name: "Unique Paths in a Grid I",
numTries: 10,
solver: (data: number[], ans: string) => {
let n: number = data[0]; // Number of rows
let m: number = data[1]; // Number of columns
let currentRow: number[] = [];
currentRow.length = n;
for (let i = 0; i < n; i++) {
currentRow[i] = 1;
}
for (let row = 1; row < m; row++) {
for (let i = 1; i < n; i++) {
currentRow[i] += currentRow[i - 1];
}
}
return parseInt(ans) === currentRow[n - 1];
},
},
{
desc: (data: number[][]) => {
let gridString: string = "";
for (const line of data) {
gridString += `${line.toString()},\n`;
}
return ["You are located in the top-left corner of the following grid:\n\n",
`${gridString}\n`,
"You are trying reach the bottom-right corner of the grid, but you can only",
"move down or right on each step. Furthermore, there are obstacles on the grid",
"that you cannot move onto. These obstacles are denoted by '1', while empty",
"spaces are denoted by 0.\n\n",
"Determine how many unique paths there are from start to finish.\n\n",
"NOTE: The data returned for this contract is an 2D array of numbers representing the grid."].join(" ");
},
difficulty: 5,
gen: () => {
const numRows: number = getRandomInt(1, 12);
const numColumns: number = getRandomInt(1, 12);
const grid: number[][] = [];
grid.length = numRows;
for (let i = 0; i < numRows; ++i) {
grid[i] = [];
grid[i].length = numColumns;
grid[i].fill(0);
}
for (let r = 0; r < numRows; ++r) {
for (let c = 0; c < numColumns; ++c) {
if (r === 0 && c === 0) { continue; }
if (r === numRows - 1 && c === numColumns - 1) { continue; }
// 15% chance of an element being an obstacle
if (Math.random() < 0.15) {
grid[r][c] = 1;
}
}
}
return grid;
},
name: "Unique Paths in a Grid II",
numTries: 10,
solver: (data: number[][], ans: string) => {
let obstacleGrid: number[][] = [];
obstacleGrid.length = data.length;
for (let i = 0; i < obstacleGrid.length; ++i) {
obstacleGrid[i] = data[i].slice();
}
for (let i = 0; i < obstacleGrid.length; i++) {
for (let j = 0; j < obstacleGrid[0].length; j++) {
if (obstacleGrid[i][j] == 1) {
obstacleGrid[i][j] = 0;
} else if (i==0 && j==0) {
obstacleGrid[0][0] = 1;
} else {
obstacleGrid[i][j] = (i > 0 ? obstacleGrid[i-1][j] : 0) + ( j > 0 ? obstacleGrid[i][j-1] : 0);
}
}
}
return (obstacleGrid[obstacleGrid.length -1][obstacleGrid[0].length-1] === parseInt(ans));
},
},
{
desc: (data: string) => {
return ["Given the following string:\n\n",
`${data}\n\n`,
"remove the minimum number of invalid parentheses in order to validate",
"the string. If there are multiple minimal ways to validate the string,",
"provide all of the possible results. The answer should be provided",
"as an array of strings. If it is impossible to validate the string",
"the result should be an array with only an empty string.\n\n",
"IMPORTANT: The string may contain letters, not just parentheses.",
`Examples:\n`,
`"()())()" -> ["()()()", "(())()"]\n`,
`"(a)())()" -> ["(a)()()", "(a())()"]\n`,
`")( -> [""]`].join(" ");
},
difficulty: 10,
gen: () => {
const len: number = getRandomInt(2, 20);
let chars: string[] = [];
chars.length = len;
// 80% chance of the first parenthesis being (
Math.random() < 0.8 ? chars[0] = "(" : chars[0] = ")";
for (let i = 1; i < len; ++i) {
const roll = Math.random();
if (roll < 0.4) {
chars[i] = "(";
} else if (roll < 0.8) {
chars[i] = ")";
} else {
chars[i] = "a";
}
}
return chars.join("");
},
name: "Sanitize Parentheses in Expression",
numTries: 10,
solver: (data: string, ans: string) => {
let left = 0;
let right = 0;
let res: string[] = [];
for (let i = 0; i < data.length; ++i) {
if (data[i] === '(') {
++left;
} else if (data[i] === ')') {
(left > 0) ? --left : ++right;
}
}
function dfs(pair: number, index: number, left: number, right: number, s: string, solution: string, res: string[]) {
if (s.length === index) {
if (left === 0 && right === 0 && pair === 0) {
for(var i = 0; i < res.length; i++) {
if(res[i] === solution) { return; }
}
res.push(solution);
}
return;
}
if (s[index] === '(') {
if (left > 0) {
dfs(pair, index + 1, left - 1, right, s, solution, res);
}
dfs(pair + 1, index + 1, left, right, s, solution + s[index], res);
} else if (s[index] === ')') {
if (right > 0) dfs(pair, index + 1, left, right - 1, s, solution, res);
if (pair > 0) dfs(pair - 1, index + 1, left, right, s, solution + s[index], res);
} else {
dfs(pair, index + 1, left, right, s, solution + s[index], res);
}
}
dfs(0, 0, left, right, data, "", res);
const sanitizedPlayerAns = removeBracketsFromArrayString(ans)
.replace(/\s/g, "");
const playerAnsArray: string[] = sanitizedPlayerAns.split(",");
if (playerAnsArray.length !== res.length) { return false; }
for (const resultInAnswer of res) {
if (!playerAnsArray.includes(resultInAnswer)) { return false; }
}
return true;
},
},
{
desc: (data: any[]) => {
const digits: string = data[0];
const target: number = data[1];
return ["You are given the following string which contains only digits between 0 and 9:\n\n",
`${digits}\n\n`,
`You are also given a target number of ${target}. Return all possible ways`,
"you can add the +, -, and * operators to the string such that it evaluates",
"to the target number.\n\n",
"The provided answer should be an array of strings containing the valid expressions.",
"The data provided by this problem is an array with two elements. The first element",
"is the string of digits, while the second element is the target number:\n\n",
`["${digits}", ${target}]\n\n`,
"Examples:\n\n",
`Input: digits = "123", target = 6\n`,
`Output: ["1+2+3", "1*2*3"]\n\n`,
`Input: digits = "105", target = 5\n`,
`Output: ["1*0+5", "10-5"]`].join(" ");
},
difficulty: 10,
gen: () => {
const numDigits = getRandomInt(4, 12);
const digitsArray: string[] = [];
digitsArray.length = numDigits;
for (let i = 0; i < digitsArray.length; ++i) {
if (i === 0) {
digitsArray[i] = String(getRandomInt(1, 9));
} else {
digitsArray[i] = String(getRandomInt(0, 9));
}
}
const target: number = getRandomInt(-100, 100);
const digits: string = digitsArray.join("");
return [digits, target];
},
name: "Find All Valid Math Expressions",
numTries: 10,
solver: (data: any[], ans: string) => {
const num: string = data[0];
const target: number = data[1];
function helper(res: string[], path: string, num: string, target: number, pos: number, evaluated: number, multed: number) {
if (pos === num.length) {
if (target === evaluated) {
res.push(path);
}
return;
}
for (let i = pos; i < num.length; ++i) {
if (i != pos && num[pos] == '0') { break; }
let cur = parseInt(num.substring(pos, i+1));
if (pos === 0) {
helper(res, path + cur, num, target, i + 1, cur, cur);
} else {
helper(res, path + "+" + cur, num, target, i + 1, evaluated + cur, cur);
helper(res, path + "-" + cur, num, target, i + 1, evaluated - cur, -cur);
helper(res, path + "*" + cur, num, target, i + 1, evaluated - multed + multed * cur, multed * cur);
}
}
}
const sanitizedPlayerAns: string = removeBracketsFromArrayString(ans);
const sanitizedPlayerAnsArr: string[] = sanitizedPlayerAns.split(",");
for (let i = 0; i < sanitizedPlayerAnsArr.length; ++i) {
sanitizedPlayerAnsArr[i] = removeQuotesFromString(sanitizedPlayerAnsArr[i]);
}
if (num == null || num.length === 0) {
if (sanitizedPlayerAnsArr.length === 0) { return true; }
if (sanitizedPlayerAnsArr.length === 1 && sanitizedPlayerAnsArr[0] === "") { return true; }
return false;
}
let result: string[] = [];
helper(result, "", num, target, 0, 0, 0);
for (const expr of result) {
if (!sanitizedPlayerAnsArr.includes(expr)) {
return false;
}
}
return true;
},
},
];

@ -12,6 +12,7 @@ export const KEY: IMap<number> = {
DOWNARROW: 40,
E: 69,
ENTER: 13,
ESC: 27,
F: 70,
H: 72,
J: 74,

@ -13,8 +13,6 @@ interface ICreatePopupCloseButtonOptions {
export function createPopupCloseButton(popup: Element | string, options: ICreatePopupCloseButtonOptions) {
let button: HTMLButtonElement;
// TODO event listener works with escape. Add and remove event listener
// from document
function closePopupWithEscFn(e: any): void {
if (e.keyCode === 27) {
button.click();