| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | --- | 
					
						
							|  |  |  | id: 5d792539534f1bf991bb987f | 
					
						
							| 
									
										
										
										
											2019-12-09 19:37:02 +09:00
										 |  |  | title: Part 123 | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | challengeType: 0 | 
					
						
							| 
									
										
										
										
											2021-01-13 03:31:00 +01:00
										 |  |  | dashedName: part-123 | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | --- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | # --description--
 | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | 
 | 
					
						
							|  |  |  | ES6 introduced a shorthand object literal syntax: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const a = 10; | 
					
						
							|  |  |  | const myObject = { a }; | 
					
						
							|  |  |  | console.log(myObject); // { a: 10 } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | First, move `sum` outside of `spreadsheetFunctions`. `sum` should be a function expression similar to `isEven`. | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | # --hints--
 | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | See description above for instructions. | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | ```js | 
					
						
							|  |  |  | assert(sum([1, 2, 3]) === 6); | 
					
						
							|  |  |  | ``` | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | # --seed--
 | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | ## --before-user-code--
 | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | ```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> | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | ## --after-user-code--
 | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | ```html | 
					
						
							|  |  |  | </body> | 
					
						
							|  |  |  | </html> | 
					
						
							|  |  |  | ``` | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | ## --seed-contents--
 | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```html | 
					
						
							|  |  |  | <script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const infixToFunction = { | 
					
						
							|  |  |  |   "+": (x, y) => x + y, | 
					
						
							|  |  |  |   "-": (x, y) => x - y, | 
					
						
							|  |  |  |   "*": (x, y) => x * y, | 
					
						
							|  |  |  |   "/": (x, y) => x / y | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const infixEval = (str, regex) => | 
					
						
							|  |  |  |   str.replace(regex, (_, arg1, fn, arg2) => | 
					
						
							|  |  |  |     infixToFunction[fn](parseFloat(arg1), parseFloat(arg2)) | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const highPrecedence = str => { | 
					
						
							|  |  |  |   const regex = /([0-9.]+)([*\/])([0-9.]+)/; | 
					
						
							|  |  |  |   const str2 = infixEval(str, regex); | 
					
						
							|  |  |  |   return str === str2 ? str : highPrecedence(str2); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const isEven = num => num % 2 === 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const spreadsheetFunctions = { | 
					
						
							|  |  |  |   "": x => x, | 
					
						
							|  |  |  |   random: ([x, y]) => Math.floor(Math.random() * y + x), | 
					
						
							|  |  |  |   increment: nums => nums.map(x => x + 1), | 
					
						
							|  |  |  |   firsttwo: arr => arr.slice(0, 2), | 
					
						
							|  |  |  |   lasttwo: arr => arr.slice(-2), | 
					
						
							|  |  |  |   even: nums => nums.filter(isEven), | 
					
						
							|  |  |  |   sum: nums => nums.reduce((a, x) => a + x), | 
					
						
							|  |  |  |   has2: arr => arr.includes(2), | 
					
						
							|  |  |  |   nodups: arr => arr.reduce((a, x) => a.includes(x) ? a : a.concat(x), []) | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const applyFn = str => { | 
					
						
							|  |  |  |   const noHigh = highPrecedence(str); | 
					
						
							|  |  |  |   const infix = /([0-9.]+)([+-])([0-9.]+)/; | 
					
						
							|  |  |  |   const str2 = infixEval(noHigh, infix); | 
					
						
							|  |  |  |   const regex = /([a-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, cells) => { | 
					
						
							|  |  |  |   const idToText = id => cells.find(cell => cell.id === id).value; | 
					
						
							|  |  |  |   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 => idToText(c + n); | 
					
						
							|  |  |  |   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 => idToText(match.toUpperCase()) | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  |   const functionExpanded = applyFn(varExpanded); | 
					
						
							|  |  |  |   return functionExpanded === x | 
					
						
							|  |  |  |     ? functionExpanded | 
					
						
							|  |  |  |     : evalFormula(functionExpanded, cells); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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), | 
					
						
							|  |  |  |       Array.from(document.getElementById("container").children) | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | </script> | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | # --solutions--
 | 
					
						
							| 
									
										
										
										
											2019-11-05 02:09:40 -01:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```html | 
					
						
							|  |  |  | <script> | 
					
						
							|  |  |  | const infixToFunction = { | 
					
						
							|  |  |  |   "+": (x, y) => x + y, | 
					
						
							|  |  |  |   "-": (x, y) => x - y, | 
					
						
							|  |  |  |   "*": (x, y) => x * y, | 
					
						
							|  |  |  |   "/": (x, y) => x / y | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const infixEval = (str, regex) => | 
					
						
							|  |  |  |   str.replace(regex, (_, arg1, fn, arg2) => | 
					
						
							|  |  |  |     infixToFunction[fn](parseFloat(arg1), parseFloat(arg2)) | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const highPrecedence = str => { | 
					
						
							|  |  |  |   const regex = /([0-9.]+)([*\/])([0-9.]+)/; | 
					
						
							|  |  |  |   const str2 = infixEval(str, regex); | 
					
						
							|  |  |  |   return str === str2 ? str : highPrecedence(str2); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const isEven = num => num % 2 === 0; | 
					
						
							|  |  |  | const sum = nums => nums.reduce((a, x) => a + x); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const spreadsheetFunctions = { | 
					
						
							|  |  |  |   "": x => x, | 
					
						
							|  |  |  |   random: ([x, y]) => Math.floor(Math.random() * y + x), | 
					
						
							|  |  |  |   increment: nums => nums.map(x => x + 1), | 
					
						
							|  |  |  |   firsttwo: arr => arr.slice(0, 2), | 
					
						
							|  |  |  |   lasttwo: arr => arr.slice(-2), | 
					
						
							|  |  |  |   even: nums => nums.filter(isEven), | 
					
						
							|  |  |  |   has2: arr => arr.includes(2), | 
					
						
							|  |  |  |   nodups: arr => arr.reduce((a, x) => a.includes(x) ? a : a.concat(x), []) | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const applyFn = str => { | 
					
						
							|  |  |  |   const noHigh = highPrecedence(str); | 
					
						
							|  |  |  |   const infix = /([0-9.]+)([+-])([0-9.]+)/; | 
					
						
							|  |  |  |   const str2 = infixEval(noHigh, infix); | 
					
						
							|  |  |  |   const regex = /([a-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, cells) => { | 
					
						
							|  |  |  |   const idToText = id => cells.find(cell => cell.id === id).value; | 
					
						
							|  |  |  |   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 => idToText(c + n); | 
					
						
							|  |  |  |   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 => idToText(match.toUpperCase()) | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  |   const functionExpanded = applyFn(varExpanded); | 
					
						
							|  |  |  |   return functionExpanded === x | 
					
						
							|  |  |  |     ? functionExpanded | 
					
						
							|  |  |  |     : evalFormula(functionExpanded, cells); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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), | 
					
						
							|  |  |  |       Array.from(document.getElementById("container").children) | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | </script> | 
					
						
							|  |  |  | ``` |