* fix: renamed basic html cat photo app steps * fix: renamed css-variables project steps * fix: renamed d3-dashboard filenames * fix: renamed rpg-game filenames * fix: renamed functional-progamming-spreadsheet filenames * fix: renamed calorie-counter project filenames
7.4 KiB
7.4 KiB
id, title, challengeType, isHidden
id | title | challengeType | isHidden |
---|---|---|---|
5d7925381e8565a5c50ba7f1 | Part 99 | 0 | true |
Description
In functional programming, we strive to use a type of function called "pure functions" as much as possible. The first property of pure functions is that they always return the same value for the same arguments.
You can check if this is the case by comparing a call to a function with another call (with the same arguments):
console.log(f(2) === f(2)); // always true for pure functions
Use this technique to check if the random
function in spreadsheetFunctions
is pure by passing in the following array: [1, 1000]
.
Instructions
Tests
tests:
- text: See description above for instructions.
testString: assert(/(spreadsheetFunctions\[["']random["']\]\(1,1000\))===\1/.test(code.replace(/\s/g, "")));
Challenge Seed
<script>
const infixToFunction = {
"+": (x, y) => x + y,
"-": (x, y) => x - y,
"*": (x, y) => x * y,
"/": (x, y) => x / y
};
const infixEval = (str, regex) =>
str.replace(regex, (_, arg1, fn, arg2) =>
infixToFunction[fn](parseFloat(arg1), parseFloat(arg2))
);
const highPrecedence = str => {
const regex = /([0-9.]+)([*\/])([0-9.]+)/;
const str2 = infixEval(str, regex);
return str === str2 ? str : highPrecedence(str2);
};
const spreadsheetFunctions = {
"": x => x,
random: ([x, y]) => Math.floor(Math.random() * y + x)
};
const applyFn = str => {
const noHigh = highPrecedence(str);
const infix = /([0-9.]+)([+-])([0-9.]+)/;
const str2 = infixEval(noHigh, infix);
const regex = /([a-z]*)\(([0-9., ]*)\)(?!.*\()/i;
const toNumberList = args => args.split(",").map(parseFloat);
const applyFunction = (fn, args) =>
spreadsheetFunctions[fn.toLowerCase()](toNumberList(args));
return str2.replace(
regex,
(match, fn, args) =>
spreadsheetFunctions.hasOwnProperty(fn.toLowerCase()) ? applyFunction(fn, args) : match
);
};
const range = (start, end) =>
start > end ? [] : [start].concat(range(start + 1, end));
const charRange = (start, end) =>
range(start.charCodeAt(0), end.charCodeAt(0)).map(x =>
String.fromCharCode(x)
);
const evalFormula = x => {
const rangeRegex = /([A-J])([1-9][0-9]?):([A-J])([1-9][0-9]?)/gi;
const rangeFromString = (n1, n2) => range(parseInt(n1), parseInt(n2));
const elemValue = n => c => document.getElementById(c + n).value;
const addChars = c1 => c2 => n => charRange(c1, c2).map(elemValue(n));
const varRangeExpanded = x.replace(rangeRegex, (_, c1, n1, c2, n2) =>
rangeFromString(n1, n2).map(addChars(c1)(c2))
);
const varRegex = /[A-J][1-9][0-9]?/gi;
const varExpanded = varRangeExpanded.replace(
varRegex,
match => document.getElementById(match.toUpperCase()).value
);
const functionExpanded = applyFn(varExpanded);
return functionExpanded === x
? functionExpanded
: evalFormula(functionExpanded);
};
window.onload = () => {
const container = document.getElementById("container");
const createLabel = name => {
const label = document.createElement("div");
label.className = "label";
label.textContent = name;
container.appendChild(label);
};
const letters = charRange("A", "J");
letters.forEach(createLabel);
range(1, 99).forEach(x => {
createLabel(x);
letters.forEach(y => {
const input = document.createElement("input");
input.type = "text";
input.id = y + x;
input.onchange = update;
container.appendChild(input);
});
});
};
const update = event => {
const element = event.target;
const value = element.value.replace(/\s/g, "");
if (!value.includes(element.id) && value[0] === "=") {
element.value = evalFormula(value.slice(1));
}
};
</script>
Before Test
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Spreadsheet</title>
<style>
#container {
display: grid;
grid-template-columns: 50px repeat(10, 200px);
grid-template-rows: repeat(11, 30px);
}
.label {
background-color: lightgray;
text-align: center;
vertical-align: middle;
line-height: 30px;
}
</style>
</head>
<body>
<div id="container">
<div></div>
</div>
After Test
</body>
</html>
Solution
<script>
const infixToFunction = {
"+": (x, y) => x + y,
"-": (x, y) => x - y,
"*": (x, y) => x * y,
"/": (x, y) => x / y
};
const infixEval = (str, regex) =>
str.replace(regex, (_, arg1, fn, arg2) =>
infixToFunction[fn](parseFloat(arg1), parseFloat(arg2))
);
const highPrecedence = str => {
const regex = /([0-9.]+)([*\/])([0-9.]+)/;
const str2 = infixEval(str, regex);
return str === str2 ? str : highPrecedence(str2);
};
const spreadsheetFunctions = {
"": x => x,
random: ([x, y]) => Math.floor(Math.random() * y + x)
};
const applyFn = str => {
const noHigh = highPrecedence(str);
const infix = /([0-9.]+)([+-])([0-9.]+)/;
const str2 = infixEval(noHigh, infix);
const regex = /([a-z]*)\(([0-9., ]*)\)(?!.*\()/i;
const toNumberList = args => args.split(",").map(parseFloat);
const applyFunction = (fn, args) =>
spreadsheetFunctions[fn.toLowerCase()](toNumberList(args));
return str2.replace(
regex,
(match, fn, args) =>
spreadsheetFunctions.hasOwnProperty(fn.toLowerCase()) ? applyFunction(fn, args) : match
);
};
const range = (start, end) =>
start > end ? [] : [start].concat(range(start + 1, end));
const charRange = (start, end) =>
range(start.charCodeAt(0), end.charCodeAt(0)).map(x =>
String.fromCharCode(x)
);
const evalFormula = x => {
const rangeRegex = /([A-J])([1-9][0-9]?):([A-J])([1-9][0-9]?)/gi;
const rangeFromString = (n1, n2) => range(parseInt(n1), parseInt(n2));
const elemValue = n => c => document.getElementById(c + n).value;
const addChars = c1 => c2 => n => charRange(c1, c2).map(elemValue(n));
const varRangeExpanded = x.replace(rangeRegex, (_, c1, n1, c2, n2) =>
rangeFromString(n1, n2).map(addChars(c1)(c2))
);
const varRegex = /[A-J][1-9][0-9]?/gi;
const varExpanded = varRangeExpanded.replace(
varRegex,
match => document.getElementById(match.toUpperCase()).value
);
const functionExpanded = applyFn(varExpanded);
return functionExpanded === x
? functionExpanded
: evalFormula(functionExpanded);
};
window.onload = () => {
const container = document.getElementById("container");
const createLabel = name => {
const label = document.createElement("div");
label.className = "label";
label.textContent = name;
container.appendChild(label);
};
const letters = charRange("A", "J");
letters.forEach(createLabel);
range(1, 99).forEach(x => {
createLabel(x);
letters.forEach(y => {
const input = document.createElement("input");
input.type = "text";
input.id = y + x;
input.onchange = update;
container.appendChild(input);
});
});
};
const update = event => {
const element = event.target;
const value = element.value.replace(/\s/g, "");
if (!value.includes(element.id) && value[0] === "=") {
element.value = evalFormula(value.slice(1));
}
};
// console.log(spreadsheetFunctions["random"](1, 1000) === spreadsheetFunctions["random"](1, 1000))
</script>