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:
parent
89e18e3a81
commit
2fbafda167
@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Introduction to the JavaScript Spreadsheet
|
||||
block: JavaScript Spreadsheet
|
||||
superBlock: JavaScript Algorithms and Data Structures
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Introduction to the JavaScript Spreadsheet
|
||||
|
||||
This is a test for the new project-based curriculum.
|
579
curriculum/challenges/_meta/javascript-spreadsheet/meta.json
Normal file
579
curriculum/challenges/_meta/javascript-spreadsheet/meta.json
Normal file
@ -0,0 +1,579 @@
|
||||
{
|
||||
"name": "JavaScript Spreadsheet",
|
||||
"dashedName": "javascript-spreadsheet",
|
||||
"order": 12,
|
||||
"time": "2 hours",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "javascript-algorithms-and-data-structures",
|
||||
"superOrder": 2,
|
||||
"isBeta": true,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"5d79253297c0ebb149ea9fed",
|
||||
"Step 001"
|
||||
],
|
||||
[
|
||||
"5d7925323be8848dbc58a07a",
|
||||
"Step 002"
|
||||
],
|
||||
[
|
||||
"5d792532f631702ae6d23e11",
|
||||
"Step 003"
|
||||
],
|
||||
[
|
||||
"5d7925329445167ecc2ac9c9",
|
||||
"Step 004"
|
||||
],
|
||||
[
|
||||
"5d792532b07918c3a5904913",
|
||||
"Step 005"
|
||||
],
|
||||
[
|
||||
"5d792533cc8b18b6c133edc7",
|
||||
"Step 006"
|
||||
],
|
||||
[
|
||||
"5d7925337954ed57a565a135",
|
||||
"Step 007"
|
||||
],
|
||||
[
|
||||
"5d79253352e33dd59ec2f6de",
|
||||
"Step 008"
|
||||
],
|
||||
[
|
||||
"5d792533d31e4f7fad33011d",
|
||||
"Step 009"
|
||||
],
|
||||
[
|
||||
"5d792533e7707b9645d7b540",
|
||||
"Step 010"
|
||||
],
|
||||
[
|
||||
"5d79253378595ec568f70ab6",
|
||||
"Step 011"
|
||||
],
|
||||
[
|
||||
"5d7925330918ae4a2f282e7e",
|
||||
"Step 012"
|
||||
],
|
||||
[
|
||||
"5d792533ed00e75d129e1b18",
|
||||
"Step 013"
|
||||
],
|
||||
[
|
||||
"5d792533a5c42fb4d1a4b70d",
|
||||
"Step 014"
|
||||
],
|
||||
[
|
||||
"5d79253358e8f646cbeb2bb0",
|
||||
"Step 015"
|
||||
],
|
||||
[
|
||||
"5d792533bb38fab70b27f527",
|
||||
"Step 016"
|
||||
],
|
||||
[
|
||||
"5d79253386060ed9eb04a070",
|
||||
"Step 017"
|
||||
],
|
||||
[
|
||||
"5d792533717672657b81aa69",
|
||||
"Step 018"
|
||||
],
|
||||
[
|
||||
"5d7925335ab63018dcec11fe",
|
||||
"Step 019"
|
||||
],
|
||||
[
|
||||
"5d7925330f300c342315066d",
|
||||
"Step 020"
|
||||
],
|
||||
[
|
||||
"5d792533aa6443215c9b16bf",
|
||||
"Step 021"
|
||||
],
|
||||
[
|
||||
"5d7925334c5e22586dd72962",
|
||||
"Step 022"
|
||||
],
|
||||
[
|
||||
"5d79253307ecd49e030bdcd1",
|
||||
"Step 023"
|
||||
],
|
||||
[
|
||||
"5d792534257122211d3043af",
|
||||
"Step 024"
|
||||
],
|
||||
[
|
||||
"5d7925346f4f2da6df4354a6",
|
||||
"Step 025"
|
||||
],
|
||||
[
|
||||
"5d792534cac2dbe0a719ea7a",
|
||||
"Step 026"
|
||||
],
|
||||
[
|
||||
"5d792534857332d07ccba3ad",
|
||||
"Step 027"
|
||||
],
|
||||
[
|
||||
"5d792534d586ef495ea9df90",
|
||||
"Step 028"
|
||||
],
|
||||
[
|
||||
"5d79253410532e13d13fe574",
|
||||
"Step 029"
|
||||
],
|
||||
[
|
||||
"5d7925342415527083bd6667",
|
||||
"Step 030"
|
||||
],
|
||||
[
|
||||
"5d792534c3d26890ac1484d4",
|
||||
"Step 031"
|
||||
],
|
||||
[
|
||||
"5d792534b92f3d1cd4410ce3",
|
||||
"Step 032"
|
||||
],
|
||||
[
|
||||
"5d7925341193948dfe6d76b4",
|
||||
"Step 033"
|
||||
],
|
||||
[
|
||||
"5d792534cf81365cfca58794",
|
||||
"Step 034"
|
||||
],
|
||||
[
|
||||
"5d7925348ee084278ff15556",
|
||||
"Step 035"
|
||||
],
|
||||
[
|
||||
"5d7925348a6a41c32f7a4e3e",
|
||||
"Step 036"
|
||||
],
|
||||
[
|
||||
"5d792534408c5be896b0a46e",
|
||||
"Step 037"
|
||||
],
|
||||
[
|
||||
"5d792534f0eda837510e9192",
|
||||
"Step 038"
|
||||
],
|
||||
[
|
||||
"5d7925346b911fce161febaf",
|
||||
"Step 039"
|
||||
],
|
||||
[
|
||||
"5d79253483eada4dd69258eb",
|
||||
"Step 040"
|
||||
],
|
||||
[
|
||||
"5d7925342b2b993ef18cd45f",
|
||||
"Step 041"
|
||||
],
|
||||
[
|
||||
"5d7925341747ad42b12f8e68",
|
||||
"Step 042"
|
||||
],
|
||||
[
|
||||
"5d792535b0b3c198ee3ed6f9",
|
||||
"Step 043"
|
||||
],
|
||||
[
|
||||
"5d7925357a0533eb221b005d",
|
||||
"Step 044"
|
||||
],
|
||||
[
|
||||
"5d792535591db67ee15b4106",
|
||||
"Step 045"
|
||||
],
|
||||
[
|
||||
"5d792535f1f7adf77de5831d",
|
||||
"Step 046"
|
||||
],
|
||||
[
|
||||
"5d7925353d2c505eafd50cd9",
|
||||
"Step 047"
|
||||
],
|
||||
[
|
||||
"5d79253539b5e944ba3e314c",
|
||||
"Step 048"
|
||||
],
|
||||
[
|
||||
"5d792535a4f1cbff7a8b9a0b",
|
||||
"Step 049"
|
||||
],
|
||||
[
|
||||
"5d792535e3304f15a8890162",
|
||||
"Step 050"
|
||||
],
|
||||
[
|
||||
"5d792535a40ea5ac549d6804",
|
||||
"Step 051"
|
||||
],
|
||||
[
|
||||
"5d7925358c220e5b2998909e",
|
||||
"Step 052"
|
||||
],
|
||||
[
|
||||
"5d7925357729e183a49498aa",
|
||||
"Step 053"
|
||||
],
|
||||
[
|
||||
"5d79253555aa652afbb68086",
|
||||
"Step 054"
|
||||
],
|
||||
[
|
||||
"5d79253582be306d339564f6",
|
||||
"Step 055"
|
||||
],
|
||||
[
|
||||
"5d7925352047e5c54882c436",
|
||||
"Step 056"
|
||||
],
|
||||
[
|
||||
"5d79253568e441c0adf9db9f",
|
||||
"Step 057"
|
||||
],
|
||||
[
|
||||
"5d7925356ab117923b80c9cd",
|
||||
"Step 058"
|
||||
],
|
||||
[
|
||||
"5d792535e54a8cd729a0d708",
|
||||
"Step 059"
|
||||
],
|
||||
[
|
||||
"5d7925353b307724a462b06b",
|
||||
"Step 060"
|
||||
],
|
||||
[
|
||||
"5d792536735f71d746ee5d99",
|
||||
"Step 061"
|
||||
],
|
||||
[
|
||||
"5d792536ad340d9dff2e4a96",
|
||||
"Step 062"
|
||||
],
|
||||
[
|
||||
"5d7925369614afd92d01fed5",
|
||||
"Step 063"
|
||||
],
|
||||
[
|
||||
"5d792536504e68254fe02236",
|
||||
"Step 064"
|
||||
],
|
||||
[
|
||||
"5d792536c8d2f0fdfad768fe",
|
||||
"Step 065"
|
||||
],
|
||||
[
|
||||
"5d79253639028b8ec56afcda",
|
||||
"Step 066"
|
||||
],
|
||||
[
|
||||
"5d792536834f2fd93e84944f",
|
||||
"Step 067"
|
||||
],
|
||||
[
|
||||
"5d792536ddff9ea73c90a994",
|
||||
"Step 068"
|
||||
],
|
||||
[
|
||||
"5d7925361596f84067904f7f",
|
||||
"Step 069"
|
||||
],
|
||||
[
|
||||
"5d792536dd8a4daf255488ac",
|
||||
"Step 070"
|
||||
],
|
||||
[
|
||||
"5d792536449c73004f265fb1",
|
||||
"Step 071"
|
||||
],
|
||||
[
|
||||
"5d79253685fc69b8fe60a0d2",
|
||||
"Step 072"
|
||||
],
|
||||
[
|
||||
"5d792536dc6e3ab29525de9e",
|
||||
"Step 073"
|
||||
],
|
||||
[
|
||||
"5d792536cfd0fd893c630abb",
|
||||
"Step 074"
|
||||
],
|
||||
[
|
||||
"5d7925366a5ff428fb483b40",
|
||||
"Step 075"
|
||||
],
|
||||
[
|
||||
"5d7925365d4035eeb2e395fd",
|
||||
"Step 076"
|
||||
],
|
||||
[
|
||||
"5d7925364c106e9aaf05a16f",
|
||||
"Step 077"
|
||||
],
|
||||
[
|
||||
"5d792536970cd8e819cc8a96",
|
||||
"Step 078"
|
||||
],
|
||||
[
|
||||
"5d792536e33baeaa60129e0a",
|
||||
"Step 079"
|
||||
],
|
||||
[
|
||||
"5d7925379e2a488f333e2d43",
|
||||
"Step 080"
|
||||
],
|
||||
[
|
||||
"5d7925379000785f6d8d9af3",
|
||||
"Step 081"
|
||||
],
|
||||
[
|
||||
"5d79253791391b0acddd0ac5",
|
||||
"Step 082"
|
||||
],
|
||||
[
|
||||
"5d7925373104ae5ae83f20a5",
|
||||
"Step 083"
|
||||
],
|
||||
[
|
||||
"5d7925373b7127cfaeb50c26",
|
||||
"Step 084"
|
||||
],
|
||||
[
|
||||
"5d792537cb3a5cd6baca5e1a",
|
||||
"Step 085"
|
||||
],
|
||||
[
|
||||
"5d79253742f3313d55db981f",
|
||||
"Step 086"
|
||||
],
|
||||
[
|
||||
"5d7925379e0180a438ce7f95",
|
||||
"Step 087"
|
||||
],
|
||||
[
|
||||
"5d792537c80984dfa5501b96",
|
||||
"Step 088"
|
||||
],
|
||||
[
|
||||
"5d7925377b54d8a76efb5657",
|
||||
"Step 089"
|
||||
],
|
||||
[
|
||||
"5d7925371398513549bb6395",
|
||||
"Step 090"
|
||||
],
|
||||
[
|
||||
"5d792537ea3eaf302bf2d359",
|
||||
"Step 91"
|
||||
],
|
||||
[
|
||||
"5d792537533b1c7843bfd029",
|
||||
"Step 092"
|
||||
],
|
||||
[
|
||||
"5d792537dc0fe84345d4f19e",
|
||||
"Step 093"
|
||||
],
|
||||
[
|
||||
"5d792537b6cadae0f4b0cda1",
|
||||
"Step 094"
|
||||
],
|
||||
[
|
||||
"5d79253770083fb730c93a93",
|
||||
"Step 095"
|
||||
],
|
||||
[
|
||||
"5d792537fef76b226b63b93b",
|
||||
"Step 096"
|
||||
],
|
||||
[
|
||||
"5d79253760fca25ccbbd8990",
|
||||
"Step 097"
|
||||
],
|
||||
[
|
||||
"5d7925374321824cba309875",
|
||||
"Step 098"
|
||||
],
|
||||
[
|
||||
"5d7925381e8565a5c50ba7f1",
|
||||
"Step 099"
|
||||
],
|
||||
[
|
||||
"5d7925383f1b77db7f1ff59e",
|
||||
"Step 100"
|
||||
],
|
||||
[
|
||||
"5d792538de9fa3f298bcd5f6",
|
||||
"Step 101"
|
||||
],
|
||||
[
|
||||
"5d7925385b74f69642e1fea5",
|
||||
"Step 102"
|
||||
],
|
||||
[
|
||||
"5d7925380ea76d55b2c97d7b",
|
||||
"Step 103"
|
||||
],
|
||||
[
|
||||
"5d792538be4fe331f1a6c008",
|
||||
"Step 104"
|
||||
],
|
||||
[
|
||||
"5d792538d169f33142175b95",
|
||||
"Step 105"
|
||||
],
|
||||
[
|
||||
"5d792538e48b5a2c6e5bbe12",
|
||||
"Step 106"
|
||||
],
|
||||
[
|
||||
"5d7925387f3e9da5ec856dbe",
|
||||
"Step 107"
|
||||
],
|
||||
[
|
||||
"5d79253824ae9b4a6e6f3108",
|
||||
"Step 108"
|
||||
],
|
||||
[
|
||||
"5d7925383f122a279f4c54ad",
|
||||
"Step 109"
|
||||
],
|
||||
[
|
||||
"5d7925387b682e962f209269",
|
||||
"Step 110"
|
||||
],
|
||||
[
|
||||
"5d792538de774217b173288e",
|
||||
"Step 111"
|
||||
],
|
||||
[
|
||||
"5d79253891d93585323d1f3c",
|
||||
"Step 112"
|
||||
],
|
||||
[
|
||||
"5d7925384e34e944ecb4612d",
|
||||
"Step 113"
|
||||
],
|
||||
[
|
||||
"5d792538631844ad0bdfb4c3",
|
||||
"Step 114"
|
||||
],
|
||||
[
|
||||
"5d792538e2a8d20cc580d481",
|
||||
"Step 115"
|
||||
],
|
||||
[
|
||||
"5d792538f5004390d6678554",
|
||||
"Step 116"
|
||||
],
|
||||
[
|
||||
"5d792539dd4fd4c96fd85f7e",
|
||||
"Step 117"
|
||||
],
|
||||
[
|
||||
"5d79253949802f8587c8bbd3",
|
||||
"Step 118"
|
||||
],
|
||||
[
|
||||
"5d7925395888767e9304c082",
|
||||
"Step 119"
|
||||
],
|
||||
[
|
||||
"5d7925393b30099e37a34668",
|
||||
"Step 120"
|
||||
],
|
||||
[
|
||||
"5d7925398157757b23730fdd",
|
||||
"Step 121"
|
||||
],
|
||||
[
|
||||
"5d792539de4b9ac14dd40409",
|
||||
"Step 122"
|
||||
],
|
||||
[
|
||||
"5d792539534f1bf991bb987f",
|
||||
"Step 123"
|
||||
],
|
||||
[
|
||||
"5d7925394089b762f93ffa52",
|
||||
"Step 124"
|
||||
],
|
||||
[
|
||||
"5d792539ec758d45a6900173",
|
||||
"Step 125"
|
||||
],
|
||||
[
|
||||
"5d7925398d525f61a9ff3a79",
|
||||
"Step 126"
|
||||
],
|
||||
[
|
||||
"5d792539a222f385c5c17d2b",
|
||||
"Step 127"
|
||||
],
|
||||
[
|
||||
"5d7925398a7184b41b12a0e0",
|
||||
"Step 128"
|
||||
],
|
||||
[
|
||||
"5d7925399afb905c34730a75",
|
||||
"Step 129"
|
||||
],
|
||||
[
|
||||
"5d792539728d1aa7788e2c9b",
|
||||
"Step 130"
|
||||
],
|
||||
[
|
||||
"5d79253939434a2724c0ec41",
|
||||
"Step 131"
|
||||
],
|
||||
[
|
||||
"5d792539b9e1d3c54d8fe94a",
|
||||
"Step 132"
|
||||
],
|
||||
[
|
||||
"5d792539b2e0bd8f9e8213e4",
|
||||
"Step 133"
|
||||
],
|
||||
[
|
||||
"5d792539239148965a1a59a5",
|
||||
"Step 134"
|
||||
],
|
||||
[
|
||||
"5d792539e1446045d0df6d28",
|
||||
"Step 135"
|
||||
],
|
||||
[
|
||||
"5d79253a2febbb77098730b9",
|
||||
"Step 136"
|
||||
],
|
||||
[
|
||||
"5d79253a98bd9fdf7ce68d0a",
|
||||
"Step 137"
|
||||
],
|
||||
[
|
||||
"5d79253a1e9abf29de64c177",
|
||||
"Step 138"
|
||||
],
|
||||
[
|
||||
"5d79253a8b29d78984369e4b",
|
||||
"Step 139"
|
||||
],
|
||||
[
|
||||
"5d79253ad297a31cbe073718",
|
||||
"Step 140"
|
||||
],
|
||||
[
|
||||
"5d79253a0f968095adfa40f6",
|
||||
"Step 141"
|
||||
]
|
||||
],
|
||||
"helpRoom": "HelpJavaScript",
|
||||
"fileName": "02-javascript-algorithms-and-data-structures/javascript-spreadsheet.json"
|
||||
}
|
@ -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>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user