feat: functional programming spreadsheet (#36873)
* Add meta.json for spreadsheet * Add spreadsheet files * Close code tags for tests in 2 files * Add solution section * Add index file * Add javascript-spreadsheet to stringifier * Move index to step * Rename steps in meta.json * Rename step numbers in files * Add index file to proper location * Remove inappropriate files from spreadsheet dir * Fix typo in first step * Fix test sections * Rename files to correct step * Fix broken tests * Add newline between sections * Change challengeType from 1 to 0 * Add missng ) in step-079.md * test -> tests in step-079 * Simplify test in step-103 * Fix step-137 test * Remove last step * Added solutions and adjusted some tests * Fix some challenges * Remove wrong spaces * Fix more tests * Add missing semicolon * Fix more tests * Fix type: lastttwo * Fix all remaining tests
This commit is contained in:
committed by
Mrugesh Mohapatra
parent
89e18e3a81
commit
2fbafda167
@ -0,0 +1,107 @@
|
||||
---
|
||||
id: 5d79253297c0ebb149ea9fed
|
||||
title: Step 001
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
In functional programming, we prefer immutable values over mutable values.
|
||||
Mutable values (declared with <code>var</code> or `let`) can lead to unexpected behaviors and bugs.
|
||||
Values declared with `const` cannot be reassigned, which makes using them easier because you don't have to keep track of their values.
|
||||
Start by creating an empty `infixToFunction` object using `const`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constinfixToFunction={}"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
const infixToFunction = {};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,111 @@
|
||||
---
|
||||
id: 5d7925323be8848dbc58a07a
|
||||
title: Step 002
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Above `infixToFunction`, define an empty function `add` using the `function` keyword.
|
||||
It should accept two parameters, `x` and `y`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("functionadd(x,y){}"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
const infixToFunction = {};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
function add(x, y) {
|
||||
|
||||
}
|
||||
|
||||
const infixToFunction = {};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,114 @@
|
||||
---
|
||||
id: 5d792532f631702ae6d23e11
|
||||
title: Step 003
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now return the sum of `x` and `y` using the `return` keyword.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(add(1, 2) === 3 && add(100, 2000) === 2100);
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
function add(x, y) {
|
||||
|
||||
}
|
||||
|
||||
const infixToFunction = {};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
function add(x, y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
const infixToFunction = {};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,118 @@
|
||||
---
|
||||
id: 5d7925329445167ecc2ac9c9
|
||||
title: Step 004
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
In JavaScript, functions are first class.
|
||||
This means that they can be used like any other values - for example, they can be assigned to variables.
|
||||
Assign `add` to a new variable `addVar`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constaddVar=add"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
function add(x, y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
const infixToFunction = {};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
function add(x, y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
const addVar = add;
|
||||
|
||||
const infixToFunction = {};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,125 @@
|
||||
---
|
||||
id: 5d792532b07918c3a5904913
|
||||
title: Step 005
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Anonymous functions are functions without names - they are used only once and then forgotten.
|
||||
The syntax is the same as for normal functions but without the name:
|
||||
|
||||
```js
|
||||
function(x) {
|
||||
return x
|
||||
}
|
||||
```
|
||||
|
||||
First, remove the `addVar` definition.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(!code.replace(/\s/g, "").includes("constaddVar=add"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
function add(x, y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
const addVar = add;
|
||||
|
||||
const infixToFunction = {};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
function add(x, y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
const infixToFunction = {};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,125 @@
|
||||
---
|
||||
id: 5d792533cc8b18b6c133edc7
|
||||
title: Step 006
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Anonymous functions are often passed as arguments to other functions, but what if you want to call one later?
|
||||
You can assign anonymous functions to variables and call them with the variable's name:
|
||||
|
||||
```js
|
||||
const fn = function(x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
fn();
|
||||
```
|
||||
|
||||
Assign the anonymous function to the variable `addVar`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constaddVar=function(x,y){returnx+y"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
function add(x, y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
const infixToFunction = {};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
const addVar = function(x, y) {
|
||||
return x + y;
|
||||
};
|
||||
|
||||
const infixToFunction = {};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,119 @@
|
||||
---
|
||||
id: 5d7925337954ed57a565a135
|
||||
title: Step 007
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
This is possible because the anonymous function has been immediately assigned to a value - this is effectively the same as using a named function.
|
||||
Rewrite `addVar` using ES6's arrow syntax:
|
||||
|
||||
```js
|
||||
const fn = (x, y) => x;
|
||||
```
|
||||
|
||||
Note that the value is returned implicitly.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constaddVar=(x,y)=>x+y"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
const addVar = function(x, y) {
|
||||
return x + y;
|
||||
};
|
||||
|
||||
const infixToFunction = {};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
const addVar = (x, y) => x + y;
|
||||
|
||||
const infixToFunction = {};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,112 @@
|
||||
---
|
||||
id: 5d79253352e33dd59ec2f6de
|
||||
title: Step 008
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add the key `+` to `infixToFunction` and assign it the value `addVar`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(infixToFunction["+"].toString() === addVar.toString());
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
const addVar = (x, y) => x + y;
|
||||
|
||||
const infixToFunction = {};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
const addVar = (x, y) => x + y;
|
||||
|
||||
const infixToFunction = {
|
||||
"+": addVar
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,114 @@
|
||||
---
|
||||
id: 5d792533d31e4f7fad33011d
|
||||
title: Step 009
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
In `infixToFunction`, replace `addVar` with `(x, y) => x + y`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, '').match(/\+["']:\(x,y\)=>x\+y/));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
const addVar = (x, y) => x + y;
|
||||
|
||||
const infixToFunction = {
|
||||
"+": addVar
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
const addVar = (x, y) => x + y;
|
||||
|
||||
const infixToFunction = {
|
||||
"+": (x, y) => x + y
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,112 @@
|
||||
---
|
||||
id: 5d792533e7707b9645d7b540
|
||||
title: Step 010
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Remove the now redundant `addVar` definition.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(typeof addVar === "undefined");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
const addVar = (x, y) => x + y;
|
||||
|
||||
const infixToFunction = {
|
||||
"+": (x, y) => x + y
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
const infixToFunction = {
|
||||
"+": (x, y) => x + y
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,113 @@
|
||||
---
|
||||
id: 5d79253378595ec568f70ab6
|
||||
title: Step 011
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add similar definitions for `-`, `*` and `/` in `infixToFunction`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(infixToFunction["-"](10, 2) === 8 && infixToFunction["*"](10, 10) === 100 && infixToFunction["/"](100, 10) === 10);
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
const infixToFunction = {
|
||||
"+": (x, y) => x + y
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
const infixToFunction = {
|
||||
"+": (x, y) => x + y,
|
||||
"-": (x, y) => x - y,
|
||||
"*": (x, y) => x * y,
|
||||
"/": (x, y) => x / y
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,118 @@
|
||||
---
|
||||
id: 5d7925330918ae4a2f282e7e
|
||||
title: Step 012
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Use arrow function syntax to define a function `infixEval` which takes `str` and `regex` as arguments and returns `str.replace(regex, "")`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/constinfixEval=\(str,regex\)=>str\.replace\(regex,['"]{2}\)/.test(code.replace(/\s/g, '')));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<script>
|
||||
|
||||
const infixToFunction = {
|
||||
"+": (x, y) => x + y,
|
||||
"-": (x, y) => x - y,
|
||||
"*": (x, y) => x * y,
|
||||
"/": (x, y) => x / y
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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, "");
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,127 @@
|
||||
---
|
||||
id: 5d792533ed00e75d129e1b18
|
||||
title: Step 013
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
`replace` is a higher order function because it can take a function as argument (higher order functions can also return functions).
|
||||
Pass the `+` function from `infixToFunction` to the `replace` method as the second argument.
|
||||
This is how you would pass the `-` function:
|
||||
|
||||
```js
|
||||
str.replace(regex, infixToFunction["-"])
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(infixEval("ab", /(a)b/) === "aba");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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, "");
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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, infixToFunction["+"]);
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,123 @@
|
||||
---
|
||||
id: 5d792533a5c42fb4d1a4b70d
|
||||
title: Step 014
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Replace the second argument of `str.replace` with an anonymous function, which takes `match`, `arg1`, `fn`, and `arg2`, and returns `infixToFunction["+"]`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes('str.replace(regex,(match,arg1,fn,arg2)=>infixToFunction["+"])'));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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, infixToFunction["+"]);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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, (match, arg1, fn, arg2) =>
|
||||
infixToFunction["+"]
|
||||
);
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,127 @@
|
||||
---
|
||||
id: 5d79253358e8f646cbeb2bb0
|
||||
title: Step 015
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Change the `"+"` in the call to `infixToFunction` to `fn`.
|
||||
`fn` is the operator that the user inputs (`+`, `-`, `*` or `/`) - we use `infixToFunction` to get the function that corresponds to it.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes('str.replace(regex,(match,arg1,fn,arg2)=>infixToFunction[fn])'));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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, (match, arg1, fn, arg2) =>
|
||||
infixToFunction["+"]
|
||||
);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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, (match, arg1, fn, arg2) =>
|
||||
infixToFunction[fn]
|
||||
);
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,127 @@
|
||||
---
|
||||
id: 5d792533bb38fab70b27f527
|
||||
title: Step 016
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
`arg1` and `arg2` are the numbers inputed by the user in a string such as "1+3".
|
||||
Pass `parseFloat(arg1)` and `parseFloat(arg2)` as the arguments to `infixToFunction[fn]` (remember `infixToFunction[fn]` is a function).
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: const regex = /([0-9.]+)([+-\/*])([0-9.]+)/; assert(infixEval("23+35", regex) === "58" && infixEval("100-20", regex) === "80" && infixEval("10*10", regex) === "100" && infixEval("120/6", regex) === "20");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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, (match, arg1, fn, arg2) =>
|
||||
infixToFunction[fn]
|
||||
);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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, (match, arg1, fn, arg2) =>
|
||||
infixToFunction[fn](parseFloat(arg1), parseFloat(arg2))
|
||||
);
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,128 @@
|
||||
---
|
||||
id: 5d79253386060ed9eb04a070
|
||||
title: Step 017
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The `match` parameter is currently unused, which can lead to unused variable warnings in some linters.
|
||||
To fix this, prefix or replace it with an underscore (`_`) - both ways signal to the reader and linter that you're aware you don't need this.
|
||||
Note that a single underscore can only be used once in a function and may conflict with some libraries (Lodash, Undrescore.js).
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("str.replace(regex,(_"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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, (match, arg1, fn, arg2) =>
|
||||
infixToFunction[fn](parseFloat(arg1), parseFloat(arg2))
|
||||
);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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))
|
||||
);
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,133 @@
|
||||
---
|
||||
id: 5d792533717672657b81aa69
|
||||
title: Step 018
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
When defining an arrow function with a single argument, the parentheses can be omitted:
|
||||
|
||||
```js
|
||||
const greeting = name => `Hello !`;
|
||||
```
|
||||
|
||||
Define a function `highPrecedence` which takes a single argument `str` and returns it.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(highPrecedence("a") === "a");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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))
|
||||
);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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 => str;
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,140 @@
|
||||
---
|
||||
id: 5d7925335ab63018dcec11fe
|
||||
title: Step 019
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Arrow functions can have multiple statements:
|
||||
|
||||
```js
|
||||
const fn = (x, y) => {
|
||||
const result = x + y;
|
||||
return result; // explicit return statement required
|
||||
};
|
||||
```
|
||||
|
||||
Use this syntax for the `highPrecedence` function.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("highPrecedence=str=>{returnstr"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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 => str;
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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 => {
|
||||
return str;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,135 @@
|
||||
---
|
||||
id: 5d7925330f300c342315066d
|
||||
title: Step 020
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
In `highPrecedence`, define `regex` to be `/([0-9.]+)([*\/])([0-9.]+)/`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("regex=/([0-9.]+)([*\\/])([0-9.]+)/"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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 => {
|
||||
return str;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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.]+)/;
|
||||
return str;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,138 @@
|
||||
---
|
||||
id: 5d792533aa6443215c9b16bf
|
||||
title: Step 021
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now, assign the result of calling `infixEval` with `str` and `regex` to `str2`.
|
||||
Return `str2`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(highPrecedence("7*6") === "42" && highPrecedence("50/25") === "2");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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.]+)/;
|
||||
return str;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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 str2;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,146 @@
|
||||
---
|
||||
id: 5d7925334c5e22586dd72962
|
||||
title: Step 022
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The ternary operator has the following syntax:
|
||||
|
||||
```js
|
||||
const result = condition ? valueIfTrue : valueIfFalse;
|
||||
const result = 1 === 1 ? 1 : 0; // 1
|
||||
const result = 9 > 10 ? "Yes" : "No"; // "No"
|
||||
```
|
||||
|
||||
Use this operator to return `str` if `str === str2`, and an empty string (`""`) otherwise.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(highPrecedence("2*2") === "" && highPrecedence("2+2") === "2+2" && code.includes("?"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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 str2;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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 : "";
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,140 @@
|
||||
---
|
||||
id: 5d79253307ecd49e030bdcd1
|
||||
title: Step 023
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Recursion is when a function calls itself.
|
||||
We often use it instead of while/for loops, as loops usually involve mutable state.
|
||||
Replace the empty string in `highPrecedence` with a call to `highPrecedence` with `str2` as argument.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(highPrecedence("2*2*2") === "8" && highPrecedence("2*2") === "4" && highPrecedence("2+2") === "2+2");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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 : "";
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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);
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,143 @@
|
||||
---
|
||||
id: 5d792534257122211d3043af
|
||||
title: Step 024
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Define an object `spreadsheetFunctions`, with a single key - an empty string (`""`).
|
||||
The corresponding value should be the function `x => x`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(spreadsheetFunctions[""]("x") === "x");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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);
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,152 @@
|
||||
---
|
||||
id: 5d7925346f4f2da6df4354a6
|
||||
title: Step 025
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Define an empty function `applyFn` which takes an argument `str`.
|
||||
Use the curly brace syntax with an anonymous function.
|
||||
Do not wrap parentheses around the parameter.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constapplyFn=str=>{}"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
const applyFn = str => {
|
||||
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,154 @@
|
||||
---
|
||||
id: 5d792534cac2dbe0a719ea7a
|
||||
title: Step 026
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set `noHigh` to `highPrecedence(str)` in `applyFn`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constapplyFn=str=>{constnoHigh=highPrecedence(str)"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
const applyFn = str => {
|
||||
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
const applyFn = str => {
|
||||
const noHigh = highPrecedence(str);
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,155 @@
|
||||
---
|
||||
id: 5d792534857332d07ccba3ad
|
||||
title: Step 027
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set `infix` to `/([0-9.]+)([+-])([0-9.]+)/` in `applyFn`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constapplyFn=str=>{constnoHigh=highPrecedence(str);constinfix=/([0-9.]+)([+-])([0-9.]+)/"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
const applyFn = str => {
|
||||
const noHigh = highPrecedence(str);
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
const applyFn = str => {
|
||||
const noHigh = highPrecedence(str);
|
||||
const infix = /([0-9.]+)([+-])([0-9.]+)/;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,157 @@
|
||||
---
|
||||
id: 5d792534d586ef495ea9df90
|
||||
title: Step 028
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set `str2` to `infixEval(noHigh, infix)`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constapplyFn=str=>{constnoHigh=highPrecedence(str);constinfix=/([0-9.]+)([+-])([0-9.]+)/;conststr2=infixEval(noHigh,infix)"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
const applyFn = str => {
|
||||
const noHigh = highPrecedence(str);
|
||||
const infix = /([0-9.]+)([+-])([0-9.]+)/;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
const applyFn = str => {
|
||||
const noHigh = highPrecedence(str);
|
||||
const infix = /([0-9.]+)([+-])([0-9.]+)/;
|
||||
const str2 = infixEval(noHigh, infix);
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,159 @@
|
||||
---
|
||||
id: 5d79253410532e13d13fe574
|
||||
title: Step 029
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set `regex` to `/([a-z]*)\(([0-9., ]*)\)(?!.*\()/i` in `applyFn`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(applyFn.toString().replace(/\s/g, '').includes('varregex=/([a-z]*)\\(([0-9.,]*)\\)(?!.*\\()/i'));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
const applyFn = str => {
|
||||
const noHigh = highPrecedence(str);
|
||||
const infix = /([0-9.]+)([+-])([0-9.]+)/;
|
||||
const str2 = infixEval(noHigh, infix);
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,169 @@
|
||||
---
|
||||
id: 5d7925342415527083bd6667
|
||||
title: Step 030
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The `split` method returns an array of strings from a larger string by using its argument to determine where to make each split:
|
||||
|
||||
```js
|
||||
"a b c".split(" "); // ["a", "b", "c"];
|
||||
```
|
||||
|
||||
Add a function `toNumberList` (inside `applyFn`) which takes an argument `args` and splits it by commas.
|
||||
Return `toNumberList`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(JSON.stringify(applyFn("")("foo,baz,bar")) === '["foo","baz","bar"]');
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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(",");
|
||||
return toNumberList;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,167 @@
|
||||
---
|
||||
id: 5d792534c3d26890ac1484d4
|
||||
title: Step 031
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The `map` method takes a function and for each element of an array, it passes the element to the function and replace the element with the return value:
|
||||
|
||||
```js
|
||||
[1, 2, 3].map(x => x + 1); // [2, 3, 4]
|
||||
```
|
||||
|
||||
In `toNumberList`, chain the `map` method to `args.split(",")` and pass it `parseFloat` to parse each element of the array into a number.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes('consttoNumberList=args=>args.split(",").map(parseFloat)'));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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(",");
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,164 @@
|
||||
---
|
||||
id: 5d792534b92f3d1cd4410ce3
|
||||
title: Step 032
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Define a new function `applyFunction` (inside `applyFn`).
|
||||
It should take two arguments: `fn` and `args`, and should return `spreadsheetFunctions`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes('consttoNumberList=args=>args.split(",").map(parseFloat);constapplyFunction=(fn,args)=>spreadsheetFunctions'));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,164 @@
|
||||
---
|
||||
id: 5d7925341193948dfe6d76b4
|
||||
title: Step 033
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now, instead of returning `spreadsheetFunctions`, use bracket notation and `fn.toLowerCase()` to get a specific function from `spreadsheetFunctions`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes('consttoNumberList=args=>args.split(",").map(parseFloat);constapplyFunction=(fn,args)=>spreadsheetFunctions[fn.toLowerCase()]'));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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()];
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,165 @@
|
||||
---
|
||||
id: 5d792534cf81365cfca58794
|
||||
title: Step 034
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Apply `toNumberList(args)` to `spreadsheetFunctions[fn.toLowerCase()]`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes('consttoNumberList=args=>args.split(",").map(parseFloat);constapplyFunction=(fn,args)=>spreadsheetFunctions[fn.toLowerCase()](toNumberList(args))'));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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()];
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,169 @@
|
||||
---
|
||||
id: 5d7925348ee084278ff15556
|
||||
title: Step 035
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Note that `applyFunction` can access `toNumberList` from outside of itself.
|
||||
This is called lexical scoping - inner functions can access variables from outer functions.
|
||||
Now return `str2.replace(regex, "")` at the end of `applyFn`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(applyFn("2*2fn(1, 2, 3.3)") === "4");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, "");
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,168 @@
|
||||
---
|
||||
id: 5d7925348a6a41c32f7a4e3e
|
||||
title: Step 036
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Replace the `""` in `str2.replace(regex, "")` with a function which takes `match`, `fn` and `args` as arguments and returns `spreadsheetFunctions`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("returnstr2.replace(regex,(match,fn,args)=>spreadsheetFunctions)"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, "");
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,174 @@
|
||||
---
|
||||
id: 5d792534408c5be896b0a46e
|
||||
title: Step 037
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The `hasOwnProperty` method checks if a key exists in an object.
|
||||
So `spreadsheetFunctions.hasOwnProperty("")` would return `true`, but replacing `""` with anything else would make it return `false`.
|
||||
Chain `hasOwnProperty` to `spreadsheetFunctions` to check if the `fn.toLowerCase()` key exists in `spreadsheetFunctions`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("returnstr2.replace(regex,(match,fn,args)=>spreadsheetFunctions.hasOwnProperty(fn.toLowerCase()))"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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())
|
||||
);
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,176 @@
|
||||
---
|
||||
id: 5d792534f0eda837510e9192
|
||||
title: Step 038
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now use the ternary operator in the last line to return `applyFunction(fn, args)` if the statement is true, and `match` otherwise.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(applyFn("2+2*2") === "6" && applyFn("(2+2)*2") === "4*2");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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
|
||||
);
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,180 @@
|
||||
---
|
||||
id: 5d7925346b911fce161febaf
|
||||
title: Step 039
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now define an empty function `range` which takes `start` and `end` as arguments (define it in the global scope).
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constrange=(start,end)=>"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,185 @@
|
||||
---
|
||||
id: 5d79253483eada4dd69258eb
|
||||
title: Step 040
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
`range` should set `arr` to `[start]` and should then return `arr`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constarr=[start]") && JSON.stringify(range(1)) === "[1]");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
const arr = [start];
|
||||
return arr;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,187 @@
|
||||
---
|
||||
id: 5d7925342b2b993ef18cd45f
|
||||
title: Step 041
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
After declaring `arr`, but before returning it, `range` should use the `push` method to add `end` onto `arr`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(JSON.stringify(range(1, 2)) === "[1,2]" && code.includes("push"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
const arr = [start];
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
const arr = [start];
|
||||
arr.push(end);
|
||||
return arr;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,196 @@
|
||||
---
|
||||
id: 5d7925341747ad42b12f8e68
|
||||
title: Step 042
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
This is still valid because we're modifying `arr` in place instead of reassigning to it (which is invalid with the `const` keyword).
|
||||
But doing this still modifies state, and we don't want to do that in functional programming.
|
||||
The `concat` method returns a new array instead of modifying an existing one:
|
||||
|
||||
```js
|
||||
[1,2,3].concat(4); // [1, 2, 3, 4]
|
||||
[1,2,3].concat(4, 5); // [1, 2, 3, 4, 5]
|
||||
```
|
||||
|
||||
Use `concat` instead of `push` to return the result of adding `end` to `arr`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(JSON.stringify(range(1,2)) === "[1,2]" && code.includes("concat") && !(code.includes("push")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
const arr = [start];
|
||||
arr.push(end);
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
const arr = [start];
|
||||
return arr.concat(end);
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,193 @@
|
||||
---
|
||||
id: 5d792535b0b3c198ee3ed6f9
|
||||
title: Step 043
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The `concat` method can also accept arrays:
|
||||
|
||||
```js
|
||||
[1,2,3].concat([4, 5]); // [1, 2, 3, 4, 5]
|
||||
[1,2,3].concat([4, 5], [6, 7]); // [1, 2, 3, 4, 5, 6, 7]
|
||||
```
|
||||
|
||||
Use this form of `concat` by passing an array with just `end` to it: `arr.concat([end])`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("returnarr.concat([end])"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
const arr = [start];
|
||||
return arr.concat(end);
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
const arr = [start];
|
||||
return arr.concat([end]);
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,185 @@
|
||||
---
|
||||
id: 5d7925357a0533eb221b005d
|
||||
title: Step 044
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Replace the call to `arr` in `arr.concat([end])` with `[start]` and remove the `arr` variable and its definition.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(!(code.includes("arr")) && code.replace(/\s/g, "").includes("[start].concat([end])"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
const arr = [start];
|
||||
return arr.concat([end]);
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
return [start].concat([end]);
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,184 @@
|
||||
---
|
||||
id: 5d792535591db67ee15b4106
|
||||
title: Step 045
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Use the ternary operator to return `[]` if `start > end` and `[start].concat([end])` otherwise.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(JSON.stringify(range(3, 2)) === "[]" && JSON.stringify(range(1, 3)) === "[1,3]");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
return [start].concat([end]);
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
return start > end ? [] : [start].concat([end]);
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,184 @@
|
||||
---
|
||||
id: 5d792535f1f7adf77de5831d
|
||||
title: Step 046
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Replace `[end]` with a recursive call to `range`: `[start].concat(range(start + 1, end))`
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(JSON.stringify(range(1, 5)) === "[1,2,3,4,5]");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
return start > end ? [] : [start].concat([end]);
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
return start > end ? [] : [start].concat(range(start + 1, end));
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,183 @@
|
||||
---
|
||||
id: 5d7925353d2c505eafd50cd9
|
||||
title: Step 047
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Remove the curly braces and `return` keyword from `range`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constrange=(start,end)=>start>end?[]:[start].concat(range(start+1,end))"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => {
|
||||
return start > end ? [] : [start].concat(range(start + 1, end));
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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));
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,185 @@
|
||||
---
|
||||
id: 5d79253539b5e944ba3e314c
|
||||
title: Step 048
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Define a function `charRange` which takes `start` and `end` as arguments.
|
||||
It should return `start`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constcharRange=(start,end)=>start"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => start;
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,186 @@
|
||||
---
|
||||
id: 5d792535a4f1cbff7a8b9a0b
|
||||
title: Step 049
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Make `charRange` return `range(start, end)`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(JSON.stringify(charRange(1,5)) === "[1,2,3,4,5]");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => start;
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, end);
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,186 @@
|
||||
---
|
||||
id: 5d792535e3304f15a8890162
|
||||
title: Step 050
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Use the `charCodeAt(0)` method on `start` and `end` in `charRange`, like this: `start.charCodeAt(0)`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(JSON.stringify(charRange("A", "C")) === "[65,66,67]");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, end);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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));
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,186 @@
|
||||
---
|
||||
id: 5d792535a40ea5ac549d6804
|
||||
title: Step 051
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Chain `map` onto `range(start.charCodeAt(0), end.charCodeAt(0))`, with `x => x` as the argument.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("range(start.charCodeAt(0),end.charCodeAt(0)).map(x=>x)"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => x);
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,189 @@
|
||||
---
|
||||
id: 5d7925358c220e5b2998909e
|
||||
title: Step 052
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now, pass `x` to `String.fromCharCode` in the arrow function.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(JSON.stringify(charRange("A", "C")) === '["A","B","C"]');
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => x);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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)
|
||||
);
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,198 @@
|
||||
---
|
||||
id: 5d7925357729e183a49498aa
|
||||
title: Step 053
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Create a new function `evalFormula` which takes a single argument, `x`.
|
||||
Set `/([A-J])([1-9][0-9]?):([A-J])([1-9][0-9]?)/gi` to a variable named `rangeRegex`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constevalFormula=x=>{constrangeRegex=/([A-J])([1-9][0-9]?):([A-J])([1-9][0-9]?)/gi"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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)
|
||||
);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,202 @@
|
||||
---
|
||||
id: 5d79253555aa652afbb68086
|
||||
title: Step 054
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Define a function `rangeFromString` in `evalFormula` which takes `n1` and `n2` as arguments and returns `n1`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/evalFormula.*constrangeFromString=\(n1,n2\)=>n1/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => n1;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,202 @@
|
||||
---
|
||||
id: 5d79253582be306d339564f6
|
||||
title: Step 055
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Replace the `n1` return value in `rangeFromString` with `range(n1, n2)`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/evalFormula.*constrangeFromString=\(n1,n2\)=>range\(n1,n2\)/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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) => n1;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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(n1, n2);
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,202 @@
|
||||
---
|
||||
id: 5d7925352047e5c54882c436
|
||||
title: Step 056
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
As `n1` and `n2` are actually strings, replace `n1` and `n2` with `parseInt(n1)` and `parseInt(n2)`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/evalFormula.*constrangeFromString=\(n1,n2\)=>range\(parseInt\(n1\),parseInt\(n2\)\)/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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(n1, n2);
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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));
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,206 @@
|
||||
---
|
||||
id: 5d79253568e441c0adf9db9f
|
||||
title: Step 057
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now define a function `elemValue`, which takes an argument `n` and returns `n`.
|
||||
Use the curly brace arrow function syntax.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/evalFormula.*constelemValue=n=>\{returnn;?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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));
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => {
|
||||
return n;
|
||||
};
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,210 @@
|
||||
---
|
||||
id: 5d7925356ab117923b80c9cd
|
||||
title: Step 058
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Inside `elemValue`, define `fn` to be a function which takes `c` as argument and returns `document.getElementById(c + n).value`.
|
||||
Return `fn` instead of `n`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/elemValue.*constfn=\(?c\)?=>document\.getElementById\(c\+n\)\.value;?returnfn;?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => {
|
||||
return n;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => {
|
||||
const fn = c => document.getElementById(c + n).value;
|
||||
return fn;
|
||||
};
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,212 @@
|
||||
---
|
||||
id: 5d792535e54a8cd729a0d708
|
||||
title: Step 059
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now define `fn` to be `elemValue("1")` (inside `evalFormula` but outside `elemValue`).
|
||||
As `elemValue` returns a function, `fn` is also a function.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/elemValue.*constfn=elemValue\(['"]1['"]\);?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => {
|
||||
const fn = c => document.getElementById(c + n).value;
|
||||
return fn;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => {
|
||||
const fn = c => document.getElementById(c + n).value;
|
||||
return fn;
|
||||
};
|
||||
const fn = elemValue("1");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,213 @@
|
||||
---
|
||||
id: 5d7925353b307724a462b06b
|
||||
title: Step 060
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Finally, return `fn("A")`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/elemValue.*constfn=elemValue\(['"]1['"]\);?returnfn\(['"]A['"]\);?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => {
|
||||
const fn = c => document.getElementById(c + n).value;
|
||||
return fn;
|
||||
};
|
||||
const fn = elemValue("1");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => {
|
||||
const fn = c => document.getElementById(c + n).value;
|
||||
return fn;
|
||||
};
|
||||
const fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,215 @@
|
||||
---
|
||||
id: 5d792536735f71d746ee5d99
|
||||
title: Step 061
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
You might think that this wouldn't work because `fn` wouldn't have access to `n` after `elemValue` has finished executing.
|
||||
However, this works because of closures - functions have access to all variables declared at their time of creation.
|
||||
Inside `elemValue`, remove the variable `fn` and its definition, and replace `return fn` with `return c => document.getElementById(c + n).value`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constelemValue=n=>{returnc=>document.getElementById(c+n).value"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => {
|
||||
const fn = c => document.getElementById(c + n).value;
|
||||
return fn;
|
||||
};
|
||||
const fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => {
|
||||
return c => document.getElementById(c + n).value;
|
||||
};
|
||||
const fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,210 @@
|
||||
---
|
||||
id: 5d792536ad340d9dff2e4a96
|
||||
title: Step 062
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now, remove the curly braces and return statement.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/constelemValue=n=>\(?c=>document\.getElementById\(c\+n\)\.value/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => {
|
||||
return c => document.getElementById(c + n).value;
|
||||
};
|
||||
const fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,210 @@
|
||||
---
|
||||
id: 5d7925369614afd92d01fed5
|
||||
title: Step 063
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
You also don't need the parentheses in `elemValue` - it's parsed this way automatically.
|
||||
Remove them.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/constelemValue=n=>c=>document\.getElementById\(c\+n\)\.value/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,211 @@
|
||||
---
|
||||
id: 5d792536504e68254fe02236
|
||||
title: Step 064
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The technique we just used is called currying - instead of taking multiple arguments, a function takes a single argument and return another function, which also takes a single argument.
|
||||
Define a new curried function, `addChars`, and set it equal to `c1 => c2 => c1 + c2`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constaddChars=c1=>c2=>c1+c2"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => c1 + c2
|
||||
const fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,216 @@
|
||||
---
|
||||
id: 5d792536c8d2f0fdfad768fe
|
||||
title: Step 065
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
You can add more arguments by simply adding another arrow with another argument name:
|
||||
|
||||
```js
|
||||
const manyArguments = a => b => c => d => [a, b, c, d]
|
||||
```
|
||||
|
||||
Add another argument to `addChars` and add it to the sum: `c1 => c2 => n => c1 + c2 + n`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constaddChars=c1=>c2=>n=>c1+c2+n"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => c1 + c2
|
||||
const fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => c1 + c2 + n
|
||||
const fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,210 @@
|
||||
---
|
||||
id: 5d79253639028b8ec56afcda
|
||||
title: Step 066
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Replace the body of `addChars`, so that instead of adding the arguments, it returns a `charRange` between the first two arguments: `c1 => c2 => n => charRange(c1, c2)`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constaddChars=c1=>c2=>n=>charRange(c1,c2)"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => c1 + c2 + n
|
||||
const fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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)
|
||||
const fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,217 @@
|
||||
---
|
||||
id: 5d792536834f2fd93e84944f
|
||||
title: Step 067
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
You call curried functions like this:
|
||||
|
||||
```js
|
||||
const result = add(1)(2);
|
||||
```
|
||||
|
||||
Use `map` on the `charRange` in `addChars`, passing in `x => elemValue(n)(x)` as the argument.
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constaddChars=c1=>c2=>n=>charRange(c1,c2).map(x=>elemValue(n)(x))"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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)
|
||||
const fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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(x => elemValue(n)(x));
|
||||
const fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,212 @@
|
||||
---
|
||||
id: 5d792536ddff9ea73c90a994
|
||||
title: Step 068
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
However, you don't need an arrow function.
|
||||
As `elemValue(n)` is a function, you can pass it to `map` directly.
|
||||
Change `x => elemValue(n)(x)` to `elemValue(n)`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constaddChars=c1=>c2=>n=>charRange(c1,c2).map(elemValue(n))"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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(x => elemValue(n)(x));
|
||||
const fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,212 @@
|
||||
---
|
||||
id: 5d7925361596f84067904f7f
|
||||
title: Step 069
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Remove the `fn` declaration and return statement.
|
||||
Set `varRangeExpanded` to the result of using the `replace` method on `x`, with `rangeRegex` as the first argument and `""` as the second argument.
|
||||
Then, return it.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(!(code.includes("const fn")) && code.includes("varRangeExpanded") && evalFormula("A1:J133") === "3");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 fn = elemValue("1");
|
||||
return fn("A");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, "");
|
||||
return varRangeExpanded;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,212 @@
|
||||
---
|
||||
id: 5d792536dd8a4daf255488ac
|
||||
title: Step 070
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Replace the `""` in `varRangeExpanded` with a function, which takes `match`, `c1`, `n1`, `c2` and `n2` as arguments, and returns `n1`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes('constvarRangeExpanded=x.replace(rangeRegex,(match,c1,n1,c2,n2)=>n1)'));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, "");
|
||||
return varRangeExpanded;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, (match, c1, n1, c2, n2) =>
|
||||
n1
|
||||
);
|
||||
return varRangeExpanded;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,214 @@
|
||||
---
|
||||
id: 5d792536449c73004f265fb1
|
||||
title: Step 071
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Replace the `n1` return value in `varRangeExpanded` with `rangeFromString(n1, n2)`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes('constvarRangeExpanded=x.replace(rangeRegex,(match,c1,n1,c2,n2)=>rangeFromString(n1,n2))'));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, (match, c1, n1, c2, n2) =>
|
||||
n1
|
||||
);
|
||||
return varRangeExpanded;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, (match, c1, n1, c2, n2) =>
|
||||
rangeFromString(n1, n2)
|
||||
);
|
||||
return varRangeExpanded;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,215 @@
|
||||
---
|
||||
id: 5d79253685fc69b8fe60a0d2
|
||||
title: Step 072
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Chain the `map` method to `rangeFromString(n1, n2)` and pass it `addChars(c1)(c2)` as an argument.
|
||||
This returns an `addChars` function, which has `c1` and `c2` (the characters) preset, and only needs a number (`n`) to be passed to it (which we get from the `rangeFromString` array).
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes('constvarRangeExpanded=x.replace(rangeRegex,(match,c1,n1,c2,n2)=>rangeFromString(n1,n2).map(addChars(c1)(c2)))'));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, (match, c1, n1, c2, n2) =>
|
||||
rangeFromString(n1, n2)
|
||||
);
|
||||
return varRangeExpanded;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, (match, c1, n1, c2, n2) =>
|
||||
rangeFromString(n1, n2).map(addChars(c1)(c2))
|
||||
);
|
||||
return varRangeExpanded;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,215 @@
|
||||
---
|
||||
id: 5d792536dc6e3ab29525de9e
|
||||
title: Step 073
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The function in `varRangeExpanded` contains an unused argument.
|
||||
Replace or prefix it with an underscore.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constvarRangeExpanded=x.replace(rangeRegex,(_"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, (match, c1, n1, c2, n2) =>
|
||||
rangeFromString(n1, n2).map(addChars(c1)(c2))
|
||||
);
|
||||
return varRangeExpanded;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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))
|
||||
);
|
||||
return varRangeExpanded;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,218 @@
|
||||
---
|
||||
id: 5d792536cfd0fd893c630abb
|
||||
title: Step 074
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set `varRegex` to `/[A-J][1-9][0-9]?/gi`.
|
||||
Then set `varExpanded` to the result of replacing `varRegex` with an empty string in `varRangeExpanded`.
|
||||
Return `varExpanded`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.includes("varRegex") && code.includes("varExpanded") && evalFormula("aC12bc") === "abc");
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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))
|
||||
);
|
||||
return varRangeExpanded;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, "");
|
||||
return varExpanded;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,221 @@
|
||||
---
|
||||
id: 5d7925366a5ff428fb483b40
|
||||
title: Step 075
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Replace the `""` in `varExpanded` with `match => document.getElementById(match.toUpperCase()).value`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("constvarExpanded=varRangeExpanded.replace(varRegex,match=>document.getElementById(match.toUpperCase()).value)"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, "");
|
||||
return varExpanded;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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
|
||||
);
|
||||
return varExpanded;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,225 @@
|
||||
---
|
||||
id: 5d7925365d4035eeb2e395fd
|
||||
title: Step 076
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set `functionExpanded` to `applyFn(varExpanded)` in `evalFormula`.
|
||||
Return `functionExpanded`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.includes("functionExpanded") && applyFn("2+2") === "4");
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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
|
||||
);
|
||||
return varExpanded;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,230 @@
|
||||
---
|
||||
id: 5d7925364c106e9aaf05a16f
|
||||
title: Step 077
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
`evalFormula` should return the value passed to it if this value remained unchanged.
|
||||
Otherwise, it should call itself with the latest value.
|
||||
Use the ternary operator in the last line of `evalFormula` to return `functionExpanded` if `x === functionExpanded` and `evalFormula(functionExpanded)` otherwise.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(evalFormula("(2+2)*2") === "8")
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,238 @@
|
||||
---
|
||||
id: 5d792536970cd8e819cc8a96
|
||||
title: Step 078
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
You can define arrow functions without arguments:
|
||||
|
||||
```js
|
||||
const two = () => 2;
|
||||
```
|
||||
|
||||
Define an empty arrow function without arguments and assign it to `window.onload`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("window.onload=()=>"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 = () => { };
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,238 @@
|
||||
---
|
||||
id: 5d792536e33baeaa60129e0a
|
||||
title: Step 079
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
In `window.onload`, assign `document.getElementById("container")` to `container`.
|
||||
Also assign `charRange("A", "J")` to `letters`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/window\.onload=\(\)=>\{constcontainer=document\.getElementById\(["']container["']\);?constletters=charRange\(["']A["'],["']J["']\);?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 = () => { };
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 letters = charRange("A", "J");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,243 @@
|
||||
---
|
||||
id: 5d7925379e2a488f333e2d43
|
||||
title: Step 080
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now define a function `createLabel` which takes an argument `name` and has an empty body.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/window\.onload[\s\S]*constcreateLabel=\(?name\)?=>\{\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 letters = charRange("A", "J");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 letters = charRange("A", "J");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,246 @@
|
||||
---
|
||||
id: 5d7925379000785f6d8d9af3
|
||||
title: Step 081
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Inside `createLabel`, assign `document.createElement("div")` to `label`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/window\.onload[\s\S]*constcreateLabel=\(?name\)?=>\{constlabel=document\.createElement\(["']div["']\);?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 letters = charRange("A", "J");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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");
|
||||
};
|
||||
const letters = charRange("A", "J");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,256 @@
|
||||
---
|
||||
id: 5d79253791391b0acddd0ac5
|
||||
title: Step 082
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add the following code to `createLabel`:
|
||||
|
||||
```js
|
||||
label.className = "label";
|
||||
label.textContent = name;
|
||||
container.appendChild(label);
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/window\.onload[\s\S]*constcreateLabel=\(?name\)?=>\{constlabel=document\.createElement\(["']div["']\);?label\.className=["']label["'];?label\.textContent=name;?container\.appendChild\(label\);?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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");
|
||||
};
|
||||
const letters = charRange("A", "J");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,254 @@
|
||||
---
|
||||
id: 5d7925373104ae5ae83f20a5
|
||||
title: Step 083
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The `forEach` method takes a function and calls it with each element of the array.
|
||||
Chain `forEach` to `letters` and pass it the `createLabel` function to create a label for each of the letters.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("letters.forEach(createLabel)"))
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,255 @@
|
||||
---
|
||||
id: 5d7925373b7127cfaeb50c26
|
||||
title: Step 084
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add `range(1, 99)` to the end of `window.onload` (the result will be discarded for now).
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/window\.onload[\s\S]*range\(1,99\);?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,256 @@
|
||||
---
|
||||
id: 5d792537cb3a5cd6baca5e1a
|
||||
title: Step 085
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Chain `forEach` onto `range(1, 99)`, passing in `createLabel` as an argument.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/window\.onload[\s\S]*range\(1,99\)\.forEach\(createLabel\);?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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(createLabel);
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,260 @@
|
||||
---
|
||||
id: 5d79253742f3313d55db981f
|
||||
title: Step 086
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Replace `createLabel` with an arrow function with a block body.
|
||||
This would allow us to add more statements.
|
||||
The arrow function should take an argument `x`, and call `createLabel(x)`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/window\.onload[\s\S]*range\(1,99\)\.forEach\(\(?x\)?=>\{createLabel\(x\);?\}\);?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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(createLabel);
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,263 @@
|
||||
---
|
||||
id: 5d7925379e0180a438ce7f95
|
||||
title: Step 087
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Inside the `range` `forEach`, use the `forEach` method on `letters`, passing in a function with argument `x` and an empty body.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/window\.onload.*range\(1,99\)\.forEach\(\(?x\)?=>\{createLabel\(x\);?letters\.forEach\(\(?y\)?=>\{\}\);?\}\);?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => {
|
||||
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,266 @@
|
||||
---
|
||||
id: 5d792537c80984dfa5501b96
|
||||
title: Step 088
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Inside `letters.forEach`, assign `document.createElement("input")` to `input`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/window\.onload[\s\S]*range\(1,99\)\.forEach\(\(?x\)?=>\{createLabel\(x\);?letters\.forEach\(\(?y\)?=>\{constinput=document\.createElement\(["']input["']\);?\}\);?\}\);?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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 => {
|
||||
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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");
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,278 @@
|
||||
---
|
||||
id: 5d7925377b54d8a76efb5657
|
||||
title: Step 089
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add the following code to `letters.forEach`:
|
||||
|
||||
```js
|
||||
input.type = "text";
|
||||
input.id = y + x;
|
||||
input.onchange = update;
|
||||
container.appendChild(input);
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/window\.onload[\s\S]*range\(1,99\)\.forEach\(\(?x\)?=>\{createLabel\(x\);?letters\.forEach\(\(?y\)?=>\{constinput=document\.createElement\(["']input["']\);?input\.type=["']text["'];?input\.id=y\+x;?input\.onchange=update;?container\.appendChild\(input\);?\}\);?\}\);?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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");
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,279 @@
|
||||
---
|
||||
id: 5d7925371398513549bb6395
|
||||
title: Step 090
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
In the global scope, define a function called `update` which takes `event` as argument.
|
||||
It should define a variable, `element`, setting it to `event.target`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/constupdate=\(?event\)?=>\{?constelement=event\.target;?\}?/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,284 @@
|
||||
---
|
||||
id: 5d792537ea3eaf302bf2d359
|
||||
title: Step 091
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now set `value` to `element.value.replace(/\s/g, "")`.
|
||||
This removes all whitespace from `element` so that we can ignore it.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/constupdate=\(?event\)?=>\{constelement=event\.target;?constvalue=element\.value\.replace\(\/\\s\/g,["']{2}\);?\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, "");
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,286 @@
|
||||
---
|
||||
id: 5d792537533b1c7843bfd029
|
||||
title: Step 092
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The `includes` method works on a string and checks if the argument is its substring.
|
||||
Add an empty if statement to `update` which executes if `element.id` is **not** a substring of `value`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/constupdate=\(?event\)?=>\{constelement=event\.target;?constvalue=element\.value\.replace\(\/\\s\/g,["']{2}\);?if\(!\(?value\.includes\(element\.id\)\)?\)\{\}\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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, "");
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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)) {}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,287 @@
|
||||
---
|
||||
id: 5d792537dc0fe84345d4f19e
|
||||
title: Step 093
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add another condition to the if statement so that it only executes if the first character of `value` is `=`.
|
||||
Do this by adding `&& value[0] === "="` to the if statement.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/constupdate=\(?event\)?=>\{constelement=event\.target;?constvalue=element\.value\.replace\(\/\\s\/g,["']{2}\);?if\(!\(?value\.includes\(element\.id\)\)?&&value\[0\]===["']=["']\)\{\}\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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)) {}
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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] === "=") {}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,291 @@
|
||||
---
|
||||
id: 5d792537b6cadae0f4b0cda1
|
||||
title: Step 094
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The `slice` method takes two arguments.
|
||||
It extracts characters from the string from the index specified by the first argument up to (but not including) the second argument.
|
||||
The index starts at 0.
|
||||
Use the `slice` method to log the first two letters of `value` to the console.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("console.log(value.slice(0,2))"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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] === "=") {}
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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] === "=") {
|
||||
console.log(value.slice(0, 2));
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,292 @@
|
||||
---
|
||||
id: 5d79253770083fb730c93a93
|
||||
title: Step 095
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
You don't have to specify the second argument in `slice`.
|
||||
If you don't, then `slice` will extract from the first argument to the end of the string.
|
||||
Change the call to `slice` to log all characters except the first instead.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(code.replace(/\s/g, "").includes("console.log(value.slice(1))"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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] === "=") {
|
||||
console.log(value.slice(0, 2));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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] === "=") {
|
||||
console.log(value.slice(1));
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,293 @@
|
||||
---
|
||||
id: 5d792537fef76b226b63b93b
|
||||
title: Step 096
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now change the if statement to set `element.value` to the result of passing `value.slice(1)` to `evalFormula`.
|
||||
There is no need to use `const` because we're modifying `element.value`, not declaring it.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/constupdate=\(?event\)?=>\{constelement=event\.target;?constvalue=element\.value\.replace\(\/\\s\/g,["']{2}\);?if\(!\(?value\.includes\(element\.id\)\)?&&value\[0\]===["']=["']\)\{element\.value=evalFormula\(value\.slice\(1\)\);?\}\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
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] === "=") {
|
||||
console.log(value.slice(1));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,300 @@
|
||||
---
|
||||
id: 5d79253760fca25ccbbd8990
|
||||
title: Step 097
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The array destructuring syntax can be used to extract values from arrays:
|
||||
|
||||
```js
|
||||
const [x, y] = [1, 2]; // in variables
|
||||
const fn = ([x, y]) => x + y // in functions
|
||||
```
|
||||
|
||||
Use this syntax to define a function `random` in `spreadsheetFunctions` which takes the array `[x, y]` and returns `x`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/["']?random["']?:\(\[x,y\]\)=>x/.test(code.replace(/\s/g, "")) && spreadsheetFunctions["random"]([1, 2]) === 1);
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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
|
||||
};
|
||||
|
||||
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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]) => 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>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,294 @@
|
||||
---
|
||||
id: 5d7925374321824cba309875
|
||||
title: Step 098
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Change the `random` function so that it returns `Math.floor(Math.random() * y + x)`.
|
||||
It now returns a random number within a range.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/["']?random["']?:\(\[x,y\]\)=>Math\.floor\(Math\.random\(\)\*y\+x\)/.test(code.replace(/\s/g, "")) && spreadsheetFunctions["random"]([1, 1]) === 1);
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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]) => 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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,302 @@
|
||||
---
|
||||
id: 5d7925381e8565a5c50ba7f1
|
||||
title: Step 099
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='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):
|
||||
|
||||
```js
|
||||
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]`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/(spreadsheetFunctions\[["']random["']\]\(1,1000\))===\1/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</section>
|
@ -0,0 +1,298 @@
|
||||
---
|
||||
id: 5d7925383f1b77db7f1ff59e
|
||||
title: Step 100
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
This is (probably) false, so `random` is certainly impure.
|
||||
The second property of pure functions is that they perform no side effects, which are state and I/O modifications.
|
||||
If you call a function without assigning the result to a variable, and it does something, then it's an impure function.
|
||||
Call `window.onload()` in `update`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: See description above for instructions.
|
||||
testString: assert(/update=\(?event\)?=>\{.*window\.onload\(\).*\}/.test(code.replace(/\s/g, "")));
|
||||
|
||||
```
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### After Test
|
||||
<div id='html-teardown'>
|
||||
|
||||
```html
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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 => {
|
||||
// window.onload();
|
||||
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>
|
||||
```
|
||||
|
||||
</section>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user