From 306e6bb494c351bf5ad3ef69dc40707ad8aceae2 Mon Sep 17 00:00:00 2001 From: Quincy Larson Date: Fri, 15 Dec 2017 15:22:19 -0600 Subject: [PATCH 001/108] feat(seed): Move required projects into new algorithm projects --- ...script-algorithms-and-data-structures.json | 158 +------ .../intermediate-algorithm-scripting.json | 207 ---------- ...gorithms-and-data-structures-projects.json | 389 ++++++++++++++++++ .../coding-interview-algorithm-questions.json | 172 -------- 4 files changed, 400 insertions(+), 526 deletions(-) create mode 100644 seed/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects.json diff --git a/seed/challenges/02-javascript-algorithms-and-data-structures/claim-your-javascript-algorithms-and-data-structures.json b/seed/challenges/02-javascript-algorithms-and-data-structures/claim-your-javascript-algorithms-and-data-structures.json index fc734893dc..d865160fbe 100644 --- a/seed/challenges/02-javascript-algorithms-and-data-structures/claim-your-javascript-algorithms-and-data-structures.json +++ b/seed/challenges/02-javascript-algorithms-and-data-structures/claim-your-javascript-algorithms-and-data-structures.json @@ -4,13 +4,13 @@ "time": "5 minutes", "challenges": [ { - "id": "587d7b7f367417b2b2512b25", + "id": "5a34371eb8853b934b0d9803", "title": "Claim Your JavaScript Algorithms and Data Structures Certificate", "description": [ [ "//i.imgur.com/k8btNUB.jpg", - "An image of our Front End Development Certificate", - "This challenge will give you your verified Front End Development Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", + "An image of our JavaScript Algorithms and Data Structures Certificate", + "This challenge will give you your verified JavaScript Algorithms and Data Structures Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" ], [ @@ -21,14 +21,14 @@ ], [ "//i.imgur.com/UedoV2G.jpg", - "An image of the text \"Front End Development Certificate requirements\"", - "Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. Click the button below to verify this.", + "An image of the text \"JavaScript Algorithms and Data Structures Certificate Requirements\"", + "Let's confirm that you have completed all of our JavaScript Algorithms and Data Structures projects. Click the button below to verify this.", "#" ], [ "//i.imgur.com/Q5Za9U6.jpg", "An image of the word \"Congratulations\"", - "Congratulations! We've added your Front End Development Certificate to your portfolio page. Unless you choose to hide your solutions, this certificate will remain publicly visible and verifiable.", + "Congratulations! We've added your JavaScript Algorithms and Data Structures Certificate to your portfolio page. Unless you choose to hide your solutions, this certificate will remain publicly visible and verifiable.", "" ] ], @@ -49,161 +49,25 @@ } ], "tests": [ - { - "id": "a202eed8fc186c8434cb6d61", - "title": "Reverse a String" - }, - { - "id": "a302f7aae1aa3152a5b413bc", - "title": "Factorialize a Number" - }, { "id": "aaa48de84e1ecc7c742e1124", - "title": "Check for Palindromes" - }, - { - "id": "a26cbbe9ad8655a977e1ceb5", - "title": "Find the Longest Word in a String" - }, - { - "id": "ab6137d4e35944e21037b769", - "title": "Title Case a Sentence" - }, - { - "id": "a789b3483989747d63b0e427", - "title": "Return Largest Numbers in Arrays" - }, - { - "id": "acda2fb1324d9b0fa741e6b5", - "title": "Confirm the Ending" - }, - { - "id": "afcc8d540bea9ea2669306b6", - "title": "Repeat a string repeat a string" - }, - { - "id": "ac6993d51946422351508a41", - "title": "Truncate a string" - }, - { - "id": "a9bd25c716030ec90084d8a1", - "title": "Chunky Monkey" - }, - { - "id": "579e2a2c335b9d72dd32e05c", - "title": "Splice and Slice" - }, - { - "id": "af2170cad53daa0770fabdea", - "title": "Mutations" - }, - { - "id": "adf08ec01beb4f99fc7a68f2", - "title": "Falsy Bouncer" - }, - { - "id": "a39963a4c10bc8b4d4f06d7e", - "title": "Seek and Destroy" - }, - { - "id": "a24c1a4622e3c05097f71d67", - "title": "Where do I belong" - }, - { - "id": "a3566b1109230028080c9345", - "title": "Sum All Numbers in a Range" - }, - { - "id": "a5de63ebea8dbee56860f4f2", - "title": "Diff Two Arrays" + "title": "Palindrome Checker" }, { "id": "a7f4d8f2483413a6ce226cac", "title": "Roman Numeral Converter" }, - { - "id": "a8e512fbe388ac2f9198f0fa", - "title": "Wherefore art thou" - }, - { - "id": "a0b5010f579e69b815e7c5d6", - "title": "Search and Replace" - }, - { - "id": "aa7697ea2477d1316795783b", - "title": "Pig Latin" - }, - { - "id": "afd15382cdfb22c9efe8b7de", - "title": "DNA Pairing" - }, - { - "id": "af7588ade1100bde429baf20", - "title": "Missing letters" - }, - { - "id": "a77dbc43c33f39daa4429b4f", - "title": "Boo who" - }, - { - "id": "a105e963526e7de52b219be9", - "title": "Sorted Union" - }, - { - "id": "a6b0bb188d873cb2c8729495", - "title": "Convert HTML Entities" - }, - { - "id": "a103376db3ba46b2d50db289", - "title": "Spinal Tap Case" - }, - { - "id": "a5229172f011153519423690", - "title": "Sum All Odd Fibonacci Numbers" - }, - { - "id": "a3bfc1673c0526e06d3ac698", - "title": "Sum All Primes" - }, - { - "id": "ae9defd7acaf69703ab432ea", - "title": "Smallest Common Multiple" - }, - { - "id": "a6e40f1041b06c996f7b2406", - "title": "Finders Keepers" - }, - { - "id": "a5deed1811a43193f9f1c841", - "title": "Drop it" - }, - { - "id": "ab306dbdcc907c7ddfc30830", - "title": "Steamroller" - }, - { - "id": "a8d97bd4c764e91f9d2bda01", - "title": "Binary Agents" - }, - { - "id": "a10d2431ad0c6a099a4b8b52", - "title": "Everything Be True" - }, - { - "id": "a97fd23d9b809dac9921074f", - "title": "Arguments Optional" - }, { "id": "56533eb9ac21ba0edf2244e2", "title": "Caesars Cipher" }, { - "id": "a2f1d72d9b908d0bd72bb9f6", - "title": "Make a Person" + "id": "aff0395860f5d3034dc0bfc9", + "title": "Telephone Number Validator" }, { - "id": "af4afb223120f7348cdfc9fd", - "title": "Map the Debris" + "id": "aa2e6f85cab2ab736c9a9b24", + "title": "Cash Register" } ], "type": "Waypoint", diff --git a/seed/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting.json b/seed/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting.json index bd0416ea39..5898533b39 100644 --- a/seed/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting.json +++ b/seed/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting.json @@ -125,77 +125,6 @@ } } }, - { - "id": "aaa48de84e1ecc7c742e1124", - "title": "Check for Palindromes", - "description": [ - "Return true if the given string is a palindrome. Otherwise, return false.", - "A palindrome is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation, case, and spacing.", - "Note
You'll need to remove all non-alphanumeric characters (punctuation, spaces and symbols) and turn everything into the same case (lower or upper case) in order to check for palindromes.", - "We'll pass strings with varying formats, such as \"racecar\", \"RaceCar\", and \"race CAR\" among others.", - "We'll also pass strings with special symbols, such as \"2A3*3a2\", \"2A3 3a2\", and \"2_A3*3#A2\".", - "Remember to use Read-Search-Ask if you get stuck. Write your own code." - ], - "challengeSeed": [ - "function palindrome(str) {", - " // Good luck!", - " return true;", - "}", - "", - "", - "", - "palindrome(\"eye\");" - ], - "tests": [ - "assert(typeof palindrome(\"eye\") === \"boolean\", 'message: palindrome(\"eye\") should return a boolean.');", - "assert(palindrome(\"eye\") === true, 'message: palindrome(\"eye\") should return true.');", - "assert(palindrome(\"_eye\") === true, 'message: palindrome(\"_eye\") should return true.');", - "assert(palindrome(\"race car\") === true, 'message: palindrome(\"race car\") should return true.');", - "assert(palindrome(\"not a palindrome\") === false, 'message: palindrome(\"not a palindrome\") should return false.');", - "assert(palindrome(\"A man, a plan, a canal. Panama\") === true, 'message: palindrome(\"A man, a plan, a canal. Panama\") should return true.');", - "assert(palindrome(\"never odd or even\") === true, 'message: palindrome(\"never odd or even\") should return true.');", - "assert(palindrome(\"nope\") === false, 'message: palindrome(\"nope\") should return false.');", - "assert(palindrome(\"almostomla\") === false, 'message: palindrome(\"almostomla\") should return false.');", - "assert(palindrome(\"My age is 0, 0 si ega ym.\") === true, 'message: palindrome(\"My age is 0, 0 si ega ym.\") should return true.');", - "assert(palindrome(\"1 eye for of 1 eye.\") === false, 'message: palindrome(\"1 eye for of 1 eye.\") should return false.');", - "assert(palindrome(\"0_0 (: /-\\ :) 0-0\") === true, 'message: palindrome(\"0_0 (: /-\\ :) 0-0\") should return true.');", - "assert(palindrome(\"five|\\_/|four\") === false, 'message: palindrome(\"five|\\_/|four\") should return false.');" - ], - "type": "bonfire", - "isRequired": true, - "solutions": [ - "function palindrome(str) {\n var string = str.toLowerCase().split(/[^A-Za-z0-9]/gi).join('');\n var aux = string.split('');\n if (aux.join('') === aux.reverse().join('')){\n return true;\n }\n\n return false;\n}" - ], - "MDNlinks": [ - "String.prototype.replace()", - "String.prototype.toLowerCase()" - ], - "challengeType": 5, - "translations": { - "es": { - "title": "Verifica si es palíndromo", - "description": [ - "Crea una función que devuelva true si una cadena de texto dada es un palíndromo, y que devuelva false en caso contrario", - "Un palíndromo es una palabra u oración que se escribe de la misma forma en ambos sentidos, sin tomar en cuenta signos de puntuación, espacios y sin distinguir entre mayúsculas y minúsculas.", - "Tendrás que quitar los caracteres no alfanuméricos (signos de puntuación, espacioes y símbolos) y transformar las letras a minúsculas para poder verificar si el texto es palíndromo.", - "Te proveeremos textos en varios formatos, como \"racecar\", \"RaceCar\", and \"race CAR\" entre otros.", - "También vamos a pasar cadenas con símbolos especiales, tales como \"2A3*3a2\", \"2A3 3a2\", y \"2_A3*3#A2\".", - "Recuerda utilizar Leer-Buscar-Preguntar si te sientes atascado. Intenta programar en pareja. Escribe tu propio código." - ] - }, - "pt-br": { - "title": "Procure por Palíndromos", - "description": [ - "Retorne true se o texto fornecida é um palíndromo. Caso contrário, retorne false.", - "Um palíndromo é uma palavra ou sentença que é soletrada da mesma maneira tanto para a frente quanto para trás, ignorando pontuação, maiúsculas e minúsculas, e espaçamento.", - "Nota
Você precisará remover todos caracteres não alfanuméricos (pontuação, espaços e símbolos) e transformar todas as letras em maiúsculas ou minúsculas para procurar por palíndromos.", - "Nós vamos passar textos de vários formatos, tais como \"racecar\", \"RaceCar\" e \"race CAR\" entre outras.", - "Nós também vamos passar textos com símbolos especiais, tais como \"2A3*3a2\", \"2A3 3a2\" e \"2_A3*3#A2\".", - "Lembre-se de usar Ler-Pesquisar-Perguntar se você ficar travado. Escreva seu próprio código." - ] - } - } - }, { "id": "a39963a4c10bc8b4d4f06d7e", "title": "Seek and Destroy", @@ -357,142 +286,6 @@ } } }, - { - "id": "a7f4d8f2483413a6ce226cac", - "title": "Roman Numeral Converter", - "description": [ - "Convert the given number into a roman numeral.", - "All roman numerals answers should be provided in upper-case.", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." - ], - "challengeSeed": [ - "function convertToRoman(num) {", - " return num;", - "}", - "", - "convertToRoman(36);" - ], - "solutions": [ - "function convertToRoman(num) {\n var ref = [['M', 1000], ['CM', 900], ['D', 500], ['CD', 400], ['C', 100], ['XC', 90], ['L', 50], ['XL', 40], ['X', 10], ['IX', 9], ['V', 5], ['IV', 4], ['I', 1]];\n var res = [];\n ref.forEach(function(p) {\n while (num >= p[1]) {\n res.push(p[0]);\n num -= p[1];\n }\n });\n return res.join('');\n}" - ], - "tests": [ - "assert.deepEqual(convertToRoman(2), \"II\", 'message: convertToRoman(2) should return \"II\".');", - "assert.deepEqual(convertToRoman(3), \"III\", 'message: convertToRoman(3) should return \"III\".');", - "assert.deepEqual(convertToRoman(4), \"IV\", 'message: convertToRoman(4) should return \"IV\".');", - "assert.deepEqual(convertToRoman(5), \"V\", 'message: convertToRoman(5) should return \"V\".');", - "assert.deepEqual(convertToRoman(9), \"IX\", 'message: convertToRoman(9) should return \"IX\".');", - "assert.deepEqual(convertToRoman(12), \"XII\", 'message: convertToRoman(12) should return \"XII\".');", - "assert.deepEqual(convertToRoman(16), \"XVI\", 'message: convertToRoman(16) should return \"XVI\".');", - "assert.deepEqual(convertToRoman(29), \"XXIX\", 'message: convertToRoman(29) should return \"XXIX\".');", - "assert.deepEqual(convertToRoman(44), \"XLIV\", 'message: convertToRoman(44) should return \"XLIV\".');", - "assert.deepEqual(convertToRoman(45), \"XLV\", 'message: convertToRoman(45) should return \"XLV\"');", - "assert.deepEqual(convertToRoman(68), \"LXVIII\", 'message: convertToRoman(68) should return \"LXVIII\"');", - "assert.deepEqual(convertToRoman(83), \"LXXXIII\", 'message: convertToRoman(83) should return \"LXXXIII\"');", - "assert.deepEqual(convertToRoman(97), \"XCVII\", 'message: convertToRoman(97) should return \"XCVII\"');", - "assert.deepEqual(convertToRoman(99), \"XCIX\", 'message: convertToRoman(99) should return \"XCIX\"');", - "assert.deepEqual(convertToRoman(400), \"CD\", 'message: convertToRoman(400) should return \"CD\"');", - "assert.deepEqual(convertToRoman(500), \"D\", 'message: convertToRoman(500) should return \"D\"');", - "assert.deepEqual(convertToRoman(501), \"DI\", 'message: convertToRoman(501) should return \"DI\"');", - "assert.deepEqual(convertToRoman(649), \"DCXLIX\", 'message: convertToRoman(649) should return \"DCXLIX\"');", - "assert.deepEqual(convertToRoman(798), \"DCCXCVIII\", 'message: convertToRoman(798) should return \"DCCXCVIII\"');", - "assert.deepEqual(convertToRoman(891), \"DCCCXCI\", 'message: convertToRoman(891) should return \"DCCCXCI\"');", - "assert.deepEqual(convertToRoman(1000), \"M\", 'message: convertToRoman(1000) should return \"M\"');", - "assert.deepEqual(convertToRoman(1004), \"MIV\", 'message: convertToRoman(1004) should return \"MIV\"');", - "assert.deepEqual(convertToRoman(1006), \"MVI\", 'message: convertToRoman(1006) should return \"MVI\"');", - "assert.deepEqual(convertToRoman(1023), \"MXXIII\", 'message: convertToRoman(1023) should return \"MXXIII\"');", - "assert.deepEqual(convertToRoman(2014), \"MMXIV\", 'message: convertToRoman(2014) should return \"MMXIV\"');", - "assert.deepEqual(convertToRoman(3999), \"MMMCMXCIX\", 'message: convertToRoman(3999) should return \"MMMCMXCIX\"');" - ], - "type": "bonfire", - "MDNlinks": [ - "Roman Numerals", - "Array.prototype.splice()", - "Array.prototype.indexOf()", - "Array.prototype.join()" - ], - "isRequired": true, - "challengeType": 5, - "translations": { - "es": { - "title": "Convertior de números romanos", - "description": [ - "Convierte el número dado en numeral romano.", - "Todos los numerales romanos en las respuestas deben estar en mayúsculas.", - "Recuerda utilizar Leer-Buscar-Preguntar si te sientes atascado. Intenta programar en pareja. Escribe tu propio código." - ] - }, - "fr": { - "title": "Convertir en chiffres romains", - "description": [ - "Convertis le nombre donné en chiffres romains.", - "Tous les chiffres romains doivent être en lettres capitales.", - "N'oublie pas d'utiliser Lire-Chercher-Demander si tu es bloqué. Essaye de trouver un partenaire. Écris ton propre code." - ] - } - } - }, - { - "id": "56533eb9ac21ba0edf2244e2", - "title": "Caesars Cipher", - "description": [ - "One of the simplest and most widely known ciphers is a Caesar cipher, also known as a shift cipher. In a shift cipher the meanings of the letters are shifted by some set amount.", - "A common modern use is the ROT13 cipher, where the values of the letters are shifted by 13 places. Thus 'A' ↔ 'N', 'B' ↔ 'O' and so on.", - "Write a function which takes a ROT13 encoded string as input and returns a decoded string.", - "All letters will be uppercase. Do not transform any non-alphabetic character (i.e. spaces, punctuation), but do pass them on.", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." - ], - "challengeSeed": [ - "function rot13(str) { // LBH QVQ VG!", - " ", - " return str;", - "}", - "", - "// Change the inputs below to test", - "rot13(\"SERR PBQR PNZC\");" - ], - "tail": [ - "" - ], - "solutions": [ - "var lookup = {\n 'A': 'N','B': 'O','C': 'P','D': 'Q',\n 'E': 'R','F': 'S','G': 'T','H': 'U',\n 'I': 'V','J': 'W','K': 'X','L': 'Y',\n 'M': 'Z','N': 'A','O': 'B','P': 'C',\n 'Q': 'D','R': 'E','S': 'F','T': 'G',\n 'U': 'H','V': 'I','W': 'J','X': 'K',\n 'Y': 'L','Z': 'M' \n};\n\nfunction rot13(encodedStr) {\n var codeArr = encodedStr.split(\"\"); // String to Array\n var decodedArr = []; // Your Result goes here\n // Only change code below this line\n \n decodedArr = codeArr.map(function(letter) {\n if(lookup.hasOwnProperty(letter)) {\n letter = lookup[letter];\n }\n return letter;\n });\n\n // Only change code above this line\n return decodedArr.join(\"\"); // Array to String\n}" - ], - "tests": [ - "assert(rot13(\"SERR PBQR PNZC\") === \"FREE CODE CAMP\", 'message: rot13(\"SERR PBQR PNZC\") should decode to FREE CODE CAMP');", - "assert(rot13(\"SERR CVMMN!\") === \"FREE PIZZA!\", 'message: rot13(\"SERR CVMMN!\") should decode to FREE PIZZA!');", - "assert(rot13(\"SERR YBIR?\") === \"FREE LOVE?\", 'message: rot13(\"SERR YBIR?\") should decode to FREE LOVE?');", - "assert(rot13(\"GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.\") === \"THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.\", 'message: rot13(\"GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.\") should decode to THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.');" - ], - "type": "bonfire", - "MDNlinks": [ - "String.prototype.charCodeAt()", - "String.fromCharCode()" - ], - "challengeType": 5, - "isRequired": true, - "releasedOn": "January 1, 2016", - "translations": { - "es": { - "title": "Cifrado César", - "description": [ - "Uno de los cifrados más simples y ampliamente conocidos es el cifrado César, también llamado cifrado por desplazamiento. En un cifrado por desplazamiento los significados de las letras se desplazan por una cierta cantidad.", - "Un uso moderno común es el cifrado ROT13 , donde los valores de las letras se desplazan 13 espacios. De esta forma 'A' ↔ 'N', 'B' ↔ 'O' y así.", - "Crea una función que tome una cadena de texto cifrada en ROT13 como argumento y que devuelva la cadena de texto decodificada.", - "Todas las letras que se te pasen van a estar en mayúsculas. No transformes ningún caracter no-alfabético (por ejemplo: espacios, puntuación). Simplemente pásalos intactos.", - "Recuerda utilizar Leer-Buscar-Preguntar si te sientes atascado. Intenta programar en pareja. Escribe tu propio código." - ] - }, - "pt-br": { - "title": "Cifra de César", - "description": [ - "Uma das mais simples e mais conhecidas cifras é a cifra de César, também conhecida como cifra de troca. Em uma cifra de troca os significados das letras são deslocados por um determinado valor.", - "Um uso moderno comum é a cifra ROT13, aonde os valores das letras são deslocados por 13 lugares. Logo 'A' ↔ 'N', 'B' ↔ 'O' e assim por diante.", - "Escreva uma função que recebe um texto criptografado com ROT13 como entrada e retorna o texto desencriptado.", - "Todas as letras serão maiúsculas. Não transforme nenhum caracter não alfanuméricos (como espaços, pontuação), mas passe-os adiante.", - "Lembre-se de usar Ler-Pesquisar-Perguntar se você ficar travado. Escreva seu próprio código." - ] - } - } - }, { "id": "aa7697ea2477d1316795783b", "title": "Pig Latin", diff --git a/seed/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects.json b/seed/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects.json new file mode 100644 index 0000000000..328607da68 --- /dev/null +++ b/seed/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects.json @@ -0,0 +1,389 @@ +{ + "name": "JavaScript Algorithms and Data Structures Projects", + "order": 8, + "time": "50 hours", + "helpRoom": "HelpJavaScript", + "challenges": [ + { + "id": "aaa48de84e1ecc7c742e1124", + "title": "Palindrome Checker", + "description": [ + "Return true if the given string is a palindrome. Otherwise, return false.", + "A palindrome is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation, case, and spacing.", + "Note
You'll need to remove all non-alphanumeric characters (punctuation, spaces and symbols) and turn everything into the same case (lower or upper case) in order to check for palindromes.", + "We'll pass strings with varying formats, such as \"racecar\", \"RaceCar\", and \"race CAR\" among others.", + "We'll also pass strings with special symbols, such as \"2A3*3a2\", \"2A3 3a2\", and \"2_A3*3#A2\".", + "Remember to use Read-Search-Ask if you get stuck. Write your own code." + ], + "challengeSeed": [ + "function palindrome(str) {", + " // Good luck!", + " return true;", + "}", + "", + "", + "", + "palindrome(\"eye\");" + ], + "tests": [ + "assert(typeof palindrome(\"eye\") === \"boolean\", 'message: palindrome(\"eye\") should return a boolean.');", + "assert(palindrome(\"eye\") === true, 'message: palindrome(\"eye\") should return true.');", + "assert(palindrome(\"_eye\") === true, 'message: palindrome(\"_eye\") should return true.');", + "assert(palindrome(\"race car\") === true, 'message: palindrome(\"race car\") should return true.');", + "assert(palindrome(\"not a palindrome\") === false, 'message: palindrome(\"not a palindrome\") should return false.');", + "assert(palindrome(\"A man, a plan, a canal. Panama\") === true, 'message: palindrome(\"A man, a plan, a canal. Panama\") should return true.');", + "assert(palindrome(\"never odd or even\") === true, 'message: palindrome(\"never odd or even\") should return true.');", + "assert(palindrome(\"nope\") === false, 'message: palindrome(\"nope\") should return false.');", + "assert(palindrome(\"almostomla\") === false, 'message: palindrome(\"almostomla\") should return false.');", + "assert(palindrome(\"My age is 0, 0 si ega ym.\") === true, 'message: palindrome(\"My age is 0, 0 si ega ym.\") should return true.');", + "assert(palindrome(\"1 eye for of 1 eye.\") === false, 'message: palindrome(\"1 eye for of 1 eye.\") should return false.');", + "assert(palindrome(\"0_0 (: /-\\ :) 0-0\") === true, 'message: palindrome(\"0_0 (: /-\\ :) 0-0\") should return true.');", + "assert(palindrome(\"five|\\_/|four\") === false, 'message: palindrome(\"five|\\_/|four\") should return false.');" + ], + "type": "bonfire", + "isRequired": true, + "solutions": [ + "function palindrome(str) {\n var string = str.toLowerCase().split(/[^A-Za-z0-9]/gi).join('');\n var aux = string.split('');\n if (aux.join('') === aux.reverse().join('')){\n return true;\n }\n\n return false;\n}" + ], + "MDNlinks": [ + "String.prototype.replace()", + "String.prototype.toLowerCase()" + ], + "challengeType": 5, + "translations": { + "es": { + "title": "Verifica si es palíndromo", + "description": [ + "Crea una función que devuelva true si una cadena de texto dada es un palíndromo, y que devuelva false en caso contrario", + "Un palíndromo es una palabra u oración que se escribe de la misma forma en ambos sentidos, sin tomar en cuenta signos de puntuación, espacios y sin distinguir entre mayúsculas y minúsculas.", + "Tendrás que quitar los caracteres no alfanuméricos (signos de puntuación, espacioes y símbolos) y transformar las letras a minúsculas para poder verificar si el texto es palíndromo.", + "Te proveeremos textos en varios formatos, como \"racecar\", \"RaceCar\", and \"race CAR\" entre otros.", + "También vamos a pasar cadenas con símbolos especiales, tales como \"2A3*3a2\", \"2A3 3a2\", y \"2_A3*3#A2\".", + "Recuerda utilizar Leer-Buscar-Preguntar si te sientes atascado. Intenta programar en pareja. Escribe tu propio código." + ] + }, + "pt-br": { + "title": "Procure por Palíndromos", + "description": [ + "Retorne true se o texto fornecida é um palíndromo. Caso contrário, retorne false.", + "Um palíndromo é uma palavra ou sentença que é soletrada da mesma maneira tanto para a frente quanto para trás, ignorando pontuação, maiúsculas e minúsculas, e espaçamento.", + "Nota
Você precisará remover todos caracteres não alfanuméricos (pontuação, espaços e símbolos) e transformar todas as letras em maiúsculas ou minúsculas para procurar por palíndromos.", + "Nós vamos passar textos de vários formatos, tais como \"racecar\", \"RaceCar\" e \"race CAR\" entre outras.", + "Nós também vamos passar textos com símbolos especiais, tais como \"2A3*3a2\", \"2A3 3a2\" e \"2_A3*3#A2\".", + "Lembre-se de usar Ler-Pesquisar-Perguntar se você ficar travado. Escreva seu próprio código." + ] + } + } + }, + { + "id": "a7f4d8f2483413a6ce226cac", + "title": "Roman Numeral Converter", + "description": [ + "Convert the given number into a roman numeral.", + "All roman numerals answers should be provided in upper-case.", + "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." + ], + "challengeSeed": [ + "function convertToRoman(num) {", + " return num;", + "}", + "", + "convertToRoman(36);" + ], + "solutions": [ + "function convertToRoman(num) {\n var ref = [['M', 1000], ['CM', 900], ['D', 500], ['CD', 400], ['C', 100], ['XC', 90], ['L', 50], ['XL', 40], ['X', 10], ['IX', 9], ['V', 5], ['IV', 4], ['I', 1]];\n var res = [];\n ref.forEach(function(p) {\n while (num >= p[1]) {\n res.push(p[0]);\n num -= p[1];\n }\n });\n return res.join('');\n}" + ], + "tests": [ + "assert.deepEqual(convertToRoman(2), \"II\", 'message: convertToRoman(2) should return \"II\".');", + "assert.deepEqual(convertToRoman(3), \"III\", 'message: convertToRoman(3) should return \"III\".');", + "assert.deepEqual(convertToRoman(4), \"IV\", 'message: convertToRoman(4) should return \"IV\".');", + "assert.deepEqual(convertToRoman(5), \"V\", 'message: convertToRoman(5) should return \"V\".');", + "assert.deepEqual(convertToRoman(9), \"IX\", 'message: convertToRoman(9) should return \"IX\".');", + "assert.deepEqual(convertToRoman(12), \"XII\", 'message: convertToRoman(12) should return \"XII\".');", + "assert.deepEqual(convertToRoman(16), \"XVI\", 'message: convertToRoman(16) should return \"XVI\".');", + "assert.deepEqual(convertToRoman(29), \"XXIX\", 'message: convertToRoman(29) should return \"XXIX\".');", + "assert.deepEqual(convertToRoman(44), \"XLIV\", 'message: convertToRoman(44) should return \"XLIV\".');", + "assert.deepEqual(convertToRoman(45), \"XLV\", 'message: convertToRoman(45) should return \"XLV\"');", + "assert.deepEqual(convertToRoman(68), \"LXVIII\", 'message: convertToRoman(68) should return \"LXVIII\"');", + "assert.deepEqual(convertToRoman(83), \"LXXXIII\", 'message: convertToRoman(83) should return \"LXXXIII\"');", + "assert.deepEqual(convertToRoman(97), \"XCVII\", 'message: convertToRoman(97) should return \"XCVII\"');", + "assert.deepEqual(convertToRoman(99), \"XCIX\", 'message: convertToRoman(99) should return \"XCIX\"');", + "assert.deepEqual(convertToRoman(400), \"CD\", 'message: convertToRoman(400) should return \"CD\"');", + "assert.deepEqual(convertToRoman(500), \"D\", 'message: convertToRoman(500) should return \"D\"');", + "assert.deepEqual(convertToRoman(501), \"DI\", 'message: convertToRoman(501) should return \"DI\"');", + "assert.deepEqual(convertToRoman(649), \"DCXLIX\", 'message: convertToRoman(649) should return \"DCXLIX\"');", + "assert.deepEqual(convertToRoman(798), \"DCCXCVIII\", 'message: convertToRoman(798) should return \"DCCXCVIII\"');", + "assert.deepEqual(convertToRoman(891), \"DCCCXCI\", 'message: convertToRoman(891) should return \"DCCCXCI\"');", + "assert.deepEqual(convertToRoman(1000), \"M\", 'message: convertToRoman(1000) should return \"M\"');", + "assert.deepEqual(convertToRoman(1004), \"MIV\", 'message: convertToRoman(1004) should return \"MIV\"');", + "assert.deepEqual(convertToRoman(1006), \"MVI\", 'message: convertToRoman(1006) should return \"MVI\"');", + "assert.deepEqual(convertToRoman(1023), \"MXXIII\", 'message: convertToRoman(1023) should return \"MXXIII\"');", + "assert.deepEqual(convertToRoman(2014), \"MMXIV\", 'message: convertToRoman(2014) should return \"MMXIV\"');", + "assert.deepEqual(convertToRoman(3999), \"MMMCMXCIX\", 'message: convertToRoman(3999) should return \"MMMCMXCIX\"');" + ], + "type": "bonfire", + "MDNlinks": [ + "Roman Numerals", + "Array.prototype.splice()", + "Array.prototype.indexOf()", + "Array.prototype.join()" + ], + "isRequired": true, + "challengeType": 5, + "translations": { + "es": { + "title": "Convertior de números romanos", + "description": [ + "Convierte el número dado en numeral romano.", + "Todos los numerales romanos en las respuestas deben estar en mayúsculas.", + "Recuerda utilizar Leer-Buscar-Preguntar si te sientes atascado. Intenta programar en pareja. Escribe tu propio código." + ] + }, + "fr": { + "title": "Convertir en chiffres romains", + "description": [ + "Convertis le nombre donné en chiffres romains.", + "Tous les chiffres romains doivent être en lettres capitales.", + "N'oublie pas d'utiliser Lire-Chercher-Demander si tu es bloqué. Essaye de trouver un partenaire. Écris ton propre code." + ] + } + } + }, + { + "id": "56533eb9ac21ba0edf2244e2", + "title": "Caesars Cipher", + "description": [ + "One of the simplest and most widely known ciphers is a Caesar cipher, also known as a shift cipher. In a shift cipher the meanings of the letters are shifted by some set amount.", + "A common modern use is the ROT13 cipher, where the values of the letters are shifted by 13 places. Thus 'A' ↔ 'N', 'B' ↔ 'O' and so on.", + "Write a function which takes a ROT13 encoded string as input and returns a decoded string.", + "All letters will be uppercase. Do not transform any non-alphabetic character (i.e. spaces, punctuation), but do pass them on.", + "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." + ], + "challengeSeed": [ + "function rot13(str) { // LBH QVQ VG!", + " ", + " return str;", + "}", + "", + "// Change the inputs below to test", + "rot13(\"SERR PBQR PNZC\");" + ], + "tail": [ + "" + ], + "solutions": [ + "var lookup = {\n 'A': 'N','B': 'O','C': 'P','D': 'Q',\n 'E': 'R','F': 'S','G': 'T','H': 'U',\n 'I': 'V','J': 'W','K': 'X','L': 'Y',\n 'M': 'Z','N': 'A','O': 'B','P': 'C',\n 'Q': 'D','R': 'E','S': 'F','T': 'G',\n 'U': 'H','V': 'I','W': 'J','X': 'K',\n 'Y': 'L','Z': 'M' \n};\n\nfunction rot13(encodedStr) {\n var codeArr = encodedStr.split(\"\"); // String to Array\n var decodedArr = []; // Your Result goes here\n // Only change code below this line\n \n decodedArr = codeArr.map(function(letter) {\n if(lookup.hasOwnProperty(letter)) {\n letter = lookup[letter];\n }\n return letter;\n });\n\n // Only change code above this line\n return decodedArr.join(\"\"); // Array to String\n}" + ], + "tests": [ + "assert(rot13(\"SERR PBQR PNZC\") === \"FREE CODE CAMP\", 'message: rot13(\"SERR PBQR PNZC\") should decode to FREE CODE CAMP');", + "assert(rot13(\"SERR CVMMN!\") === \"FREE PIZZA!\", 'message: rot13(\"SERR CVMMN!\") should decode to FREE PIZZA!');", + "assert(rot13(\"SERR YBIR?\") === \"FREE LOVE?\", 'message: rot13(\"SERR YBIR?\") should decode to FREE LOVE?');", + "assert(rot13(\"GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.\") === \"THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.\", 'message: rot13(\"GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.\") should decode to THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.');" + ], + "type": "bonfire", + "MDNlinks": [ + "String.prototype.charCodeAt()", + "String.fromCharCode()" + ], + "challengeType": 5, + "isRequired": true, + "releasedOn": "January 1, 2016", + "translations": { + "es": { + "title": "Cifrado César", + "description": [ + "Uno de los cifrados más simples y ampliamente conocidos es el cifrado César, también llamado cifrado por desplazamiento. En un cifrado por desplazamiento los significados de las letras se desplazan por una cierta cantidad.", + "Un uso moderno común es el cifrado ROT13 , donde los valores de las letras se desplazan 13 espacios. De esta forma 'A' ↔ 'N', 'B' ↔ 'O' y así.", + "Crea una función que tome una cadena de texto cifrada en ROT13 como argumento y que devuelva la cadena de texto decodificada.", + "Todas las letras que se te pasen van a estar en mayúsculas. No transformes ningún caracter no-alfabético (por ejemplo: espacios, puntuación). Simplemente pásalos intactos.", + "Recuerda utilizar Leer-Buscar-Preguntar si te sientes atascado. Intenta programar en pareja. Escribe tu propio código." + ] + }, + "pt-br": { + "title": "Cifra de César", + "description": [ + "Uma das mais simples e mais conhecidas cifras é a cifra de César, também conhecida como cifra de troca. Em uma cifra de troca os significados das letras são deslocados por um determinado valor.", + "Um uso moderno comum é a cifra ROT13, aonde os valores das letras são deslocados por 13 lugares. Logo 'A' ↔ 'N', 'B' ↔ 'O' e assim por diante.", + "Escreva uma função que recebe um texto criptografado com ROT13 como entrada e retorna o texto desencriptado.", + "Todas as letras serão maiúsculas. Não transforme nenhum caracter não alfanuméricos (como espaços, pontuação), mas passe-os adiante.", + "Lembre-se de usar Ler-Pesquisar-Perguntar se você ficar travado. Escreva seu próprio código." + ] + } + } + }, + { + "id": "aff0395860f5d3034dc0bfc9", + "title": "Telephone Number Validator", + "description": [ + "Return true if the passed string looks like a valid US phone number.", + "The user may fill out the form field any way they choose as long as it has the format of a valid US number. The following are examples of valid formats for US numbers (refer to the tests below for other variants):", + "
555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555
", + "For this challenge you will be presented with a string such as 800-692-7753 or 8oo-six427676;laskdjf. Your job is to validate or reject the US phone number based on any combination of the formats provided above. The area code is required. If the country code is provided, you must confirm that the country code is 1. Return true if the string is a valid US phone number; otherwise return false.", + "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." + ], + "challengeSeed": [ + "function telephoneCheck(str) {", + " // Good luck!", + " return true;", + "}", + "", + "telephoneCheck(\"555-555-5555\");" + ], + "solutions": [ + "var re = /^([+]?1[\\s]?)?((?:[(](?:[2-9]1[02-9]|[2-9][02-8][0-9])[)][\\s]?)|(?:(?:[2-9]1[02-9]|[2-9][02-8][0-9])[\\s.-]?)){1}([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2}[\\s.-]?){1}([0-9]{4}){1}$/;\n\nfunction telephoneCheck(str) {\n return re.test(str);\n}\n\ntelephoneCheck(\"555-555-5555\");" + ], + "tests": [ + "assert(typeof telephoneCheck(\"555-555-5555\") === \"boolean\", 'message: telephoneCheck(\"555-555-5555\") should return a boolean.');", + "assert(telephoneCheck(\"1 555-555-5555\") === true, 'message: telephoneCheck(\"1 555-555-5555\") should return true.');", + "assert(telephoneCheck(\"1 (555) 555-5555\") === true, 'message: telephoneCheck(\"1 (555) 555-5555\") should return true.');", + "assert(telephoneCheck(\"5555555555\") === true, 'message: telephoneCheck(\"5555555555\") should return true.');", + "assert(telephoneCheck(\"555-555-5555\") === true, 'message: telephoneCheck(\"555-555-5555\") should return true.');", + "assert(telephoneCheck(\"(555)555-5555\") === true, 'message: telephoneCheck(\"(555)555-5555\") should return true.');", + "assert(telephoneCheck(\"1(555)555-5555\") === true, 'message: telephoneCheck(\"1(555)555-5555\") should return true.');", + "assert(telephoneCheck(\"555-5555\") === false, 'message: telephoneCheck(\"555-5555\") should return false.');", + "assert(telephoneCheck(\"5555555\") === false, 'message: telephoneCheck(\"5555555\") should return false.');", + "assert(telephoneCheck(\"1 555)555-5555\") === false, 'message: telephoneCheck(\"1 555)555-5555\") should return false.');", + "assert(telephoneCheck(\"1 555 555 5555\") === true, 'message: telephoneCheck(\"1 555 555 5555\") should return true.');", + "assert(telephoneCheck(\"1 456 789 4444\") === true, 'message: telephoneCheck(\"1 456 789 4444\") should return true.');", + "assert(telephoneCheck(\"123**&!!asdf#\") === false, 'message: telephoneCheck(\"123**&!!asdf#\") should return false.');", + "assert(telephoneCheck(\"55555555\") === false, 'message: telephoneCheck(\"55555555\") should return false.');", + "assert(telephoneCheck(\"(6054756961)\") === false, 'message: telephoneCheck(\"(6054756961)\") should return false');", + "assert(telephoneCheck(\"2 (757) 622-7382\") === false, 'message: telephoneCheck(\"2 (757) 622-7382\") should return false.');", + "assert(telephoneCheck(\"0 (757) 622-7382\") === false, 'message: telephoneCheck(\"0 (757) 622-7382\") should return false.');", + "assert(telephoneCheck(\"-1 (757) 622-7382\") === false, 'message: telephoneCheck(\"-1 (757) 622-7382\") should return false');", + "assert(telephoneCheck(\"2 757 622-7382\") === false, 'message: telephoneCheck(\"2 757 622-7382\") should return false.');", + "assert(telephoneCheck(\"10 (757) 622-7382\") === false, 'message: telephoneCheck(\"10 (757) 622-7382\") should return false.');", + "assert(telephoneCheck(\"27576227382\") === false, 'message: telephoneCheck(\"27576227382\") should return false.');", + "assert(telephoneCheck(\"(275)76227382\") === false, 'message: telephoneCheck(\"(275)76227382\") should return false.');", + "assert(telephoneCheck(\"2(757)6227382\") === false, 'message: telephoneCheck(\"2(757)6227382\") should return false.');", + "assert(telephoneCheck(\"2(757)622-7382\") === false, 'message: telephoneCheck(\"2(757)622-7382\") should return false.');", + "assert(telephoneCheck(\"555)-555-5555\") === false, 'message: telephoneCheck(\"555)-555-5555\") should return false.');", + "assert(telephoneCheck(\"(555-555-5555\") === false, 'message: telephoneCheck(\"(555-555-5555\") should return false.');", + "assert(telephoneCheck(\"(555)5(55?)-5555\") === false, 'message: telephoneCheck(\"(555)5(55?)-5555\") should return false.');" + ], + "type": "bonfire", + "MDNlinks": [ + "RegExp" + ], + "challengeType": 5, + "isRequired": true, + "translations": { + "es": { + "title": "Valida Números Telefónicos de los EEUU", + "description": [ + "Haz que la función devuelva true (verdadero) si el texto introducido parece un número válido en los EEUU.", + "El usuario debe llenar el campo del formulario de la forma que desee siempre y cuando tenga el formato de un número válido en los EEUU. Los números mostrados a continuación tienen formatos válidos en los EEUU:", + "
555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555
", + "Para esta prueba se te presentará una cadena de texto como por ejemplo: 800-692-7753 o 8oo-six427676;laskdjf. Tu trabajo consiste en validar o rechazar el número telefónico tomando como base cualquier combinación de los formatos anteriormente presentados. El código de área es requrido. Si el código de país es provisto, debes confirmar que este es 1. La función debe devolver true si la cadena de texto es un número telefónico válido en los EEUU; de lo contrario, debe devolver false.", + "Recuerda utilizar Read-Search-Ask si te sientes atascado. Intenta programar en pareja. Escribe tu propio código." + ] + }, + "it": { + "title": "Verifica i numeri telefonici degli Stati Uniti", + "description": [ + "Ritorna true se la stringa passata come argomento è un numero valido negli Stati Uniti.", + "L'utente può digitare qualunque stringa nel campo di inserimento, purchè sia un numero di telefono valido negli Stati Uniti. Qui sotto alcuni esempi di numeri di telefono validi negli Stati Uniti (fai riferimento ai test per le altre varianti):", + "
555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555
", + "In questo problema ti saranno presentate delle stringe come 800-692-7753 o 8oo-six427676;laskdjf. Il tuo obiettivo è di validare o rigettare il numero di telefono basato su una qualunque combinazione dei formati specificati sopra. Il prefisso di zona è obbligatorio. Se il prefisso nazionale è presente, devi confermare che corrisponda a 1. Ritorna true se la stringa è un numero di telefono valido negli Stati Uniti; altrimenti ritorna false.", + "Ricorda di usare Leggi-Cerca-Chiedi se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te." + ] + }, + "pt-br": { + "title": "Valida números telefônicos dos EUA", + "description": [ + "Retorna true se a string passada é um número telefônico válido nos EUA.", + "O usuário pode preencher o campo de qualquer maneira com tanto que seja um número válido nos EUA. Os seguintes exemplos são formatos válidos para números de telefone nos EUA (baseie-se nos testes abaixo para outras variações):", + "
555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555
", + "Para esse desafio será dado a você uma string como 800-692-7753 ou 8oo-six427676;laskdjf. Seu trabalho é validar ou rejeitar o número de telefone dos EUA baseado nos exmplos de formatos fornecidos acima. O código de área é obrigatório. Se o código do país for fornecido, você deve confirmar que o código do país é 1. Retorne true se a string é um número válido nos EUA; caso contrário retorne false.", + "Lembre-se de usar Ler-Procurar-Perguntar se você ficar preso. Tente programar em par. Escreva seu próprio código." + ] + } + } + }, + { + "id": "aa2e6f85cab2ab736c9a9b24", + "title": "Cash Register", + "description": [ + "Design a cash register drawer function checkCashRegister() that accepts purchase price as the first argument (price), payment as the second argument (cash), and cash-in-drawer (cid) as the third argument.", + "cid is a 2D array listing available currency.", + "Return the string \"Insufficient Funds\" if cash-in-drawer is less than the change due or if you cannot return the exact change. Return the string \"Closed\" if cash-in-drawer is equal to the change due.", + "Otherwise, return change in coin and bills, sorted in highest to lowest order.", + "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code.", + "
Currency UnitAmount
Penny$0.01 (PENNY)
Nickel$0.05 (NICKEL)
Dime$0.1 (DIME)
Quarter$0.25 (QUARTER)
Dollar$1 (DOLLAR)
Five Dollars$5 (FIVE)
Ten Dollars$10 (TEN)
Twenty Dollars$20 (TWENTY)
One-hundred Dollars$100 (ONE HUNDRED)
" + ], + "challengeSeed": [ + "function checkCashRegister(price, cash, cid) {", + " var change;", + " // Here is your change, ma'am.", + " return change;", + "}", + "", + "// Example cash-in-drawer array:", + "// [[\"PENNY\", 1.01],", + "// [\"NICKEL\", 2.05],", + "// [\"DIME\", 3.1],", + "// [\"QUARTER\", 4.25],", + "// [\"ONE\", 90],", + "// [\"FIVE\", 55],", + "// [\"TEN\", 20],", + "// [\"TWENTY\", 60],", + "// [\"ONE HUNDRED\", 100]]", + "", + "checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]);" + ], + "solutions": [ + "var denom = [\n\t{ name: 'ONE HUNDRED', val: 100},\n\t{ name: 'TWENTY', val: 20},\n\t{ name: 'TEN', val: 10},\n\t{ name: 'FIVE', val: 5},\n\t{ name: 'ONE', val: 1},\n\t{ name: 'QUARTER', val: 0.25},\n\t{ name: 'DIME', val: 0.1},\n\t{ name: 'NICKEL', val: 0.05},\n\t{ name: 'PENNY', val: 0.01}\n];\n\nfunction checkCashRegister(price, cash, cid) {\n var change = cash - price;\n var register = cid.reduce(function(acc, curr) {\n acc.total += curr[1];\n acc[curr[0]] = curr[1];\n return acc;\n }, {total: 0});\n if(register.total === change) {\n return 'Closed';\n }\n if(register.total < change) {\n return 'Insufficient Funds';\n }\n var change_arr = denom.reduce(function(acc, curr) {\n var value = 0;\n while(register[curr.name] > 0 && change >= curr.val) {\n change -= curr.val;\n register[curr.name] -= curr.val;\n value += curr.val;\n change = Math.round(change * 100) / 100;\n }\n if(value > 0) {\n acc.push([ curr.name, value ]);\n }\n return acc;\n }, []);\n if(change_arr.length < 1 || change > 0) {\n return \"Insufficient Funds\";\n }\n return change_arr;\n}" + ], + "tests": [ + "assert.isArray(checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]), 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]) should return an array.');", + "assert.isString(checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return a string.');", + "assert.isString(checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return a string.');", + "assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]), [[\"QUARTER\", 0.5]], 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]) should return [[\"QUARTER\", 0.5]].');", + "assert.deepEqual(checkCashRegister(3.26, 100, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]), [[\"TWENTY\", 60], [\"TEN\", 20], [\"FIVE\", 15], [\"ONE\", 1], [\"QUARTER\", 0.5], [\"DIME\", 0.2], [\"PENNY\", 0.04]], 'message: checkCashRegister(3.26, 100, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]) should return [[\"TWENTY\", 60], [\"TEN\", 20], [\"FIVE\", 15], [\"ONE\", 1], [\"QUARTER\", 0.5], [\"DIME\", 0.2], [\"PENNY\", 0.04]].');", + "assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), \"Insufficient Funds\", 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return \"Insufficient Funds\".');", + "assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 1], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), \"Insufficient Funds\", 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 1], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return \"Insufficient Funds\".');", + "assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), \"Closed\", 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return \"Closed\".');" + ], + "type": "bonfire", + "isRequired": true, + "MDNlinks": [ + "Global Object", + "Floating Point Guide" + ], + "challengeType": 5, + "translations": { + "es": { + "title": "Cambio Exacto", + "description": [ + "Crea una función que simule una caja registradora que acepte el precio de compra como el primer argumento, la cantidad recibida como el segundo argumento, y la cantidad de dinero disponible en la registradora (cid) como tercer argumento", + "cid es un arreglo bidimensional que lista la cantidad de dinero disponible", + "La función debe devolver la cadena de texto \"Insufficient Funds\" si el cid es menor al cambio requerido. También debe devolver \"Closed\" si el cid es igual al cambio", + "De no ser el caso, devuelve el cambio en monedas y billetes, ordenados de mayor a menor denominación.", + "Recuerda utilizar Read-Search-Ask si te sientes atascado. Intenta programar en pareja. Escribe tu propio código." + ] + }, + "it": { + "title": "Cambio Esatto", + "description": [ + "Scrivi una funzione che simuli un registro di cassa chiamata checkCashRegister() che accetti il prezzo degli articoli come primo argomento (price), la somma pagata (cash), e la somma disponibile nel registratore di cassa (cid) come terzo argomento.", + "cid è un array a due dimensioni che contiene la quantità di monete e banconote disponibili.", + "Ritorna la stringa \"Insufficient Funds\" se la quantità di denaro disponibile nel registratore di cassa non è abbastanza per restituire il resto. Ritorna la stringa \"Closed\" se il denaro disponibile è esattamente uguale al resto.", + "Altrimenti, ritorna il resto in monete e banconote, ordinate da quelle con valore maggiore a quelle con valore minore.", + "Ricorda di usare Leggi-Cerca-Chiedi se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te." + ] + }, + "pt-br": { + "title": "Troco Exato", + "description": [ + "Crie uma função que simula uma caixa registradora chamada checkCashRegister() e aceita o valor da compra como primeiro argumento (price), pagamento como segundo argumento (cash), e o dinheiro na caixa registradora (cid) como terceiro argumento.", + "cid é uma matriz bidimensional que lista o dinheiro disponível.", + "Retorne a string \"Insufficient Funds\" se o dinheiro na caixa registradora é menor do que o troco ou se não é possível retornar o troco exato. Retorne a string \"Closed\" se o dinheiro na caixa é igual ao troco.", + "Case cotrário, retorne o troco em moedas e notas, ordenado do maior para menor.", + "Lembre-se de usar Ler-Procurar-Perguntar se você ficar preso. Tente programar em par. Escreva seu próprio código.", + "
Currency UnitAmount
Penny$0.01 (PENNY)
Nickel$0.05 (NICKEL)
Dime$0.1 (DIME)
Quarter$0.25 (QUARTER)
Dollar$1 (DOLLAR)
Five Dollars$5 (FIVE)
Ten Dollars$10 (TEN)
Twenty Dollars$20 (TWENTY)
One-hundred Dollars$100 (ONE HUNDRED)
" + ] + } + } + } + ] +} \ No newline at end of file diff --git a/seed/challenges/08-coding-interview-questions-and-take-home-assignments/coding-interview-algorithm-questions.json b/seed/challenges/08-coding-interview-questions-and-take-home-assignments/coding-interview-algorithm-questions.json index 6921ffc8d8..97e627d0a4 100644 --- a/seed/challenges/08-coding-interview-questions-and-take-home-assignments/coding-interview-algorithm-questions.json +++ b/seed/challenges/08-coding-interview-questions-and-take-home-assignments/coding-interview-algorithm-questions.json @@ -4,94 +4,6 @@ "time": "", "helpRoom": "HelpJavaScript", "challenges": [ - { - "id": "aff0395860f5d3034dc0bfc9", - "title": "Validate US Telephone Numbers", - "description": [ - "Return true if the passed string looks like a valid US phone number.", - "The user may fill out the form field any way they choose as long as it has the format of a valid US number. The following are examples of valid formats for US numbers (refer to the tests below for other variants):", - "
555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555
", - "For this challenge you will be presented with a string such as 800-692-7753 or 8oo-six427676;laskdjf. Your job is to validate or reject the US phone number based on any combination of the formats provided above. The area code is required. If the country code is provided, you must confirm that the country code is 1. Return true if the string is a valid US phone number; otherwise return false.", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." - ], - "challengeSeed": [ - "function telephoneCheck(str) {", - " // Good luck!", - " return true;", - "}", - "", - "telephoneCheck(\"555-555-5555\");" - ], - "solutions": [ - "var re = /^([+]?1[\\s]?)?((?:[(](?:[2-9]1[02-9]|[2-9][02-8][0-9])[)][\\s]?)|(?:(?:[2-9]1[02-9]|[2-9][02-8][0-9])[\\s.-]?)){1}([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2}[\\s.-]?){1}([0-9]{4}){1}$/;\n\nfunction telephoneCheck(str) {\n return re.test(str);\n}\n\ntelephoneCheck(\"555-555-5555\");" - ], - "tests": [ - "assert(typeof telephoneCheck(\"555-555-5555\") === \"boolean\", 'message: telephoneCheck(\"555-555-5555\") should return a boolean.');", - "assert(telephoneCheck(\"1 555-555-5555\") === true, 'message: telephoneCheck(\"1 555-555-5555\") should return true.');", - "assert(telephoneCheck(\"1 (555) 555-5555\") === true, 'message: telephoneCheck(\"1 (555) 555-5555\") should return true.');", - "assert(telephoneCheck(\"5555555555\") === true, 'message: telephoneCheck(\"5555555555\") should return true.');", - "assert(telephoneCheck(\"555-555-5555\") === true, 'message: telephoneCheck(\"555-555-5555\") should return true.');", - "assert(telephoneCheck(\"(555)555-5555\") === true, 'message: telephoneCheck(\"(555)555-5555\") should return true.');", - "assert(telephoneCheck(\"1(555)555-5555\") === true, 'message: telephoneCheck(\"1(555)555-5555\") should return true.');", - "assert(telephoneCheck(\"555-5555\") === false, 'message: telephoneCheck(\"555-5555\") should return false.');", - "assert(telephoneCheck(\"5555555\") === false, 'message: telephoneCheck(\"5555555\") should return false.');", - "assert(telephoneCheck(\"1 555)555-5555\") === false, 'message: telephoneCheck(\"1 555)555-5555\") should return false.');", - "assert(telephoneCheck(\"1 555 555 5555\") === true, 'message: telephoneCheck(\"1 555 555 5555\") should return true.');", - "assert(telephoneCheck(\"1 456 789 4444\") === true, 'message: telephoneCheck(\"1 456 789 4444\") should return true.');", - "assert(telephoneCheck(\"123**&!!asdf#\") === false, 'message: telephoneCheck(\"123**&!!asdf#\") should return false.');", - "assert(telephoneCheck(\"55555555\") === false, 'message: telephoneCheck(\"55555555\") should return false.');", - "assert(telephoneCheck(\"(6054756961)\") === false, 'message: telephoneCheck(\"(6054756961)\") should return false');", - "assert(telephoneCheck(\"2 (757) 622-7382\") === false, 'message: telephoneCheck(\"2 (757) 622-7382\") should return false.');", - "assert(telephoneCheck(\"0 (757) 622-7382\") === false, 'message: telephoneCheck(\"0 (757) 622-7382\") should return false.');", - "assert(telephoneCheck(\"-1 (757) 622-7382\") === false, 'message: telephoneCheck(\"-1 (757) 622-7382\") should return false');", - "assert(telephoneCheck(\"2 757 622-7382\") === false, 'message: telephoneCheck(\"2 757 622-7382\") should return false.');", - "assert(telephoneCheck(\"10 (757) 622-7382\") === false, 'message: telephoneCheck(\"10 (757) 622-7382\") should return false.');", - "assert(telephoneCheck(\"27576227382\") === false, 'message: telephoneCheck(\"27576227382\") should return false.');", - "assert(telephoneCheck(\"(275)76227382\") === false, 'message: telephoneCheck(\"(275)76227382\") should return false.');", - "assert(telephoneCheck(\"2(757)6227382\") === false, 'message: telephoneCheck(\"2(757)6227382\") should return false.');", - "assert(telephoneCheck(\"2(757)622-7382\") === false, 'message: telephoneCheck(\"2(757)622-7382\") should return false.');", - "assert(telephoneCheck(\"555)-555-5555\") === false, 'message: telephoneCheck(\"555)-555-5555\") should return false.');", - "assert(telephoneCheck(\"(555-555-5555\") === false, 'message: telephoneCheck(\"(555-555-5555\") should return false.');", - "assert(telephoneCheck(\"(555)5(55?)-5555\") === false, 'message: telephoneCheck(\"(555)5(55?)-5555\") should return false.');" - ], - "type": "bonfire", - "MDNlinks": [ - "RegExp" - ], - "challengeType": 5, - "translations": { - "es": { - "title": "Valida Números Telefónicos de los EEUU", - "description": [ - "Haz que la función devuelva true (verdadero) si el texto introducido parece un número válido en los EEUU.", - "El usuario debe llenar el campo del formulario de la forma que desee siempre y cuando tenga el formato de un número válido en los EEUU. Los números mostrados a continuación tienen formatos válidos en los EEUU:", - "
555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555
", - "Para esta prueba se te presentará una cadena de texto como por ejemplo: 800-692-7753 o 8oo-six427676;laskdjf. Tu trabajo consiste en validar o rechazar el número telefónico tomando como base cualquier combinación de los formatos anteriormente presentados. El código de área es requrido. Si el código de país es provisto, debes confirmar que este es 1. La función debe devolver true si la cadena de texto es un número telefónico válido en los EEUU; de lo contrario, debe devolver false.", - "Recuerda utilizar Read-Search-Ask si te sientes atascado. Intenta programar en pareja. Escribe tu propio código." - ] - }, - "it": { - "title": "Verifica i numeri telefonici degli Stati Uniti", - "description": [ - "Ritorna true se la stringa passata come argomento è un numero valido negli Stati Uniti.", - "L'utente può digitare qualunque stringa nel campo di inserimento, purchè sia un numero di telefono valido negli Stati Uniti. Qui sotto alcuni esempi di numeri di telefono validi negli Stati Uniti (fai riferimento ai test per le altre varianti):", - "
555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555
", - "In questo problema ti saranno presentate delle stringe come 800-692-7753 o 8oo-six427676;laskdjf. Il tuo obiettivo è di validare o rigettare il numero di telefono basato su una qualunque combinazione dei formati specificati sopra. Il prefisso di zona è obbligatorio. Se il prefisso nazionale è presente, devi confermare che corrisponda a 1. Ritorna true se la stringa è un numero di telefono valido negli Stati Uniti; altrimenti ritorna false.", - "Ricorda di usare Leggi-Cerca-Chiedi se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te." - ] - }, - "pt-br": { - "title": "Valida números telefônicos dos EUA", - "description": [ - "Retorna true se a string passada é um número telefônico válido nos EUA.", - "O usuário pode preencher o campo de qualquer maneira com tanto que seja um número válido nos EUA. Os seguintes exemplos são formatos válidos para números de telefone nos EUA (baseie-se nos testes abaixo para outras variações):", - "
555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555
", - "Para esse desafio será dado a você uma string como 800-692-7753 ou 8oo-six427676;laskdjf. Seu trabalho é validar ou rejeitar o número de telefone dos EUA baseado nos exmplos de formatos fornecidos acima. O código de área é obrigatório. Se o código do país for fornecido, você deve confirmar que o código do país é 1. Retorne true se a string é um número válido nos EUA; caso contrário retorne false.", - "Lembre-se de usar Ler-Procurar-Perguntar se você ficar preso. Tente programar em par. Escreva seu próprio código." - ] - } - } - }, { "id": "a3f503de51cf954ede28891d", "title": "Symmetric Difference", @@ -159,90 +71,6 @@ } } }, - { - "id": "aa2e6f85cab2ab736c9a9b24", - "title": "Exact Change", - "description": [ - "Design a cash register drawer function checkCashRegister() that accepts purchase price as the first argument (price), payment as the second argument (cash), and cash-in-drawer (cid) as the third argument.", - "cid is a 2D array listing available currency.", - "Return the string \"Insufficient Funds\" if cash-in-drawer is less than the change due or if you cannot return the exact change. Return the string \"Closed\" if cash-in-drawer is equal to the change due.", - "Otherwise, return change in coin and bills, sorted in highest to lowest order.", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code.", - "
Currency UnitAmount
Penny$0.01 (PENNY)
Nickel$0.05 (NICKEL)
Dime$0.1 (DIME)
Quarter$0.25 (QUARTER)
Dollar$1 (DOLLAR)
Five Dollars$5 (FIVE)
Ten Dollars$10 (TEN)
Twenty Dollars$20 (TWENTY)
One-hundred Dollars$100 (ONE HUNDRED)
" - ], - "challengeSeed": [ - "function checkCashRegister(price, cash, cid) {", - " var change;", - " // Here is your change, ma'am.", - " return change;", - "}", - "", - "// Example cash-in-drawer array:", - "// [[\"PENNY\", 1.01],", - "// [\"NICKEL\", 2.05],", - "// [\"DIME\", 3.1],", - "// [\"QUARTER\", 4.25],", - "// [\"ONE\", 90],", - "// [\"FIVE\", 55],", - "// [\"TEN\", 20],", - "// [\"TWENTY\", 60],", - "// [\"ONE HUNDRED\", 100]]", - "", - "checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]);" - ], - "solutions": [ - "var denom = [\n\t{ name: 'ONE HUNDRED', val: 100},\n\t{ name: 'TWENTY', val: 20},\n\t{ name: 'TEN', val: 10},\n\t{ name: 'FIVE', val: 5},\n\t{ name: 'ONE', val: 1},\n\t{ name: 'QUARTER', val: 0.25},\n\t{ name: 'DIME', val: 0.1},\n\t{ name: 'NICKEL', val: 0.05},\n\t{ name: 'PENNY', val: 0.01}\n];\n\nfunction checkCashRegister(price, cash, cid) {\n var change = cash - price;\n var register = cid.reduce(function(acc, curr) {\n acc.total += curr[1];\n acc[curr[0]] = curr[1];\n return acc;\n }, {total: 0});\n if(register.total === change) {\n return 'Closed';\n }\n if(register.total < change) {\n return 'Insufficient Funds';\n }\n var change_arr = denom.reduce(function(acc, curr) {\n var value = 0;\n while(register[curr.name] > 0 && change >= curr.val) {\n change -= curr.val;\n register[curr.name] -= curr.val;\n value += curr.val;\n change = Math.round(change * 100) / 100;\n }\n if(value > 0) {\n acc.push([ curr.name, value ]);\n }\n return acc;\n }, []);\n if(change_arr.length < 1 || change > 0) {\n return \"Insufficient Funds\";\n }\n return change_arr;\n}" - ], - "tests": [ - "assert.isArray(checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]), 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]) should return an array.');", - "assert.isString(checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return a string.');", - "assert.isString(checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return a string.');", - "assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]), [[\"QUARTER\", 0.5]], 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]) should return [[\"QUARTER\", 0.5]].');", - "assert.deepEqual(checkCashRegister(3.26, 100, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]), [[\"TWENTY\", 60], [\"TEN\", 20], [\"FIVE\", 15], [\"ONE\", 1], [\"QUARTER\", 0.5], [\"DIME\", 0.2], [\"PENNY\", 0.04]], 'message: checkCashRegister(3.26, 100, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]) should return [[\"TWENTY\", 60], [\"TEN\", 20], [\"FIVE\", 15], [\"ONE\", 1], [\"QUARTER\", 0.5], [\"DIME\", 0.2], [\"PENNY\", 0.04]].');", - "assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), \"Insufficient Funds\", 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return \"Insufficient Funds\".');", - "assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 1], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), \"Insufficient Funds\", 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 1], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return \"Insufficient Funds\".');", - "assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), \"Closed\", 'message: checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return \"Closed\".');" - ], - "type": "bonfire", - "MDNlinks": [ - "Global Object", - "Floating Point Guide" - ], - "challengeType": 5, - "translations": { - "es": { - "title": "Cambio Exacto", - "description": [ - "Crea una función que simule una caja registradora que acepte el precio de compra como el primer argumento, la cantidad recibida como el segundo argumento, y la cantidad de dinero disponible en la registradora (cid) como tercer argumento", - "cid es un arreglo bidimensional que lista la cantidad de dinero disponible", - "La función debe devolver la cadena de texto \"Insufficient Funds\" si el cid es menor al cambio requerido. También debe devolver \"Closed\" si el cid es igual al cambio", - "De no ser el caso, devuelve el cambio en monedas y billetes, ordenados de mayor a menor denominación.", - "Recuerda utilizar Read-Search-Ask si te sientes atascado. Intenta programar en pareja. Escribe tu propio código." - ] - }, - "it": { - "title": "Cambio Esatto", - "description": [ - "Scrivi una funzione che simuli un registro di cassa chiamata checkCashRegister() che accetti il prezzo degli articoli come primo argomento (price), la somma pagata (cash), e la somma disponibile nel registratore di cassa (cid) come terzo argomento.", - "cid è un array a due dimensioni che contiene la quantità di monete e banconote disponibili.", - "Ritorna la stringa \"Insufficient Funds\" se la quantità di denaro disponibile nel registratore di cassa non è abbastanza per restituire il resto. Ritorna la stringa \"Closed\" se il denaro disponibile è esattamente uguale al resto.", - "Altrimenti, ritorna il resto in monete e banconote, ordinate da quelle con valore maggiore a quelle con valore minore.", - "Ricorda di usare Leggi-Cerca-Chiedi se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te." - ] - }, - "pt-br": { - "title": "Troco Exato", - "description": [ - "Crie uma função que simula uma caixa registradora chamada checkCashRegister() e aceita o valor da compra como primeiro argumento (price), pagamento como segundo argumento (cash), e o dinheiro na caixa registradora (cid) como terceiro argumento.", - "cid é uma matriz bidimensional que lista o dinheiro disponível.", - "Retorne a string \"Insufficient Funds\" se o dinheiro na caixa registradora é menor do que o troco ou se não é possível retornar o troco exato. Retorne a string \"Closed\" se o dinheiro na caixa é igual ao troco.", - "Case cotrário, retorne o troco em moedas e notas, ordenado do maior para menor.", - "Lembre-se de usar Ler-Procurar-Perguntar se você ficar preso. Tente programar em par. Escreva seu próprio código.", - "
Currency UnitAmount
Penny$0.01 (PENNY)
Nickel$0.05 (NICKEL)
Dime$0.1 (DIME)
Quarter$0.25 (QUARTER)
Dollar$1 (DOLLAR)
Five Dollars$5 (FIVE)
Ten Dollars$10 (TEN)
Twenty Dollars$20 (TWENTY)
One-hundred Dollars$100 (ONE HUNDRED)
" - ] - } - } - }, { "id": "a56138aff60341a09ed6c480", "title": "Inventory Update", From 5ab0fe21485dac621a7974633499029e146d13c5 Mon Sep 17 00:00:00 2001 From: Mikhail Pontus Date: Wed, 20 Dec 2017 03:03:45 +0300 Subject: [PATCH 002/108] fix(seed): Update Show the Local Weather challenge Pulling changes from commit a29a928f49ef0c0153ea1c8e25a5f40fa46a3190 Preserve glitch weather API from commit ddd852df7b8ecad54ebd141fb5e5e273ca5d4dbf --- .../take-home-interview-projects.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/seed/challenges/08-coding-interview-questions-and-take-home-assignments/take-home-interview-projects.json b/seed/challenges/08-coding-interview-questions-and-take-home-assignments/take-home-interview-projects.json index f4488d60f2..0e698b2275 100644 --- a/seed/challenges/08-coding-interview-questions-and-take-home-assignments/take-home-interview-projects.json +++ b/seed/challenges/08-coding-interview-questions-and-take-home-assignments/take-home-interview-projects.json @@ -9,7 +9,8 @@ "title": "Show the Local Weather", "description": [ "Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/bELRjV.", - "Fulfill the below user stories. Use whichever libraries or APIs you need. Give it your own personal style.", + "Rule #1: Don't look at the example project's code. Figure it out for yourself.", + "Rule #2: Fulfill the below user stories. Use whichever libraries or APIs you need. Give it your own personal style.", "User Story: I can see the weather in my current location.", "User Story: I can see a different icon or background image (e.g. snowy mountain, hot desert) depending on the weather.", "User Story: I can push a button to toggle between Fahrenheit and Celsius.", From a79d5fec19cfa8e34c370a44af9ec19509714568 Mon Sep 17 00:00:00 2001 From: Cassidy Pignatello Date: Wed, 20 Dec 2017 14:00:39 -0500 Subject: [PATCH 003/108] fix: declares index variable in Set challenges --- .../coding-interview-data-structure-questions.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/seed/challenges/08-coding-interview-questions-and-take-home-assignments/coding-interview-data-structure-questions.json b/seed/challenges/08-coding-interview-questions-and-take-home-assignments/coding-interview-data-structure-questions.json index 8a7cf3d2c9..11525bd810 100644 --- a/seed/challenges/08-coding-interview-questions-and-take-home-assignments/coding-interview-data-structure-questions.json +++ b/seed/challenges/08-coding-interview-questions-and-take-home-assignments/coding-interview-data-structure-questions.json @@ -372,7 +372,7 @@ " // this method will remove an element from a set", " this.remove = function(element) {", " if(this.has(element)){", - " index = collection.indexOf(element);", + " var index = collection.indexOf(element);", " collection.splice(index,1);", " return true;", " }", @@ -424,7 +424,7 @@ " // this method will remove an element from a set", " this.remove = function(element) {", " if(this.has(element)){", - " index = collection.indexOf(element);", + " var index = collection.indexOf(element);", " collection.splice(index,1);", " return true;", " }", @@ -481,7 +481,7 @@ " // this method will remove an element from a set", " this.remove = function(element) {", " if(this.has(element)){", - " index = collection.indexOf(element);", + " var index = collection.indexOf(element);", " collection.splice(index,1);", " return true;", " }", @@ -550,7 +550,7 @@ " // this method will remove an element from a set", " this.remove = function(element) {", " if(this.has(element)){", - " index = collection.indexOf(element);", + " var index = collection.indexOf(element);", " collection.splice(index,1);", " return true;", " }", @@ -630,7 +630,7 @@ " // this method will remove an element from a set", " this.remove = function(element) {", " if(this.has(element)){", - " index = collection.indexOf(element);", + " var index = collection.indexOf(element);", " collection.splice(index,1);", " return true;", " }", From 674ce83ab04c19d113b482ebbeae5070f15c6388 Mon Sep 17 00:00:00 2001 From: Jonathan Grah <30289773+jonathan-grah@users.noreply.github.com> Date: Thu, 21 Dec 2017 01:15:23 +0000 Subject: [PATCH 004/108] feat(cert): Certificates (#16185) * feat(cert): finished layout and design of legacy certificates * feat(cert): added new certs * feat(cert): added logic for new certs * feat(cert): updated claiming challenges * feat(cert): fixed various small issues * feat(cert): completed suggested changes --- common/models/user.json | 30 +++++++ ...our-responsive-web-design-certificate.json | 26 +++--- ...script-algorithms-and-data-structures.json | 20 ++--- ...-your-front-end-libraries-certificate.json | 18 ++--- ...m-your-data-visualization-certificate.json | 26 +++--- ...ur-apis-and-microservices-certificate.json | 24 +++--- ...ity-and-quality-assurance-certificate.json | 24 +++--- server/boot/certificate.js | 78 +++++++++++++++--- server/boot/commit.js | 2 +- server/boot/user.js | 81 +++++++++++++++---- server/services/user.js | 5 ++ server/utils/certTypes.json | 7 +- server/utils/commit-goals.json | 9 ++- server/utils/commit.js | 19 ++++- server/utils/constantStrings.json | 9 ++- .../views/certificate/advanced-front-end.jade | 32 ++++++++ .../certificate/apis-and-microservices.jade | 32 ++++++++ server/views/certificate/back-end.jade | 58 +++++++------ server/views/certificate/data-vis.jade | 36 --------- .../views/certificate/data-visualization.jade | 32 ++++++++ .../certificate/front-end-libraries.jade | 32 ++++++++ server/views/certificate/front-end.jade | 58 +++++++------ server/views/certificate/full-stack.jade | 58 +++++++------ ...mation-security-and-quality-assurance.jade | 32 ++++++++ ...script-algorithms-and-data-structures.jade | 32 ++++++++ .../certificate/responsive-web-design.jade | 32 ++++++++ server/views/certificate/styles.jade | 5 +- server/views/commit/index.jade | 30 ++++--- server/views/emails/a-new-user.ejs | 11 ++- 29 files changed, 604 insertions(+), 254 deletions(-) create mode 100644 server/views/certificate/advanced-front-end.jade create mode 100644 server/views/certificate/apis-and-microservices.jade delete mode 100644 server/views/certificate/data-vis.jade create mode 100644 server/views/certificate/data-visualization.jade create mode 100644 server/views/certificate/front-end-libraries.jade create mode 100644 server/views/certificate/information-security-and-quality-assurance.jade create mode 100644 server/views/certificate/javascript-algorithms-and-data-structures.jade create mode 100644 server/views/certificate/responsive-web-design.jade diff --git a/common/models/user.json b/common/models/user.json index 737b2055e0..2dbcceeac3 100644 --- a/common/models/user.json +++ b/common/models/user.json @@ -179,6 +179,36 @@ "description": "Campers is full stack certified", "default": false }, + "isRespWebDesignCert": { + "type": "boolean", + "description": "Camper is data visualization certified", + "default": false + }, + "isNewDataVisCert": { + "type": "boolean", + "description": "Camper is responsive web design certified", + "default": false + }, + "isFrontEndLibsCert": { + "type": "boolean", + "description": "Camper is front end libraries certified", + "default": false + }, + "isJsAlgoDataStructCert": { + "type": "boolean", + "description": "Camper is javascript algorithms and data structures certified", + "default": false + }, + "isApisMicroservicesCert": { + "type": "boolean", + "description": "Camper is apis and microservices certified", + "default": false + }, + "isInfosecQaCert": { + "type": "boolean", + "description": "Camper is information security and quality assurance certified", + "default": false + }, "isChallengeMapMigrated": { "type": "boolean", "description": "Migrate completedChallenges array to challenge map", diff --git a/seed/challenges/01-responsive-web-design/claim-your-responsive-web-design-certificate.json b/seed/challenges/01-responsive-web-design/claim-your-responsive-web-design-certificate.json index fb4a4a4d8b..60fb8700a4 100644 --- a/seed/challenges/01-responsive-web-design/claim-your-responsive-web-design-certificate.json +++ b/seed/challenges/01-responsive-web-design/claim-your-responsive-web-design-certificate.json @@ -8,9 +8,9 @@ "title": "Claim Your Responsive Web Design Certificate", "description": [ [ - "//i.imgur.com/k8btNUB.jpg", + "//i.imgur.com/GjTPLxI.jpg", "An image of our Responsive Web Design Certificate", - "This challenge will give you your verified Responsive Web Design Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", + "This challenge will give you your verified Responsive Web Design Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our responsive web design projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" ], [ @@ -20,9 +20,9 @@ "#" ], [ - "//i.imgur.com/UedoV2G.jpg", - "An image of the text \"Front End Development Certificate requirements\"", - "Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. Click the button below to verify this.", + "//i.imgur.com/cyRVnUa.jpg", + "An image of the text \"Responsive Web Design requirements\"", + "Let's confirm that you have completed all of our responsive web design projects. Click the button below to verify this.", "#" ], [ @@ -36,11 +36,11 @@ { "properties": [ "isHonest", - "isFrontEndCert" + "isRespWebDesignCert" ], "apis": [ "/certificate/honest", - "/certificate/verify/front-end" + "/certificate/verify/responsive-web-design" ], "stepIndex": [ 1, @@ -77,9 +77,9 @@ "title": "Reclama tu certificado de Desarrollo de interfaces", "description": [ [ - "//i.imgur.com/k8btNUB.jpg", - "Una imagen que muestra nuestro certificado de Desarrollo de interfaces", - "Este desafío te otorga tu certificado autenticado de Desarrollo de interfaces. Antes de que podamos emitir tu certificado, debemos verificar que has completado todos los desafíos básicos e intermedios de diseño de algoritmos, y todos los proyectos básicos e intermedios de desarrollo de interfaces. También debes aceptar nuestro Juramento de honestidad académica. Pulsa el botón siguiente para iniciar este proceso.", + "//i.imgur.com/GjTPLxI.jpg", + "An image of our Responsive Web Design Certificate", + "This challenge will give you your verified Responsive Web Design Certificate. Before we issue your certificate, we must verify that you have completed all of our responsive web design projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" ], [ @@ -89,9 +89,9 @@ "#" ], [ - "//i.imgur.com/14F2Van.jpg", - "Una imagen del texto \"Front End Development Certificate requirements\"", - "Confirmemos que has completado todos nuestros desafíos básicos e intermedios de diseño de algoritmos, y todos nuestros proyectos básicos e intermedios de desarrollo de interfaces. Pulsa el botón siguiente para hacer la verificación.", + "//i.imgur.com/cyRVnUa.jpg", + "An image of the text \"Responsive Web Design requirements\"", + "Let's confirm that you have completed all of our responsive web design projects. Click the button below to verify this.", "#" ], [ diff --git a/seed/challenges/02-javascript-algorithms-and-data-structures/claim-your-javascript-algorithms-and-data-structures.json b/seed/challenges/02-javascript-algorithms-and-data-structures/claim-your-javascript-algorithms-and-data-structures.json index d865160fbe..15d2f606d8 100644 --- a/seed/challenges/02-javascript-algorithms-and-data-structures/claim-your-javascript-algorithms-and-data-structures.json +++ b/seed/challenges/02-javascript-algorithms-and-data-structures/claim-your-javascript-algorithms-and-data-structures.json @@ -8,7 +8,7 @@ "title": "Claim Your JavaScript Algorithms and Data Structures Certificate", "description": [ [ - "//i.imgur.com/k8btNUB.jpg", + "//i.imgur.com/EzMrezJ.jpg", "An image of our JavaScript Algorithms and Data Structures Certificate", "This challenge will give you your verified JavaScript Algorithms and Data Structures Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" @@ -20,8 +20,8 @@ "#" ], [ - "//i.imgur.com/UedoV2G.jpg", - "An image of the text \"JavaScript Algorithms and Data Structures Certificate Requirements\"", + "//i.imgur.com/rx2gKfB.jpg", + "An image of the text \"JavaScript Algorithms and Data Structures requirements\"", "Let's confirm that you have completed all of our JavaScript Algorithms and Data Structures projects. Click the button below to verify this.", "#" ], @@ -36,11 +36,11 @@ { "properties": [ "isHonest", - "isFrontEndCert" + "isJsAlgoDataStructCert" ], "apis": [ "/certificate/honest", - "/certificate/verify/front-end" + "/certificate/verify/javascript-algorithms-data-structures" ], "stepIndex": [ 1, @@ -74,9 +74,9 @@ "challengeType": 7, "descriptionEs": [ [ - "//i.imgur.com/k8btNUB.jpg", + "//i.imgur.com/EzMrezJ.jpg", "Una imagen que muestra nuestro certificado de Desarrollo de interfaces", - "Este desafío te otorga tu certificado autenticado de Desarrollo de interfaces. Antes de que podamos emitir tu certificado, debemos verificar que has completado todos los desafíos básicos e intermedios de diseño de algoritmos, y todos los proyectos básicos e intermedios de desarrollo de interfaces. También debes aceptar nuestro Juramento de honestidad académica. Pulsa el botón siguiente para iniciar este proceso.", + "This challenge will give you your verified JavaScript Algorithms and Data Structures Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" ], [ @@ -86,9 +86,9 @@ "#" ], [ - "//i.imgur.com/14F2Van.jpg", - "Una imagen del texto \"Front End Development Certificate requirements\"", - "Confirmemos que has completado todos nuestros desafíos básicos e intermedios de diseño de algoritmos, y todos nuestros proyectos básicos e intermedios de desarrollo de interfaces. Pulsa el botón siguiente para hacer la verificación.", + "//i.imgur.com/rx2gKfB.jpg", + "An image of the text \"JavaScript Algorithms and Data Structures requirements\"", + "Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges. Click the button below to verify this.", "#" ], [ diff --git a/seed/challenges/03-front-end-libraries/claim-your-front-end-libraries-certificate.json b/seed/challenges/03-front-end-libraries/claim-your-front-end-libraries-certificate.json index 64096ce0d9..5e68368cf3 100644 --- a/seed/challenges/03-front-end-libraries/claim-your-front-end-libraries-certificate.json +++ b/seed/challenges/03-front-end-libraries/claim-your-front-end-libraries-certificate.json @@ -8,9 +8,9 @@ "title": "Claim Your Front End Libraries Certificate", "description": [ [ - "//i.imgur.com/k8btNUB.jpg", + "//i.imgur.com/vOtZumH.jpg", "An image of our Front End Libraries Certificate", - "This challenge will give you your verified Front End Libraries Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", + "This challenge will give you your verified Front End Libraries Certificate. Before we issue your certificate, we must verify that you have completed all of our front end libraries projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" ], [ @@ -20,9 +20,9 @@ "#" ], [ - "//i.imgur.com/UedoV2G.jpg", - "An image of the text \"Front End Development Certificate requirements\"", - "Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. Click the button below to verify this.", + "//i.imgur.com/GJeTCMS.jpg", + "An image of the text \"Front End Libraries Certificate requirements\"", + "Let's confirm that you have completed all of our front end libraries projects. Click the button below to verify this.", "#" ], [ @@ -36,11 +36,11 @@ { "properties": [ "isHonest", - "isFrontEndCert" + "isFrontEndLibsCert" ], "apis": [ "/certificate/honest", - "/certificate/verify/front-end" + "/certificate/verify/front-end-libraries" ], "stepIndex": [ 1, @@ -106,9 +106,9 @@ "title": "Solicite seu Certificado de Bibliotecas Front End", "description": [ [ - "//i.imgur.com/k8btNUB.jpg", + "//i.imgur.com/vOtZumH.jpg", "Uma imagem do nosso Certificado de Bibliotecas Front End", - "Este desafio lhe dará seu certificado verificado de bibliotecas Front End. Antes de emitir o seu certificado, precisamos verificar que você completou todos os nossos desafios de algoritmos básicos e intermediários e todos os nossos projetos básicos, intermediários e avançados de desenvolvimento. Você também deve aceitar nosso Compromisso de Honestidade Acadêmica. Clique no botão abaixo para iniciar este processo.", + "This challenge will give you your verified Front End Libraries Certificate. Before we issue your certificate, we must verify that you have completed all of our front end libraries projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" ], [ diff --git a/seed/challenges/04-data-visualization/claim-your-data-visualization-certificate.json b/seed/challenges/04-data-visualization/claim-your-data-visualization-certificate.json index c123358ce2..f4091a0e99 100644 --- a/seed/challenges/04-data-visualization/claim-your-data-visualization-certificate.json +++ b/seed/challenges/04-data-visualization/claim-your-data-visualization-certificate.json @@ -8,9 +8,9 @@ "title": "Claim Your Data Visualization Certificate", "description": [ [ - "//i.imgur.com/k8btNUB.jpg", + "//i.imgur.com/N8drT4I.jpg", "An image of our Data Visualization Certificate", - "This challenge will give you your verified Data Visualization Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", + "This challenge will give you your verified Data Visualization Certificate. Before we issue your certificate, we must verify that you have completed all of our data visualisation projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" ], [ @@ -20,10 +20,9 @@ "#" ], [ - "//i.imgur.com/UedoV2G.jpg", - "An image of the text \"Front End Development Certificate requirements\"", - "Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. Click the button below to verify this.", - "#" + "//i.imgur.com/BUaEvDo.jpg", + "An image of the text \"Data Visualization Certificate requirements\"", + "Let's confirm that you have completed data visualisation projects. Click the button below to verify this.", "#" ], [ "//i.imgur.com/Q5Za9U6.jpg", @@ -36,11 +35,11 @@ { "properties": [ "isHonest", - "isFrontEndCert" + "isDataVisCert" ], "apis": [ "/certificate/honest", - "/certificate/verify/front-end" + "/certificate/verify/data-visualization" ], "stepIndex": [ 1, @@ -77,10 +76,9 @@ "title": "Reclama tu certificado de Desarrollo de interfaces", "description": [ [ - "//i.imgur.com/k8btNUB.jpg", + "//i.imgur.com/N8drT4I.jpg", "Una imagen que muestra nuestro certificado de Desarrollo de interfaces", - "Este desafío te otorga tu certificado autenticado de Desarrollo de interfaces. Antes de que podamos emitir tu certificado, debemos verificar que has completado todos los desafíos básicos e intermedios de diseño de algoritmos, y todos los proyectos básicos e intermedios de desarrollo de interfaces. También debes aceptar nuestro Juramento de honestidad académica. Pulsa el botón siguiente para iniciar este proceso.", - "" + "This challenge will give you your verified Data Visualization Certificate. Before we issue your certificate, we must verify that you have completed all of our data visualisation projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" ], [ "//i.imgur.com/HArFfMN.jpg", @@ -89,9 +87,9 @@ "#" ], [ - "//i.imgur.com/14F2Van.jpg", - "Una imagen del texto \"Front End Development Certificate requirements\"", - "Confirmemos que has completado todos nuestros desafíos básicos e intermedios de diseño de algoritmos, y todos nuestros proyectos básicos e intermedios de desarrollo de interfaces. Pulsa el botón siguiente para hacer la verificación.", + "//i.imgur.com/BUaEvDo.jpg", + "An image of the text \"Data Visualization Certificate requirements\"", + "Let's confirm that you have completed data visualisation projects. Click the button below to verify this.", "Confirmemos que has completado todos nuestros desafíos básicos e intermedios de diseño de algoritmos, y todos nuestros proyectos básicos e intermedios de desarrollo de interfaces. Pulsa el botón siguiente para hacer la verificación.", "#" ], [ diff --git a/seed/challenges/05-apis-and-microservices/claim-your-apis-and-microservices-certificate.json b/seed/challenges/05-apis-and-microservices/claim-your-apis-and-microservices-certificate.json index e1874d27ea..c43ce58cf3 100644 --- a/seed/challenges/05-apis-and-microservices/claim-your-apis-and-microservices-certificate.json +++ b/seed/challenges/05-apis-and-microservices/claim-your-apis-and-microservices-certificate.json @@ -8,9 +8,9 @@ "title": "Claim Your APIs and Microservices Certificate", "description": [ [ - "//i.imgur.com/k8btNUB.jpg", + "//i.imgur.com/gfH7j5B.jpg", "An image of our APIs and Microservices Certificate", - "This challenge will give you your verified APIs and Microservices Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", + "This challenge will give you your verified APIs and Microservices Certificate. Before we issue your certificate, we must verify that you have completed all of our apis and microservices projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" ], [ @@ -20,9 +20,9 @@ "#" ], [ - "//i.imgur.com/UedoV2G.jpg", - "An image of the text \"Front End Development Certificate requirements\"", - "Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. Click the button below to verify this.", + "//i.imgur.com/IBTfUzO.jpg", + "An image of the text \"APIs and Microservices Certificate requirements\"", + "Let's confirm that you have completed all of our apis and microservices projects. Click the button below to verify this.", "#" ], [ @@ -36,11 +36,11 @@ { "properties": [ "isHonest", - "isFrontEndCert" + "isApisMicroservicesCert" ], "apis": [ "/certificate/honest", - "/certificate/verify/front-end" + "/certificate/verify/apis-microservices" ], "stepIndex": [ 1, @@ -77,9 +77,9 @@ "title": "Reclama tu certificado de Desarrollo de interfaces", "description": [ [ - "//i.imgur.com/k8btNUB.jpg", + "//i.imgur.com/gfH7j5B.jpg", "Una imagen que muestra nuestro certificado de Desarrollo de interfaces", - "Este desafío te otorga tu certificado autenticado de Desarrollo de interfaces. Antes de que podamos emitir tu certificado, debemos verificar que has completado todos los desafíos básicos e intermedios de diseño de algoritmos, y todos los proyectos básicos e intermedios de desarrollo de interfaces. También debes aceptar nuestro Juramento de honestidad académica. Pulsa el botón siguiente para iniciar este proceso.", + "This challenge will give you your verified APIs and Microservices Certificate. Before we issue your certificate, we must verify that you have completed all of our apis and microservices projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" ], [ @@ -89,9 +89,9 @@ "#" ], [ - "//i.imgur.com/14F2Van.jpg", - "Una imagen del texto \"Front End Development Certificate requirements\"", - "Confirmemos que has completado todos nuestros desafíos básicos e intermedios de diseño de algoritmos, y todos nuestros proyectos básicos e intermedios de desarrollo de interfaces. Pulsa el botón siguiente para hacer la verificación.", + "//i.imgur.com/IBTfUzO.jpg", + "An image of the text \"APIs and Microservices Certificate requirements\"", + "Let's confirm that you have completed all of our apis and microservices projects. Click the button below to verify this.", "#" ], [ diff --git a/seed/challenges/06-information-security-and-quality-assurance/claim-your-information-security-and-quality-assurance-certificate.json b/seed/challenges/06-information-security-and-quality-assurance/claim-your-information-security-and-quality-assurance-certificate.json index 71d6c94d22..ec0bbb6134 100644 --- a/seed/challenges/06-information-security-and-quality-assurance/claim-your-information-security-and-quality-assurance-certificate.json +++ b/seed/challenges/06-information-security-and-quality-assurance/claim-your-information-security-and-quality-assurance-certificate.json @@ -8,9 +8,9 @@ "title": "Claim Your Information Security and Quality Assurance Certificate", "description": [ [ - "//i.imgur.com/k8btNUB.jpg", + "//i.imgur.com/YhKzGLb.jpg", "An image of our Information Security and Quality Assurance Certificate", - "This challenge will give you your verified Information Security and Quality Assurance Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", + "This challenge will give you your verified Information Security and Quality Assurance Certificate. Before we issue your certificate, we must verify that you have completed all of our information security and quality assurance projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" ], [ @@ -20,9 +20,9 @@ "#" ], [ - "//i.imgur.com/UedoV2G.jpg", - "An image of the text \"Front End Development Certificate requirements\"", - "Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. Click the button below to verify this.", + "//i.imgur.com/TM4KGfb.jpg", + "An image of the text \"Information Security and Quality Assurance Certificate requirements\"", + "Let's confirm that you have completed all of our information security and quality assurance projects. Click the button below to verify this.", "#" ], [ @@ -36,11 +36,11 @@ { "properties": [ "isHonest", - "isFrontEndCert" + "isInfosecQaCert" ], "apis": [ "/certificate/honest", - "/certificate/verify/front-end" + "/certificate/verify/information-security-quality-assurance" ], "stepIndex": [ 1, @@ -77,9 +77,9 @@ "title": "Reclama tu certificado de Desarrollo de interfaces", "description": [ [ - "//i.imgur.com/k8btNUB.jpg", + "//i.imgur.com/YhKzGLb.jpg", "Una imagen que muestra nuestro certificado de Desarrollo de interfaces", - "Este desafío te otorga tu certificado autenticado de Desarrollo de interfaces. Antes de que podamos emitir tu certificado, debemos verificar que has completado todos los desafíos básicos e intermedios de diseño de algoritmos, y todos los proyectos básicos e intermedios de desarrollo de interfaces. También debes aceptar nuestro Juramento de honestidad académica. Pulsa el botón siguiente para iniciar este proceso.", + "This challenge will give you your verified Information Security and Quality Assurance Certificate. Before we issue your certificate, we must verify that you have completed all of our information security and quality assurance projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.", "" ], [ @@ -89,9 +89,9 @@ "#" ], [ - "//i.imgur.com/14F2Van.jpg", - "Una imagen del texto \"Front End Development Certificate requirements\"", - "Confirmemos que has completado todos nuestros desafíos básicos e intermedios de diseño de algoritmos, y todos nuestros proyectos básicos e intermedios de desarrollo de interfaces. Pulsa el botón siguiente para hacer la verificación.", + "//i.imgur.com/TM4KGfb.jpg", + "An image of the text \"Information Security and Quality Assurance Certificate requirements\"", + "Let's confirm that you have completed all of our information security and quality assurance projects. Click the button below to verify this.", "#" ], [ diff --git a/server/boot/certificate.js b/server/boot/certificate.js index 1249d8fbdc..0bb7f9169b 100644 --- a/server/boot/certificate.js +++ b/server/boot/certificate.js @@ -14,9 +14,14 @@ import { import { observeQuery } from '../utils/rx'; import { + respWebDesignId, + frontEndLibsId, + jsAlgoDataStructId, frontEndChallengeId, - dataVisChallengeId, - backEndChallengeId + dataVisId, + apisMicroservicesId, + backEndChallengeId, + infosecQaId } from '../utils/constantStrings.json'; import { @@ -60,9 +65,12 @@ function getIdsForCert$(id, Challenge) { // { // email: String, // username: String, -// isFrontEndCert: Boolean, -// isBackEndCert: Boolean, -// isDataVisCert: Boolean +// isRespWebDesignCert: Boolean, +// isFrontEndLibsCert: Boolean, +// isJsAlgoDataStructCert: Boolean, +// isDataVisCert: Boolean, +// isApisMicroservicesCert: Boolean, +// isInfosecQaCert: Boolean // }, // send$: Observable // ) => Observable @@ -71,17 +79,23 @@ function sendCertifiedEmail( email, name, username, - isFrontEndCert, - isBackEndCert, - isDataVisCert + isRespWebDesignCert, + isFrontEndLibsCert, + isJsAlgoDataStructCert, + isDataVisCert, + isApisMicroservicesCert, + isInfosecQaCert }, send$ ) { if ( !isEmail(email) || - !isFrontEndCert || - !isBackEndCert || - !isDataVisCert + !isRespWebDesignCert || + !isFrontEndLibsCert || + !isJsAlgoDataStructCert || + !isDataVisCert || + !isApisMicroservicesCert || + !isInfosecQaCert ) { return Observable.just(false); } @@ -107,8 +121,16 @@ export default function certificate(app) { const certTypeIds = { [certTypes.frontEnd]: getIdsForCert$(frontEndChallengeId, Challenge), - [certTypes.dataVis]: getIdsForCert$(dataVisChallengeId, Challenge), - [certTypes.backEnd]: getIdsForCert$(backEndChallengeId, Challenge) + [certTypes.backEnd]: getIdsForCert$(backEndChallengeId, Challenge), + [certTypes.respWebDesign]: getIdsForCert$(respWebDesignId, Challenge), + [certTypes.frontEndLibs]: getIdsForCert$(frontEndLibsId, Challenge), + [certTypes.jsAlgoDataStruct]: getIdsForCert$(jsAlgoDataStructId, Challenge), + [certTypes.dataVis]: getIdsForCert$(dataVisId, Challenge), + [certTypes.apisMicroservices]: getIdsForCert$( + apisMicroservicesId, + Challenge + ), + [certTypes.infosecQa]: getIdsForCert$(infosecQaId, Challenge) }; router.post( @@ -123,12 +145,42 @@ export default function certificate(app) { verifyCert.bind(null, certTypes.backEnd) ); + router.post( + '/certificate/verify/responsive-web-design', + ifNoUser401, + verifyCert.bind(null, certTypes.respWebDesign) + ); + + router.post( + '/certificate/verify/front-end-libraries', + ifNoUser401, + verifyCert.bind(null, certTypes.frontEndLibs) + ); + + router.post( + '/certificate/verify/javascript-algorithms-data-structures', + ifNoUser401, + verifyCert.bind(null, certTypes.jsAlgoDataStruct) + ); + router.post( '/certificate/verify/data-visualization', ifNoUser401, verifyCert.bind(null, certTypes.dataVis) ); + router.post( + '/certificate/verify/apis-microservices', + ifNoUser401, + verifyCert.bind(null, certTypes.apisMicroservices) + ); + + router.post( + '/certificate/verify/information-security-quality-assurance', + ifNoUser401, + verifyCert.bind(null, certTypes.infosecQa) + ); + router.post( '/certificate/honest', sendMessageToNonUser, diff --git a/server/boot/commit.js b/server/boot/commit.js index dc8607c215..e4990ed50c 100644 --- a/server/boot/commit.js +++ b/server/boot/commit.js @@ -132,7 +132,7 @@ export default function commit(app) { const { nonprofit: nonprofitName = 'girl develop it', amount = '5', - goal = commitGoals.frontEndCert + goal = commitGoals.respWebDesignCert } = req.query; const nonprofit = findNonprofit(nonprofitName); diff --git a/server/boot/user.js b/server/boot/user.js index 0c0393cf8d..3731ba1047 100644 --- a/server/boot/user.js +++ b/server/boot/user.js @@ -6,8 +6,13 @@ import emoji from 'node-emoji'; import { frontEndChallengeId, - dataVisChallengeId, - backEndChallengeId + backEndChallengeId, + respWebDesignId, + frontEndLibsId, + jsAlgoDataStructId, + dataVisId, + apisMicroservicesId, + infosecQaId } from '../utils/constantStrings.json'; import certTypes from '../utils/certTypes.json'; import { @@ -29,22 +34,40 @@ const debug = debugFactory('fcc:boot:user'); const sendNonUserToMap = ifNoUserRedirectTo('/map'); const certIds = { [certTypes.frontEnd]: frontEndChallengeId, - [certTypes.dataVis]: dataVisChallengeId, - [certTypes.backEnd]: backEndChallengeId + [certTypes.backEnd]: backEndChallengeId, + [certTypes.respWebDesign]: respWebDesignId, + [certTypes.frontEndLibs]: frontEndLibsId, + [certTypes.jsAlgoDataStruct]: jsAlgoDataStructId, + [certTypes.dataVis]: dataVisId, + [certTypes.apisMicroservices]: apisMicroservicesId, + [certTypes.infosecQa]: infosecQaId }; const certViews = { [certTypes.frontEnd]: 'certificate/front-end.jade', - [certTypes.dataVis]: 'certificate/data-vis.jade', [certTypes.backEnd]: 'certificate/back-end.jade', - [certTypes.fullStack]: 'certificate/full-stack.jade' + [certTypes.fullStack]: 'certificate/full-stack.jade', + [certTypes.respWebDesign]: 'certificate/responsive-web-design.jade', + [certTypes.frontEndLibs]: 'certificate/front-end-libraries.jade', + [certTypes.jsAlgoDataStruct]: + 'certificate/javascript-algorithms-and-data-structures.jade', + [certTypes.dataVis]: 'certificate/data-visualization.jade', + [certTypes.apisMicroservices]: 'certificate/apis-and-microservices.jade', + [certTypes.infosecQa]: + 'certificate/information-security-and-quality-assurance.jade' }; const certText = { [certTypes.frontEnd]: 'Front End certified', - [certTypes.dataVis]: 'Data Vis Certified', [certTypes.backEnd]: 'Back End Certified', - [certTypes.fullStack]: 'Full Stack Certified' + [certTypes.fullStack]: 'Full Stack Certified', + [certTypes.respWebDesign]: 'Responsive Web Design Certified', + [certTypes.frontEndLibs]: 'Front End Libraries Certified', + [certTypes.jsAlgoDataStruct]: + 'JavaScript Algorithms and Data Structures Certified', + [certTypes.dataVis]: 'Data Visualization Certified', + [certTypes.apisMicroservices]: 'APIs and Microservices Certified', + [certTypes.infosecQa]: 'Information Security and Quality Assurance Certified' }; const dateFormat = 'MMM DD, YYYY'; @@ -208,11 +231,6 @@ module.exports = function(app) { showCert.bind(null, certTypes.frontEnd) ); - api.get( - '/:username/data-visualization-certification', - showCert.bind(null, certTypes.dataVis) - ); - api.get( '/:username/back-end-certification', showCert.bind(null, certTypes.backEnd) @@ -223,6 +241,36 @@ module.exports = function(app) { (req, res) => res.redirect(req.url.replace('full-stack', 'back-end')) ); + api.get( + '/:username/responsive-web-design-certification', + showCert.bind(null, certTypes.respWebDesign) + ); + + api.get( + '/:username/front-end-libraries-certification', + showCert.bind(null, certTypes.frontEndLibs) + ); + + api.get( + '/:username/javascript-algorithms-data-structures-certification', + showCert.bind(null, certTypes.jsAlgoDataStruct) + ); + + api.get( + '/:username/data-visualization-certification', + showCert.bind(null, certTypes.dataVis) + ); + + api.get( + '/:username/apis-microservices-certification', + showCert.bind(null, certTypes.apisMicroservices) + ); + + api.get( + '/:username/information-security-quality-assurance-certification', + showCert.bind(null, certTypes.infosecQa) + ); + router.get('/:username', showUserProfile); router.get( '/:username/report-user/', @@ -586,9 +634,14 @@ module.exports = function(app) { isLocked: true, isAvailableForHire: true, isFrontEndCert: true, - isDataVisCert: true, isBackEndCert: true, isFullStackCert: true, + isRespWebDesignCert: true, + isFrontEndLibsCert: true, + isJsAlgoDataStructCert: true, + isDataVisCert: true, + isApisMicroservicesCert: true, + isInfosecQaCert: true, isHonest: true, username: true, name: true, diff --git a/server/services/user.js b/server/services/user.js index 0891b3b691..05e2a25196 100644 --- a/server/services/user.js +++ b/server/services/user.js @@ -21,6 +21,11 @@ const publicUserProps = [ 'isBackEndCert', 'isDataVisCert', 'isFullStackCert', + 'isRespWebDesignCert', + 'isFrontEndLibsCert', + 'isJsAlgoDataStructCert', + 'isApisMicroservicesCert', + 'isInfosecQaCert', 'githubURL', 'sendMonthlyEmail', diff --git a/server/utils/certTypes.json b/server/utils/certTypes.json index 6dcd7bdcc7..90cf58d1ff 100644 --- a/server/utils/certTypes.json +++ b/server/utils/certTypes.json @@ -1,6 +1,11 @@ { "frontEnd": "isFrontEndCert", "backEnd": "isBackEndCert", + "fullStack": "isFullStackCert", + "respWebDesign": "isRespWebDesignCert", + "frontEndLibs": "isFrontEndLibsCert", + "jsAlgoDataStruct": "isJsAlgoDataStructCert", "dataVis": "isDataVisCert", - "fullStack": "isFullStackCert" + "apisMicroservices": "isApisMicroservicesCert", + "infosecQa": "isInfosecQaCert" } diff --git a/server/utils/commit-goals.json b/server/utils/commit-goals.json index 9c7c69721b..272ccfca86 100644 --- a/server/utils/commit-goals.json +++ b/server/utils/commit-goals.json @@ -1,6 +1,11 @@ { "frontEndCert": "Front End Development Certification", "backEndCert": "Back End Development Certification", - "dataVisCert": "Data Visualisation Certification", - "fullStackCert": "Full Stack Development Certification" + "fullStackCert": "Full Stack Development Certification", + "respWebDesign": "Responsive Web Design Certification", + "frontEndLibs": "Front End Libraries Certification", + "jsAlgoDataStruct": "JavaScript Algorithms and Data Structures Certification", + "dataVis": "Data Visualisation Certification", + "apisMicroservices": "APIs and Microservices Certification", + "infosecQa": "Information Security and Quality Assurance Certification" } diff --git a/server/utils/commit.js b/server/utils/commit.js index a7f5d2ba7b..2a04fb7bcc 100644 --- a/server/utils/commit.js +++ b/server/utils/commit.js @@ -10,9 +10,14 @@ export { commitGoals }; export function completeCommitment$(user) { const { isFrontEndCert, - isDataVisCert, isBackEndCert, - isFullStackCert + isFullStackCert, + isRespWebDesignCert, + isFrontEndLibsCert, + isJsAlgoDataStructCert, + isDataVisCert, + isApisMicroservicesCert, + isInfosecQaCert } = user; return Observable.fromNodeCallback(user.pledge, user)() @@ -25,9 +30,15 @@ export function completeCommitment$(user) { if ( (isFrontEndCert && goal === commitGoals.frontEndCert) || - (isDataVisCert && goal === commitGoals.dataVisCert) || (isBackEndCert && goal === commitGoals.backEndCert) || - (isFullStackCert && goal === commitGoals.fullStackCert) + (isFullStackCert && goal === commitGoals.fullStackCert) || + (isRespWebDesignCert && goal === commitGoals.respWebDesignCert) || + (isFrontEndLibsCert && goal === commitGoals.frontEndLibsCert) || + (isJsAlgoDataStructCert && goal === commitGoals.jsAlgoDataStructCert) || + (isDataVisCert && goal === commitGoals.dataVisCert) || + (isApisMicroservicesCert && + goal === commitGoals.apisMicroservicesCert) || + (isInfosecQaCert && goal === commitGoals.infosecQaCert) ) { debug('marking goal complete'); pledge.isCompleted = true; diff --git a/server/utils/constantStrings.json b/server/utils/constantStrings.json index eba50d1f67..9163a1a3b5 100644 --- a/server/utils/constantStrings.json +++ b/server/utils/constantStrings.json @@ -1,6 +1,11 @@ { "gitHubUserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1521.3 Safari/537.36", "frontEndChallengeId": "561add10cb82ac38a17513be", - "dataVisChallengeId": "561add10cb82ac38a17513b3", - "backEndChallengeId": "660add10cb82ac38a17513be" + "backEndChallengeId": "660add10cb82ac38a17513be", + "respWebDesignId": "561add10cb82ac38a17513bc", + "frontEndLibsId": "561acd10cb82ac38a17513bc", + "jsAlgoDataStructId": "561abd10cb81ac38a17513bc", + "dataVisId": "561add10cb82ac39a17513bc", + "apisMicroservicesId": "561add10cb82ac38a17523bc", + "infosecQaId": "561add10cb82ac38a17213bc" } diff --git a/server/views/certificate/advanced-front-end.jade b/server/views/certificate/advanced-front-end.jade new file mode 100644 index 0000000000..1d2e18bb86 --- /dev/null +++ b/server/views/certificate/advanced-front-end.jade @@ -0,0 +1,32 @@ +meta(name='viewport', content='width=device-width, initial-scale=1') +link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css') +include styles + +.certificate-wrapper.container + .row + header + .col-md-5.col-sm-12 + .logo + img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") + .col-md-7.col-sm-12 + .issue-date Issued  + strong #{date} + + section.information + .information-container + h3 This certifies that + h1 + strong= name + h3 has successfully completed freeCodeCamp's + h1 + strong Advanced Frontend Projects + h4 1 of 3 legacy freeCodeCamp certificates, representing approximately 400 hours of coursework + + footer + .row.signatures + img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") + p + strong Quincy Larson + p Executive Director, freeCodeCamp.org + .row + p.verify Verify this certificate at: https://freecodecamp.org/#{username}/advanced-front-end-certification diff --git a/server/views/certificate/apis-and-microservices.jade b/server/views/certificate/apis-and-microservices.jade new file mode 100644 index 0000000000..56e8d2fc3d --- /dev/null +++ b/server/views/certificate/apis-and-microservices.jade @@ -0,0 +1,32 @@ +meta(name='viewport', content='width=device-width, initial-scale=1') +link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css') +include styles + +.certificate-wrapper.container + .row + header + .col-md-5.col-sm-12 + .logo + img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") + .col-md-7.col-sm-12 + .issue-date Issued  + strong #{date} + + section.information + .information-container + h3 This certifies that + h1 + strong= name + h3 has successfully completed freeCodeCamp's + h1 + strong APIs and Microservices Projects + h4 1 of 6 freeCodeCamp certificates, representing approximately 300 hours of coursework + + footer + .row.signatures + img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") + p + strong Quincy Larson + p Executive Director, freeCodeCamp.org + .row + p.verify Verify this certificate at: https://freecodecamp.org/#{username}/apis-and-microservices-certification diff --git a/server/views/certificate/back-end.jade b/server/views/certificate/back-end.jade index 823299a3b0..1d2bf7631f 100644 --- a/server/views/certificate/back-end.jade +++ b/server/views/certificate/back-end.jade @@ -3,34 +3,30 @@ link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-boot include styles .certificate-wrapper.container - .row - header - .col-md-5.col-sm-12 - .logo - img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") - .col-md-7.col-sm-12 - .issue-date Issued - strong #{date} - - section.information - .information-container - h3 This certifies that - h1 - strong= name - h3 has successfully completed the - h1 - strong Back End Development Projects - h4 (400 hours of coursework & 1 of 3 freeCodeCamp certificates) - - footer - .row.signatures - .col-md-6 - img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") - p - strong Quincy Larson - .col-md-6 - img(class='img-responsive', src='https://i.imgur.com/b0YdXS4.png', alt="Michael D. Johnson's Signature") - p - strong Michael D. Johnson - .row - p.verify Verify this certificate at: https://www.freecodecamp.org/#{username}/back-end-certification + .row + header + .col-md-5.col-sm-12 + .logo + img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") + .col-md-7.col-sm-12 + .issue-date Issued  + strong #{date} + + section.information + .information-container + h3 This certifies that + h1 + strong= name + h3 has successfully completed freeCodeCamp's + h1 + strong Back End Development Projects + h4 1 of 3 legacy freeCodeCamp certificates, representing approximately 400 hours of coursework + + footer + .row.signatures + img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") + p + strong Quincy Larson + p Executive Director, freeCodeCamp.org + .row + p.verify Verify this certificate at: https://freecodecamp.org/#{username}/back-end-certification diff --git a/server/views/certificate/data-vis.jade b/server/views/certificate/data-vis.jade deleted file mode 100644 index 550340e5e0..0000000000 --- a/server/views/certificate/data-vis.jade +++ /dev/null @@ -1,36 +0,0 @@ -meta(name='viewport', content='width=device-width, initial-scale=1') -link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css') -include styles - -.certificate-wrapper.container - .row - header - .col-md-5.col-sm-12 - .logo - img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") - .col-md-7.col-sm-12 - .issue-date Issued - strong #{date} - - section.information - .information-container - h3 This certifies that - h1 - strong= name - h3 has successfully completed the - h1 - strong Data Visualization Projects - h4 (400 hours of coursework & 1 of 3 freeCodeCamp certificates) - - footer - .row.signatures - .col-md-6 - img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") - p - strong Quincy Larson - .col-md-6 - img(class='img-responsive', src='https://i.imgur.com/b0YdXS4.png', alt="Michael D. Johnson's Signature") - p - strong Michael D. Johnson - .row - p.verify Verify this certificate at: https://www.freecodecamp.org/#{username}/data-visualization-certification diff --git a/server/views/certificate/data-visualization.jade b/server/views/certificate/data-visualization.jade new file mode 100644 index 0000000000..1831699fe0 --- /dev/null +++ b/server/views/certificate/data-visualization.jade @@ -0,0 +1,32 @@ +meta(name='viewport', content='width=device-width, initial-scale=1') +link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css') +include styles + +.certificate-wrapper.container + .row + header + .col-md-5.col-sm-12 + .logo + img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") + .col-md-7.col-sm-12 + .issue-date Issued  + strong #{date} + + section.information + .information-container + h3 This certifies that + h1 + strong= name + h3 has successfully completed freeCodeCamp's + h1 + strong Data Visualization Projects + h4 1 of 6 freeCodeCamp certificates, representing approximately 300 hours of coursework + + footer + .row.signatures + img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") + p + strong Quincy Larson + p Executive Director, freeCodeCamp.org + .row + p.verify Verify this certificate at: https://freecodecamp.org/#{username}/data-visualization-certification diff --git a/server/views/certificate/front-end-libraries.jade b/server/views/certificate/front-end-libraries.jade new file mode 100644 index 0000000000..24d7dfad85 --- /dev/null +++ b/server/views/certificate/front-end-libraries.jade @@ -0,0 +1,32 @@ +meta(name='viewport', content='width=device-width, initial-scale=1') +link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css') +include styles + +.certificate-wrapper.container + .row + header + .col-md-5.col-sm-12 + .logo + img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") + .col-md-7.col-sm-12 + .issue-date Issued  + strong #{date} + + section.information + .information-container + h3 This certifies that + h1 + strong= name + h3 has successfully completed freeCodeCamp's + h1 + strong Front End Libraries Projects + h4 1 of 6 freeCodeCamp certificates, representing approximately 300 hours of coursework + + footer + .row.signatures + img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") + p + strong Quincy Larson + p Executive Director, freeCodeCamp.org + .row + p.verify Verify this certificate at: https://freecodecamp.org/#{username}/front-end-libraries-certification diff --git a/server/views/certificate/front-end.jade b/server/views/certificate/front-end.jade index 6451c06fef..efa363ce88 100644 --- a/server/views/certificate/front-end.jade +++ b/server/views/certificate/front-end.jade @@ -3,34 +3,30 @@ link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-boot include styles .certificate-wrapper.container - .row - header - .col-md-5.col-sm-12 - .logo - img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") - .col-md-7.col-sm-12 - .issue-date Issued - strong #{date} - - section.information - .information-container - h3 This certifies that - h1 - strong= name - h3 has successfully completed the - h1 - strong Front End Development Projects - h4 (400 hours of coursework & 1 of 3 freeCodeCamp certificates) - - footer - .row.signatures - .col-md-6 - img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") - p - strong Quincy Larson - .col-md-6 - img(class='img-responsive', src='https://i.imgur.com/b0YdXS4.png', alt="Michael D. Johnson's Signature") - p - strong Michael D. Johnson - .row - p.verify Verify this certificate at: https://www.freecodecamp.org/#{username}/front-end-certification + .row + header + .col-md-5.col-sm-12 + .logo + img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") + .col-md-7.col-sm-12 + .issue-date Issued  + strong #{date} + + section.information + .information-container + h3 This certifies that + h1 + strong= name + h3 has successfully completed freeCodeCamp's + h1 + strong Front End Development Projects + h4 1 of 3 legacy freeCodeCamp certificates, representing approximately 400 hours of coursework + + footer + .row.signatures + img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") + p + strong Quincy Larson + p Executive Director, freeCodeCamp.org + .row + p.verify Verify this certificate at: https://freecodecamp.org/#{username}/front-end-certification diff --git a/server/views/certificate/full-stack.jade b/server/views/certificate/full-stack.jade index 246221d560..69fea248f7 100644 --- a/server/views/certificate/full-stack.jade +++ b/server/views/certificate/full-stack.jade @@ -3,34 +3,30 @@ link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-boot include styles .certificate-wrapper.container - .row - header - .col-md-5.col-sm-12 - .logo - img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") - .col-md-7.col-sm-12 - .issue-date Issued - strong #{date} - - section.information - .information-container - h3 This certifies that - h1 - strong= name - h3 has successfully completed the - h1 - strong Full Stack Development Projects - h4 (400 hours of coursework & 1 of 3 freeCodeCamp certificates) - - footer - .row.signatures - .col-md-6 - img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") - p - strong Quincy Larson - .col-md-6 - img(class='img-responsive', src='https://i.imgur.com/b0YdXS4.png', alt="Michael D. Johnson's Signature") - p - strong Michael D. Johnson - .row - p.verify Verify this certificate at: https://www.freecodecamp.org/#{username}/full-stack-certification + .row + header + .col-md-5.col-sm-12 + .logo + img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") + .col-md-7.col-sm-12 + .issue-date Issued  + strong #{date} + + section.information + .information-container + h3 This certifies that + h1 + strong= name + h3 has successfully completed freeCodeCamp's + h1 + strong Full Stack Development Projects + h4 1 of 3 legacy freeCodeCamp certificates, representing approximately 400 hours of coursework + + footer + .row.signatures + img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") + p + strong Quincy Larson + p Executive Director, freeCodeCamp.org + .row + p.verify Verify this certificate at: https://freecodecamp.org/#{username}/full-stack-certification diff --git a/server/views/certificate/information-security-and-quality-assurance.jade b/server/views/certificate/information-security-and-quality-assurance.jade new file mode 100644 index 0000000000..5d82fb7d24 --- /dev/null +++ b/server/views/certificate/information-security-and-quality-assurance.jade @@ -0,0 +1,32 @@ +meta(name='viewport', content='width=device-width, initial-scale=1') +link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css') +include styles + +.certificate-wrapper.container + .row + header + .col-md-5.col-sm-12 + .logo + img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") + .col-md-7.col-sm-12 + .issue-date Issued  + strong #{date} + + section.information + .information-container + h3 This certifies that + h1 + strong= name + h3 has successfully completed freeCodeCamp's + h1 + strong Information Security and Quality Assurance Projects + h4 1 of 6 freeCodeCamp certificates, representing approximately 300 hours of coursework + + footer + .row.signatures + img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") + p + strong Quincy Larson + p Executive Director, freeCodeCamp.org + .row + p.verify Verify this certificate at: https://freecodecamp.org/#{username}/information-security-and-quality-assurance-certification diff --git a/server/views/certificate/javascript-algorithms-and-data-structures.jade b/server/views/certificate/javascript-algorithms-and-data-structures.jade new file mode 100644 index 0000000000..03b42c29aa --- /dev/null +++ b/server/views/certificate/javascript-algorithms-and-data-structures.jade @@ -0,0 +1,32 @@ +meta(name='viewport', content='width=device-width, initial-scale=1') +link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css') +include styles + +.certificate-wrapper.container + .row + header + .col-md-5.col-sm-12 + .logo + img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") + .col-md-7.col-sm-12 + .issue-date Issued  + strong #{date} + + section.information + .information-container + h3 This certifies that + h1 + strong= name + h3 has successfully completed freeCodeCamp's + h1 + strong JavaScript Algorithms and Data Structures Certificate + h4 1 of 6 freeCodeCamp certificates, representing approximately 300 hours of coursework + + footer + .row.signatures + img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") + p + strong Quincy Larson + p Executive Director, freeCodeCamp.org + .row + p.verify Verify this certificate at: https://freecodecamp.org/#{username}/javascript-algorithms-and-data-structures-certification diff --git a/server/views/certificate/responsive-web-design.jade b/server/views/certificate/responsive-web-design.jade new file mode 100644 index 0000000000..b5ccbe321b --- /dev/null +++ b/server/views/certificate/responsive-web-design.jade @@ -0,0 +1,32 @@ +meta(name='viewport', content='width=device-width, initial-scale=1') +link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css') +include styles + +.certificate-wrapper.container + .row + header + .col-md-5.col-sm-12 + .logo + img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo") + .col-md-7.col-sm-12 + .issue-date Issued  + strong #{date} + + section.information + .information-container + h3 This certifies that + h1 + strong= name + h3 has successfully completed freeCodeCamp's + h1 + strong Responsive Web Design Projects + h4 1 of 6 freeCodeCamp certificates, representing approximately 300 hours of coursework + + footer + .row.signatures + img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature") + p + strong Quincy Larson + p Executive Director, freeCodeCamp.org + .row + p.verify Verify this certificate at: https://freecodecamp.org/#{username}/responsive-web-design-certification diff --git a/server/views/certificate/styles.jade b/server/views/certificate/styles.jade index b9dcc31195..c65f61e98e 100644 --- a/server/views/certificate/styles.jade +++ b/server/views/certificate/styles.jade @@ -70,6 +70,7 @@ style. .information { margin-top: -20px; height: 380px; + text-align: center; background-color: #efefef; } @@ -98,7 +99,7 @@ style. color: #006400; } - .signatures .col-md-6 { + .signatures { text-align: center; margin: 0 auto; background-color: #efefef; @@ -183,7 +184,7 @@ style. } } - @media screen and (max-width: 350px) { + @media screen and (max-width: 675px) { .container { padding: 0; border: 0; diff --git a/server/views/commit/index.jade b/server/views/commit/index.jade index 89664458e3..052aafd984 100644 --- a/server/views/commit/index.jade +++ b/server/views/commit/index.jade @@ -23,18 +23,24 @@ block content .col-xs-12.col-sm-6.col-sm-offset-3 h3 Step 1: Which certification do you pledge to complete? .btn-group.btn-group-justified(data-toggle='buttons' role='group') - label.btn.btn-primary.btn-lg.active - input(type='radio' id=frontEndCert value=frontEndCert name='goal' checked="checked") - | Front End - label.btn.btn-primary.btn-lg - input(type='radio' id=dataVisCert value=dataVisCert name='goal') - | Data Vis - label.btn.btn-primary.btn-lg - input(type='radio' id=backEndCert value=backEndCert name='goal') - | Back End - label.btn.btn-primary.btn-lg - input(type='radio' id=fullStackCert value=fullStackCert name='goal') - | Full Stack + label.btn.btn-primary.active + input(type='radio' id="respWebDesignCert" value="Responsive Web Design Certification" name='goal' checked="checked") + | Responsive Web Design + label.btn.btn-primary + input(type='radio' id="frontEndLibsCert" value="Front End Libraries Certification" name='goal') + | Front End Libraries + label.btn.btn-primary + input(type='radio' id="jsAlgoDataStructCert" value="JavaScript Algorithms and Data Structures Certification" name='goal') + | JavaScript Algorithms and Data Structures + label.btn.btn-primary + input(type='radio' id="dataVisCert" value="Data Visualization Certification" name='goal') + | Data Visualization + label.btn.btn-primary + input(type='radio' id="apisMicroservicesCert" value="APIs and Microservices Certification" name='goal') + | APIs and Microservices + label.btn.btn-primary + input(type='radio' id="infosecQaCert" value="Information Security and Quality Assurance Certification" name='goal') + | Information Security and Quality Assurance .spacer .row .col-xs-12.col-sm-6.col-sm-offset-3 diff --git a/server/views/emails/a-new-user.ejs b/server/views/emails/a-new-user.ejs index 98abab37d8..97adc22f70 100644 --- a/server/views/emails/a-new-user.ejs +++ b/server/views/emails/a-new-user.ejs @@ -1,7 +1,10 @@ -Camper <%= username %> has completed all three certifications! +Camper <%= username %> has completed all six certifications! -Completed front end cert on <%= frontEndDate %>. -Completed data vis cert on <%= dataVisDate %>. -Completed back end cert on <%= backEndDate %>. +Completed Responsive Web Design Certification on <%= responsiveWebDesignDate %>. +Completed Front End Libraries Certification on <%= frontEndLibrariesDate %>. +Completed JavaScript Algorithms and Data Structures Certification on <%= javascriptAlgorithmsDataStructuresDate %>. +Completed Data Visualization Certification on <%= dataVisualizationDate %>. +Completed API's and microservices Certification on <%= apisMicroservicesDate %>. +Completed Information Security and Quality Assurance Certification on <%= infosecQADate %>. https://www.freecodecamp.org/<%= username %> From 277898afd36604f66f500d911fd03d337825acbe Mon Sep 17 00:00:00 2001 From: Peter Weinberg Date: Tue, 19 Dec 2017 01:04:17 -0500 Subject: [PATCH 005/108] fix(challenges): put finishing touches on react & redux challenges --- .../react-and-redux.json | 4 +- .../03-front-end-libraries/react.json | 65 +++++++++---------- .../03-front-end-libraries/redux.json | 10 +-- 3 files changed, 36 insertions(+), 43 deletions(-) diff --git a/seed/challenges/03-front-end-libraries/react-and-redux.json b/seed/challenges/03-front-end-libraries/react-and-redux.json index 020aef9d41..04645dcd12 100644 --- a/seed/challenges/03-front-end-libraries/react-and-redux.json +++ b/seed/challenges/03-front-end-libraries/react-and-redux.json @@ -50,7 +50,7 @@ }, "tests": [ "assert((function() { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); return mockedComponent.find('div').text() === '' })(), 'message: The DisplayMessages component should render an empty div element.');", - "getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/ /g,''); return noWhiteSpace.includes('constructor(props)') && noWhiteSpace.includes('super(props'); })(), 'message: The DisplayMessages constructor should be called properly with super, passing in props.');", + "getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/\\s/g,''); return noWhiteSpace.includes('constructor(props)') && noWhiteSpace.includes('super(props'); })(), 'message: The DisplayMessages constructor should be called properly with super, passing in props.');", "assert((function() { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const initialState = mockedComponent.state(); return typeof initialState === 'object' && initialState.input === '' && Array.isArray(initialState.messages) && initialState.messages.length === 0; })(), 'message: The DisplayMessages component should have an initial state equal to {input: \"\", messages: []}.');" ], "solutions": [ @@ -258,7 +258,7 @@ }, "tests": [ "assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('AppWrapper').length === 1; })(), 'message: The AppWrapper should render.');", - "getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return getUserInput('index').replace(/ /g,'').includes(''); })(), 'message: The Provider wrapper component should have a prop of store passed to it, equal to the Redux store.');", + "getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return getUserInput('index').replace(/\\s/g,'').includes(''); })(), 'message: The Provider wrapper component should have a prop of store passed to it, equal to the Redux store.');", "assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('AppWrapper').find('DisplayMessages').length === 1; })(), 'message: DisplayMessages should render as a child of AppWrapper.');", "assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('div').length === 1 && mockedComponent.find('h2').length === 1 && mockedComponent.find('button').length === 1 && mockedComponent.find('ul').length === 1; })(), 'message: The DisplayMessages component should render an h2, input, button, and ul element.');" ], diff --git a/seed/challenges/03-front-end-libraries/react.json b/seed/challenges/03-front-end-libraries/react.json index 6ee2923436..3eaca1d226 100644 --- a/seed/challenges/03-front-end-libraries/react.json +++ b/seed/challenges/03-front-end-libraries/react.json @@ -12,7 +12,7 @@ "src": "https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react-dom.js" } ], - "template": "
${ source }", + "template": "
${ source }", "challenges": [ { "id": "587d7dbc367417b2b2512bb1", @@ -143,11 +143,7 @@ "releasedOn": "December 25, 2017", "description": [ "So far, you've learned that JSX is a convenient tool to write readable HTML within JavaScript. With React, we can render this JSX directly to the HTML DOM using React's rendering API known as ReactDOM.", - "ReactDOM offers a simple method to render React elements to the DOM which looks like this: ReactDOM.render(componentToRender, targetNode).", - "
    ", - "
  • The first argument is the React element or component that you want to render.
  • ", - "
  • The second argument is the DOM node that you want to render the component within.
  • ", - "
", + "ReactDOM offers a simple method to render React elements to the DOM which looks like this: ReactDOM.render(componentToRender, targetNode), where the first argument is the React element or component that you want to render, and the second argument is the DOM node that you want to render the component to.", "As you would expect, ReactDOM.render() must be called after the JSX element declarations, just like how you must declare variables before using them.", "
", "The code editor has a simple JSX component. Use the ReactDOM.render() method to render this component to the page. You can pass defined JSX elements directly in as the first argument and use document.getElementById() to select the DOM node to render them to. There is a div with id='challenge-node' available for you to use. Make sure you don't change the JSX constant." @@ -166,8 +162,7 @@ ");", "// change code below this line", "" - ], - "tail": "ReactDOM.render(JSX, document.getElementById('root'))" + ] } }, "tests": [ @@ -251,9 +246,9 @@ " remove comment and change code above this line */}", " ", ");", - "", - "ReactDOM.render(JSX, document.getElementById('root'));" - ] + "" + ], + "tail": "ReactDOM.render(JSX, document.getElementById('root'))" } }, "tests": [ @@ -680,8 +675,7 @@ "", "// change code below this line", "" - ], - "tail": "ReactDOM.render(, document.getElementById('root'))" + ] } }, "tests": [ @@ -716,8 +710,7 @@ "contents": [ "// change code below this line", "" - ], - "tail": "ReactDOM.render(, document.getElementById('root'))" + ] } }, "tests": [ @@ -1129,8 +1122,8 @@ "tests": [ "assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find('CampSite').length === 1; })(), 'message: The CampSite component should render.');", "assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find('Camper').length === 1; })(), 'message: The Camper component should render.');", - "getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/ /g, '').replace(/\\r?\\n|\\r/g, ''); const verify1 = 'Camper.defaultProps={name:\\'CamperBot\\'}'; const verify2 = 'Camper.defaultProps={name:\"CamperBot\"}'; return (noWhiteSpace.includes(verify1) || noWhiteSpace.includes(verify2)); })(), 'message: The Camper component should include default props which assign the string CamperBot to the key name.');", - "getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); const noWhiteSpace = getUserInput('index').replace(/ /g, '').replace(/\\r?\\n|\\r/g, ''); const verifyDefaultProps = 'Camper.propTypes={name:PropTypes.string.isRequired'; return noWhiteSpace.includes(verifyDefaultProps); })(), 'message: The Camper component should include prop types which require the name prop to be of type string.');", + "getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/\\s/g, ''); const verify1 = 'Camper.defaultProps={name:\\'CamperBot\\'}'; const verify2 = 'Camper.defaultProps={name:\"CamperBot\"}'; return (noWhiteSpace.includes(verify1) || noWhiteSpace.includes(verify2)); })(), 'message: The Camper component should include default props which assign the string CamperBot to the key name.');", + "getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); const noWhiteSpace = getUserInput('index').replace(/\\s/g, ''); const verifyDefaultProps = 'Camper.propTypes={name:PropTypes.string.isRequired}'; return noWhiteSpace.includes(verifyDefaultProps); })(), 'message: The Camper component should include prop types which require the name prop to be of type string.');", "assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find('p').text() === mockedComponent.find('Camper').props().name; })(), 'message: The Camper component should contain a p element with only the text from the name prop.');" ], "solutions": [ @@ -1235,7 +1228,7 @@ "tests": [ "assert(Enzyme.mount(React.createElement(MyComponent)).state('name') === 'freeCodeCamp', 'message: MyComponent should have a key name with value freeCodeCamp stored in its state.');", "assert(/

.*<\\/h1><\\/div>/.test(Enzyme.mount(React.createElement(MyComponent)).html()), 'message: MyComponent should render an h1 header enclosed in a single div.');", - "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'TestName' }); return waitForIt(() => mockedComponent.html()) }; const firstValue = await first(); assert(firstValue === '

TestName

', 'message: The rendered h1 header should contain text rendered from the component's state.'); };" + "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'TestName' }); return waitForIt(() => mockedComponent.html()) }; const firstValue = await first(); assert(firstValue === '

TestName

', 'message: The rendered h1 header should contain text rendered from the component's state.');};" ], "solutions": [ "class MyComponent extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n name: 'freeCodeCamp'\n }\n }\n render() {\n return (\n
\n { /* change code below this line */ }\n

{this.state.name}

\n { /* change code above this line */ }\n
\n );\n }\n};" @@ -1289,7 +1282,7 @@ "assert(Enzyme.mount(React.createElement(MyComponent)).state('name') === 'freeCodeCamp', 'message: MyComponent should have a key name with value freeCodeCamp stored in its state.');", "assert(/

.*<\\/h1><\\/div>/.test(Enzyme.mount(React.createElement(MyComponent)).html()), 'message: MyComponent should render an h1 header enclosed in a single div.');", "getUserInput => assert(/

\\n*\\s*\\{\\s*name\\s*\\}\\s*\\n*<\\/h1>/.test(getUserInput('index')), 'message: The rendered h1 tag should include a reference to {name}.');", - "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'TestName' }); return waitForIt(() => mockedComponent.html()) }; const firstValue = await first(); assert(firstValue === '

TestName

', 'message: The rendered h1 header should contain text rendered from the component's state.'); };" + "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'TestName' }); return waitForIt(() => mockedComponent.html()) }; const firstValue = await first(); assert(firstValue === '

TestName

', 'message: The rendered h1 header should contain text rendered from the component's state.'); };" ], "solutions": [ "class MyComponent extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n name: 'freeCodeCamp'\n }\n }\n render() {\n // change code below this line\n const name = this.state.name;\n // change code above this line\n return (\n
\n { /* change code below this line */ }\n

{name}

\n { /* change code above this line */ }\n
\n );\n }\n};" @@ -1346,7 +1339,7 @@ "tests": [ "assert(Enzyme.mount(React.createElement(MyComponent)).state('name') === 'Initial State', 'message: The state of MyComponent should initialize with the key value pair { name: Initial State }.');", "assert(Enzyme.mount(React.createElement(MyComponent)).find('h1').length === 1, 'message: MyComponent should render an h1 header.');", - "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'TestName' }); return waitForIt(() => mockedComponent.html()); }; const firstValue = await first(); assert(/

TestName<\\/h1>/.test(firstValue), 'message: The rendered h1 header should contain text rendered from the component's state.'); };", + "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'TestName' }); return waitForIt(() => mockedComponent.html()); }; const firstValue = await first(); assert(/

TestName<\\/h1>/.test(firstValue), 'message: The rendered h1 header should contain text rendered from the component's state.'); };", "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'Before' }); return waitForIt(() => mockedComponent.state('name')); }; const second = () => { mockedComponent.setState({ name: 'React Rocks!' }); return waitForIt(() => mockedComponent.state('name')); }; const firstValue = await first(); const secondValue = await second(); assert(firstValue === 'Before' && secondValue === 'React Rocks!', 'message: Calling the handleClick method on MyComponent should set the name property in state to equal React Rocks!.'); }; " ], "solutions": [ @@ -1658,9 +1651,9 @@ "tests": [ "assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyForm)); return (mockedComponent.find('div').children().find('form').length === 1 && mockedComponent.find('div').children().find('h1').length === 1 && mockedComponent.find('form').children().find('input').length === 1 && mockedComponent.find('form').children().find('button').length === 1) })(), 'message: MyForm should return a div element which contains a form and an h1 tag. The form should include an input and a button.');", "assert(Enzyme.mount(React.createElement(MyForm)).state('input') === '' && Enzyme.mount(React.createElement(MyForm)).state('submit') === '', 'message: The state of MyForm should initialize with input and submit properties, both set to empty strings.');", - "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); return waitForIt(() => mockedComponent.state('input'))}; const _2 = () => { mockedComponent.find('input').simulate('change', { target: { value: 'TestInput' }}); return waitForIt(() => ({ state: mockedComponent.state('input'), inputVal: mockedComponent.find('input').props().value }))}; const before = await _1(); const after = await _2(); assert(before === '' && after.state === 'TestInput' && after.inputVal === 'TestInput', 'message: Typing in the input element should update the input property of the component's state.'); }; ", + "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); return waitForIt(() => mockedComponent.state('input'))}; const _2 = () => { mockedComponent.find('input').simulate('change', { target: { value: 'TestInput' }}); return waitForIt(() => ({ state: mockedComponent.state('input'), inputVal: mockedComponent.find('input').props().value }))}; const before = await _1(); const after = await _2(); assert(before === '' && after.state === 'TestInput' && after.inputVal === 'TestInput', 'message: Typing in the input element should update the input property of the component's state.'); }; ", "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); mockedComponent.setState({submit: ''}); mockedComponent.find('input').simulate('change', {target: {value: 'SubmitInput'}}); return waitForIt(() => mockedComponent.state('submit'))}; const _2 = () => { mockedComponent.find('form').simulate('submit'); return waitForIt(() => mockedComponent.state('submit'))}; const before = await _1(); const after = await _2(); assert(before === '' && after === 'SubmitInput', 'message: Submitting the form should run handleSubmit which should set the submit property in state equal to the current input.'); };", - "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); mockedComponent.setState({submit: ''}); mockedComponent.find('input').simulate('change', {target: {value: 'TestInput'}}); return waitForIt(() => mockedComponent.find('h1').text())}; const _2 = () => { mockedComponent.find('form').simulate('submit'); return waitForIt(() => mockedComponent.find('h1').text())}; const before = await _1(); const after = await _2(); assert(before === '' && after === 'TestInput', 'message: The h1 header should render the value of the submit field from the component's state.'); }; " + "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); mockedComponent.setState({submit: ''}); mockedComponent.find('input').simulate('change', {target: {value: 'TestInput'}}); return waitForIt(() => mockedComponent.find('h1').text())}; const _2 = () => { mockedComponent.find('form').simulate('submit'); return waitForIt(() => mockedComponent.find('h1').text())}; const before = await _1(); const after = await _2(); assert(before === '' && after === 'TestInput', 'message: The h1 header should render the value of the submit field from the component's state.'); }; " ], "solutions": [ "class MyForm extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n input: '',\n submit: ''\n };\n this.handleChange = this.handleChange.bind(this);\n this.handleSubmit = this.handleSubmit.bind(this);\n }\n handleChange(event) {\n this.setState({\n input: event.target.value\n });\n }\n handleSubmit(event) {\n event.preventDefault()\n this.setState({\n submit: this.state.input\n });\n }\n render() {\n return (\n
\n
\n \n \n \n

{this.state.submit}

\n
\n );\n }\n};" @@ -1739,7 +1732,7 @@ "description": [ "You can pass state as props to child components, but you're not limited to passing data. You can also pass handler functions or any method that's defined on a React component to a child component. This is how you allow child components to interact with their parent components. You pass methods to a child just like a regular prop. It's assigned a name and you have access to that method name under this.props in the child component.", "
", - "There are three components outlined in the code editor. The MyApp component is the parent that will render the GetInput and RenderInput child components. Add the GetInput component to the render method in MyApp, then pass it a prop called input assigned to inputValue from MyApp's state. Also create a prop called handleChange and pass the input handler handleChange to it.", + "There are three components outlined in the code editor. The MyApp component is the parent that will render the GetInput and RenderInput child components. Add the GetInput component to the render method in MyApp, then pass it a prop called input assigned to inputValue from MyApp's state. Also create a prop called handleChange and pass the input handler handleChange to it.", "Next, add RenderInput to the render method in MyApp, then create a prop called input and pass the inputValue from state to it. Once you are finished you will be able to type in the input field in the GetInput component, which then calls the handler method in its parent via props. This updates the input in the state of the parent, which is passed as props to both children. Observe how the data flows between the components and how the single source of truth remains the state of the parent component. Admittedly, this example is a bit contrived, but should serve to illustrate how data and callbacks can be passed between React components." ], "files": { @@ -1917,7 +1910,7 @@ "tests": [ "assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return (mockedComponent.find('div').length === 1 && mockedComponent.find('h1').length === 1); })(), 'message: MyComponent should render a div element which wraps an h1 tag.');", "assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return new RegExp('setTimeout(.|\\n)+setState(.|\\n)+activeUsers').test(String(mockedComponent.instance().componentDidMount)); })(), 'message: Component state should be updated with a timeout function in componentDidMount.');", - "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ activeUsers: 1237 }); return waitForIt(() => mockedComponent.find('h1').text()); }; const second = () => { mockedComponent.setState({ activeUsers: 1000 }); return waitForIt(() => mockedComponent.find('h1').text()); }; const firstValue = await first(); const secondValue = await second(); assert(new RegExp('1237').test(firstValue) && new RegExp('1000').test(secondValue), 'message: The h1 tag should render the activeUsers value from MyComponent's state.); }; " + "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ activeUsers: 1237 }); return waitForIt(() => mockedComponent.find('h1').text()); }; const second = () => { mockedComponent.setState({ activeUsers: 1000 }); return waitForIt(() => mockedComponent.find('h1').text()); }; const firstValue = await first(); const secondValue = await second(); assert(new RegExp('1237').test(firstValue) && new RegExp('1000').test(secondValue), 'message: The h1 tag should render the activeUsers value from MyComponent's state.'); }; " ], "solutions": [ "class MyComponent extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n activeUsers: null\n };\n }\n componentDidMount() {\n setTimeout( () => {\n this.setState({\n activeUsers: 1273\n });\n }, 2500);\n }\n render() {\n return (\n
\n

Active Users: {this.state.activeUsers}

\n
\n );\n }\n};" @@ -2340,9 +2333,9 @@ }, "tests": [ "assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).find('MagicEightBall').length, 1, 'message: The MagicEightBall compponent should exist and should render to the page.');", - "assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).children().childAt(0).name(), 'input', \"message: MagicEightBall's first child should be an input element.\");", - "assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).children().childAt(2).name(), 'button', \"message: MagicEightBall's third child should be a button element.\");", - "assert(Enzyme.mount(React.createElement(MagicEightBall)).state('randomIndex') === '' && Enzyme.mount(React.createElement(MagicEightBall)).state('userInput') === '', \"message: MagicEightBall's state should be initialized with a property of userInput and a property of randomIndex both set to a value of an empty string.\");", + "assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).children().childAt(0).name(), 'input', \"message: MagicEightBall's first child should be an input element.\");", + "assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).children().childAt(2).name(), 'button', \"message: MagicEightBall's third child should be a button element.\");", + "assert(Enzyme.mount(React.createElement(MagicEightBall)).state('randomIndex') === '' && Enzyme.mount(React.createElement(MagicEightBall)).state('userInput') === '', \"message: MagicEightBall's state should be initialized with a property of userInput and a property of randomIndex both set to a value of an empty string.\");", "assert(Enzyme.mount(React.createElement(MagicEightBall)).find('p').length === 1 && Enzyme.mount(React.createElement(MagicEightBall)).find('p').text() === '', 'message: When MagicEightBall is first mounted to the DOM, it should return an empty p element.');", "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MagicEightBall)); const simulate = () => { comp.find('input').simulate('change', { target: { value: 'test?' }}); comp.find('button').simulate('click'); }; const result = () => comp.find('p').text(); const _1 = () => { simulate(); return waitForIt(() => result()) }; const _2 = () => { simulate(); return waitForIt(() => result()) }; const _3 = () => { simulate(); return waitForIt(() => result()) }; const _4 = () => { simulate(); return waitForIt(() => result()) }; const _5 = () => { simulate(); return waitForIt(() => result()) }; const _6 = () => { simulate(); return waitForIt(() => result()) }; const _7 = () => { simulate(); return waitForIt(() => result()) }; const _8 = () => { simulate(); return waitForIt(() => result()) }; const _9 = () => { simulate(); return waitForIt(() => result()) }; const _10 = () => { simulate(); return waitForIt(() => result()) }; const _1_val = await _1(); const _2_val = await _2(); const _3_val = await _3(); const _4_val = await _4(); const _5_val = await _5(); const _6_val = await _6(); const _7_val = await _7(); const _8_val = await _8(); const _9_val = await _9(); const _10_val = await _10(); const actualAnswers = [_1_val, _2_val, _3_val, _4_val, _5_val, _6_val, _7_val, _8_val, _9_val, _10_val]; const hasIndex = actualAnswers.filter((answer, i) => possibleAnswers.indexOf(answer) !== -1); const notAllEqual = new Set(actualAnswers); assert(notAllEqual.size > 1 && hasIndex.length === 10, 'message: When text is entered into the input element and the button is clicked, the MagicEightBall compponent should return a p element that contains a random element from the possibleAnswers array.'); }; " ], @@ -2402,7 +2395,7 @@ "assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find('MyComponent').length === 1; })(), 'message: MyComponent should exist and render.');", "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: true}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(mockedComponent.find('div').length === 1 && mockedComponent.find('div').children().length === 2 && mockedComponent.find('button').length === 1 && mockedComponent.find('h1').length === 1, 'message: When display is set to true, a div, button, and h1 should render.'); }; ", "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: false}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(mockedComponent.find('div').length === 1 && mockedComponent.find('div').children().length === 1 && mockedComponent.find('button').length === 1 && mockedComponent.find('h1').length === 0, 'message: When display is set to false, only a div and button should render.'); }; ", - "getUserInput => assert(getUserInput('index').includes('if') === true && getUserInput('index').includes('else') === true, 'message: The render method should use an if/else statement to check the condition of this.state.display.');" + "getUserInput => assert(getUserInput('index').includes('if') && getUserInput('index').includes('else'), 'message: The render method should use an if/else statement to check the condition of this.state.display.');" ], "solutions": [ "class MyComponent extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n display: true\n }\n this.toggleDisplay = this.toggleDisplay.bind(this); \n }\n toggleDisplay() {\n this.setState({\n display: !this.state.display\n });\n }\n render() {\n // change code below this line\n if (this.state.display) {\n return (\n
\n \n

Displayed!

\n
\n );\n } else {\n return (\n
\n \n
\n );\n }\n }\n};" @@ -2460,7 +2453,7 @@ "assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find('MyComponent').length; })(), 'message: MyComponent should exist and render.');", "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: true}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(updated.find('div').length === 1 && updated.find('div').children().length === 2 && updated.find('button').length === 1 && updated.find('h1').length === 1, 'message: When display is set to true, a div, button, and h1 should render.'); }; ", "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: false}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(updated.find('div').length === 1 && updated.find('div').children().length === 1 && updated.find('button').length === 1 && updated.find('h1').length === 0, 'message: When display is set to false, only a div and button should render.'); }; ", - "getUserInput=> assert(getUserInput('index').includes('&&'), 'message: The render method should use the && logical operator to check the condition of this.state.display.');" + "getUserInput => assert(getUserInput('index').includes('&&'), 'message: The render method should use the && logical operator to check the condition of this.state.display.');" ], "solutions": [ "class MyComponent extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n display: true\n }\n this.toggleDisplay = this.toggleDisplay.bind(this); \n }\n toggleDisplay() {\n this.setState({\n display: !this.state.display\n });\n }\n render() {\n // change code below this line\n return (\n
\n \n {this.state.display &&

Displayed!

}\n
\n );\n }\n};" @@ -2538,10 +2531,10 @@ }, "tests": [ "assert(Enzyme.mount(React.createElement(CheckUserAge)).find('div').find('input').length === 1 && Enzyme.mount(React.createElement(CheckUserAge)).find('div').find('button').length === 1, 'message: The CheckUserAge component should render with a single input element and a single button element.');", - "assert(Enzyme.mount(React.createElement(CheckUserAge)).state().input === '' && Enzyme.mount(React.createElement(CheckUserAge)).state().userAge === '', \"message: The CheckUserAge component's state should be initialized with a property of userAge and a property of input, both set to a value of an empty string.\");", - "assert(Enzyme.mount(React.createElement(CheckUserAge)).find('button').text() === 'Submit', \"message: When the CheckUserAge component is first rendered to the DOM, the button's inner text should be Submit.\");", - "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const initialButton = mockedComponent.find('button').text(); const enter3AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 3 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const enter17AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 17 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const userAge3 = await enter3AndClickButton(); const userAge17 = await enter17AndClickButton(); assert(initialButton === 'Submit' && userAge3 === 'You Shall Not Pass' && userAge17 === 'You Shall Not Pass', 'message: When a number of less than 18 is entered into the input element and the button is clicked, the button's inner text should read You Shall Not Pass.); }; ", - "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const initialButton = mockedComponent.find('button').text(); const enter18AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 18 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const enter35AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 35 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const userAge18 = await enter18AndClickButton(); const userAge35 = await enter35AndClickButton(); assert(initialButton === 'Submit' && userAge18 === 'You May Enter' && userAge35 === 'You May Enter', 'message: When a number greater than or equal to 18 is entered into the input element and the button is clicked, the button's inner text should read You May Enter.); }; ", + "assert(Enzyme.mount(React.createElement(CheckUserAge)).state().input === '' && Enzyme.mount(React.createElement(CheckUserAge)).state().userAge === '', 'message: The CheckUserAge component's state should be initialized with a property of userAge and a property of input, both set to a value of an empty string.');", + "assert(Enzyme.mount(React.createElement(CheckUserAge)).find('button').text() === 'Submit', 'message: When the CheckUserAge component is first rendered to the DOM, the button's inner text should be Submit.');", + "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const initialButton = mockedComponent.find('button').text(); const enter3AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 3 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const enter17AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 17 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const userAge3 = await enter3AndClickButton(); const userAge17 = await enter17AndClickButton(); assert(initialButton === 'Submit' && userAge3 === 'You Shall Not Pass' && userAge17 === 'You Shall Not Pass', 'message: When a number of less than 18 is entered into the input element and the button is clicked, the button's inner text should read You Shall Not Pass.'); }; ", + "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const initialButton = mockedComponent.find('button').text(); const enter18AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 18 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const enter35AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 35 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const userAge18 = await enter18AndClickButton(); const userAge35 = await enter35AndClickButton(); assert(initialButton === 'Submit' && userAge18 === 'You May Enter' && userAge35 === 'You May Enter', 'message: When a number greater than or equal to 18 is entered into the input element and the button is clicked, the button's inner text should read You May Enter.'); }; ", "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const enter18AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 18 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const changeInputDontClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 5 }}); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const enter10AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 10 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const userAge18 = await enter18AndClickButton(); const changeInput1 = await changeInputDontClickButton(); const userAge10 = await enter10AndClickButton(); const changeInput2 = await changeInputDontClickButton(); assert(userAge18 === 'You May Enter' && changeInput1 === 'Submit' && userAge10 === 'You Shall Not Pass' && changeInput2 === 'Submit', 'message: Once a number has been submitted, and the value of the input is once again changed, the button should return to reading Submit.'); }; ", "assert(new RegExp(/(\\s|;)if(\\s|\\()/).test(Enzyme.mount(React.createElement(CheckUserAge)).instance().render.toString()) === false, 'message: Your code should not contain any if/else statements.');" ], @@ -2844,7 +2837,7 @@ "The map array method is a powerful tool that you will use often when working with React. Another method related to map is filter, which filters the contents of an array based on a condition, then returns a new array. For example, if you have an array of users that all have a property online which can be set to true or false, you can filter only those users that are online by writing:", "let onlineUsers = users.filter(user => user.online);", "
", - "In the code editor, MyComponent's state is initialized with an array of users. Some users are online and some aren't. Filter the array so you see only the users who are online. To do this, first use filter to return a new array containing only the users whose online property is true. Then, in the renderOnline variable, map over the filtered array, and return a li element for each user that contains the text of their username. Be sure to include a unique key as well, like in the last challenges." + "In the code editor, MyComponent's state is initialized with an array of users. Some users are online and some aren't. Filter the array so you see only the users who are online. To do this, first use filter to return a new array containing only the users whose online property is true. Then, in the renderOnline variable, map over the filtered array, and return a li element for each user that contains the text of their username. Be sure to include a unique key as well, like in the last challenges." ], "files": { "indexjsx": { @@ -2903,9 +2896,9 @@ }, "tests": [ "assert.strictEqual(Enzyme.mount(React.createElement(MyComponent)).find('MyComponent').length, 1, 'message: MyComponent should exist and render to the page.');", - "assert(Array.isArray(Enzyme.mount(React.createElement(MyComponent)).state('users')) === true && Enzyme.mount(React.createElement(MyComponent)).state('users').length === 6, \"message: MyComponent's state should be initialized to an array of six users.\");", + "assert(Array.isArray(Enzyme.mount(React.createElement(MyComponent)).state('users')) === true && Enzyme.mount(React.createElement(MyComponent)).state('users').length === 6, \"message: MyComponent's state should be initialized to an array of six users.\");", "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MyComponent)); const users = (bool) => ({users:[ { username: 'Jeff', online: bool }, { username: 'Alan', online: bool }, { username: 'Mary', online: bool }, { username: 'Jim', online: bool }, { username: 'Laura', online: bool } ]}); const result = () => comp.find('li').length; const _1 = result(); const _2 = () => { comp.setState(users(true)); return waitForIt(() => result()) }; const _3 = () => { comp.setState(users(false)); return waitForIt(() => result()) }; const _4 = () => { comp.setState({ users: [] }); return waitForIt(() => result()) }; const _2_val = await _2(); const _3_val = await _3(); const _4_val = await _4(); assert(comp.find('div').length === 1 && comp.find('h1').length === 1 && comp.find('ul').length === 1 && _1 === 4 && _2_val === 5 && _3_val === 0 && _4_val === 0, 'message: MyComponent should return a div, an h1, and then an unordered list containing li elements for every user whose online status is set to true.'); }; ", - "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MyComponent)); const users = (bool) => ({users:[ { username: 'Jeff', online: bool }, { username: 'Alan', online: bool }, { username: 'Mary', online: bool }, { username: 'Jim', online: bool }, { username: 'Laura', online: bool } ]}); const ul = () => { comp.setState(users(true)); return waitForIt(() => comp.find('ul').html()) }; const html = await ul(); assert(html === '
  • Jeff
  • Alan
  • Mary
  • Jim
  • Laura
, 'message: MyComponent should render li elements that contain the username of each online user.); }; ", + "async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MyComponent)); const users = (bool) => ({users:[ { username: 'Jeff', online: bool }, { username: 'Alan', online: bool }, { username: 'Mary', online: bool }, { username: 'Jim', online: bool }, { username: 'Laura', online: bool } ]}); const ul = () => { comp.setState(users(true)); return waitForIt(() => comp.find('ul').html()) }; const html = await ul(); assert(html === '
  • Jeff
  • Alan
  • Mary
  • Jim
  • Laura
, 'message: MyComponent should render li elements that contain the username of each online user.'); }; ", "assert((() => { const ul = Enzyme.mount(React.createElement(MyComponent)).find('ul'); console.log(ul.debug()); const keys = new Set([ ul.childAt(0).key(), ul.childAt(1).key(), ul.childAt(2).key(), ul.childAt(3).key() ]); return keys.size === 4; })(), 'message: Each list item element should have a unique key attribute.');" ], "solutions": [ diff --git a/seed/challenges/03-front-end-libraries/redux.json b/seed/challenges/03-front-end-libraries/redux.json index 61d69b4bdb..49fd798443 100644 --- a/seed/challenges/03-front-end-libraries/redux.json +++ b/seed/challenges/03-front-end-libraries/redux.json @@ -195,7 +195,7 @@ "tests": [ "assert(loginAction().type === 'LOGIN', 'message: Calling the function loginAction should return an object with type property set to the string LOGIN.');", "assert(store.getState().login === false, 'message: The store should be initialized with an object with property login set to false.');", - "getUserInput => assert((function() { let noWhiteSpace = getUserInput('index').replace(/ /g,''); return noWhiteSpace.includes('store.dispatch(loginAction())') || noWhiteSpace.includes('store.dispatch({type: \\'LOGIN\\'})') === true })(), 'message: The store.dispatch() method should be used to dispatch an action of type LOGIN.');" + "getUserInput => assert((function() { let noWhiteSpace = getUserInput('index').replace(/\\s/g,''); return noWhiteSpace.includes('store.dispatch(loginAction())') || noWhiteSpace.includes('store.dispatch({type: \\'LOGIN\\'})') === true })(), 'message: The store.dispatch() method should be used to dispatch an action of type LOGIN.');" ], "solutions": [ "const store = Redux.createStore(\n (state = {login: false}) => state\n);\n\nconst loginAction = () => {\n return {\n type: 'LOGIN'\n }\n};\n\n// Dispatch the action here:\nstore.dispatch(loginAction());" @@ -381,8 +381,8 @@ "assert((function() { const initialState = store.getState(); store.dispatch(loginUser()); const afterLogin = store.getState(); return initialState.authenticated === false && afterLogin.authenticated === true })(), 'message: Dispatching loginUser should update the login property in the store state to true.');", "assert((function() { store.dispatch(loginUser()); const loggedIn = store.getState(); store.dispatch(logoutUser()); const afterLogout = store.getState(); return loggedIn.authenticated === true && afterLogout.authenticated === false })(), 'message: Dispatching logoutUser should update the login property in the store state to false.');", "getUserInput => assert((function() { return typeof authReducer === 'function' && getUserInput('index').toString().includes('switch') && getUserInput('index').toString().includes('case') && getUserInput('index').toString().includes('default') })(), 'message: The authReducer function should handle multiple action types with a switch statement.');", - "getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').toString().replace(/ /g,''); return (noWhiteSpace.includes('constLOGIN=\\'LOGIN\\'') || noWhiteSpace.includes('constLOGIN=\"LOGIN\"')) && (noWhiteSpace.includes('constLOGOUT=\\'LOGOUT\\'') || noWhiteSpace.includes('constLOGOUT=\"LOGOUT\"')) })(), 'message: LOGIN and LOGOUT should be declared as const values and should be assigned strings of LOGINand LOGOUT.');", - "getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').toString().replace(/ /g,''); return noWhiteSpace.includes('caseLOGIN:') && noWhiteSpace.includes('caseLOGOUT:') && noWhiteSpace.includes('type:LOGIN') && noWhiteSpace.includes('type:LOGOUT') })(), 'message: The action creators and the reducer should reference the LOGIN and LOGOUT constants.');" + "getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').toString().replace(/\\s/g,''); return (noWhiteSpace.includes('constLOGIN=\\'LOGIN\\'') || noWhiteSpace.includes('constLOGIN=\"LOGIN\"')) && (noWhiteSpace.includes('constLOGOUT=\\'LOGOUT\\'') || noWhiteSpace.includes('constLOGOUT=\"LOGOUT\"')) })(), 'message: LOGIN and LOGOUT should be declared as const values and should be assigned strings of LOGINand LOGOUT.');", + "getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').toString().replace(/\\s/g,''); return noWhiteSpace.includes('caseLOGIN:') && noWhiteSpace.includes('caseLOGOUT:') && noWhiteSpace.includes('type:LOGIN') && noWhiteSpace.includes('type:LOGOUT') })(), 'message: The action creators and the reducer should reference the LOGIN and LOGOUT constants.');" ], "solutions": [ "const LOGIN = 'LOGIN';\nconst LOGOUT = 'LOGOUT';\n\nconst defaultState = {\n authenticated: false\n};\n\nconst authReducer = (state = defaultState, action) => {\n\n switch (action.type) {\n\n case LOGIN:\n return {\n authenticated: true\n }\n\n case LOGOUT:\n return {\n authenticated: false\n }\n\n default:\n return state;\n\n }\n\n};\n\nconst store = Redux.createStore(authReducer);\n\nconst loginUser = () => {\n return {\n type: LOGIN\n }\n};\n\nconst logoutUser = () => {\n return {\n type: LOGOUT\n }\n};" @@ -514,7 +514,7 @@ "assert((function() { const initalState = store.getState().count; store.dispatch({type: INCREMENT}); store.dispatch({type: INCREMENT}); const firstState = store.getState().count; store.dispatch({type: DECREMENT}); const secondState = store.getState().count; return firstState === initalState + 2 && secondState === firstState - 1 })(), 'message: The counterReducer should increment and decrement the state.');", "assert((function() { store.dispatch({type: LOGIN}); const loggedIn = store.getState().auth.authenticated; store.dispatch({type: LOGOUT}); const loggedOut = store.getState().auth.authenticated; return loggedIn === true && loggedOut === false })(), 'message: The authReducer should toggle the state of authenticated between true and false.');", "assert((function() { const state = store.getState(); return typeof state.auth === 'object' && typeof state.auth.authenticated === 'boolean' && typeof state.count === 'number' })(), 'message: The store state should have two keys: count, which holds a number, and auth, which holds an object. The auth object should have a property of authenticated, which holds a boolean.');", - "getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/ /g,''); return typeof rootReducer === 'function' && noWhiteSpace.includes('Redux.combineReducers') })(), 'message: The rootReducer should be a function that combines the counterReducer and the authReducer.');" + "getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/\\s/g,''); return typeof rootReducer === 'function' && noWhiteSpace.includes('Redux.combineReducers') })(), 'message: The rootReducer should be a function that combines the counterReducer and the authReducer.');" ], "solutions": [ "const INCREMENT = 'INCREMENT';\nconst DECREMENT = 'DECREMENT';\n\nconst counterReducer = (state = 0, action) => {\n switch(action.type) {\n case INCREMENT:\n return state + 1;\n case DECREMENT:\n return state - 1;\n default:\n return state;\n }\n};\n\nconst LOGIN = 'LOGIN';\nconst LOGOUT = 'LOGOUT';\n\nconst authReducer = (state = {authenticated: false}, action) => {\n switch(action.type) {\n case LOGIN:\n return {\n authenticated: true\n }\n case LOGOUT:\n return {\n authenticated: false\n }\n default:\n return state;\n }\n};\n\nconst rootReducer = Redux.combineReducers({\n count: counterReducer,\n auth: authReducer\n});\n\nconst store = Redux.createStore(rootReducer);" @@ -651,7 +651,7 @@ "assert(receivedData('data').type === RECEIVED_DATA, 'message: The receivedData action creator should return an object of type equal to the value of RECEIVED_DATA.');", "assert(typeof asyncDataReducer === 'function', 'message: asyncDataReducer should be a function.');", "assert((function() { const initialState = store.getState(); store.dispatch(requestingData()); const reqState = store.getState(); return initialState.fetching === false && reqState.fetching === true })(), 'message: Dispatching the requestingData action creator should update the store state property of fetching to true.');", - "assert((function() { const noWhiteSpace = handleAsync.toString().replace(/ /g,''); return noWhiteSpace.includes('dispatch(requestingData())') === true && noWhiteSpace.includes('dispatch(receivedData(data))') === true })(), 'message: Dispatching handleAsync should dispatch the data request action and then dispatch the received data action after a delay.');" + "assert((function() { const noWhiteSpace = handleAsync.toString().replace(/\\s/g,''); return noWhiteSpace.includes('dispatch(requestingData())') === true && noWhiteSpace.includes('dispatch(receivedData(data))') === true })(), 'message: Dispatching handleAsync should dispatch the data request action and then dispatch the received data action after a delay.');" ], "solutions": [ "const REQUESTING_DATA = 'REQUESTING_DATA'\nconst RECEIVED_DATA = 'RECEIVED_DATA'\n\nconst requestingData = () => { return {type: REQUESTING_DATA} }\nconst receivedData = (data) => { return {type: RECEIVED_DATA, users: data.users} }\n\nconst handleAsync = () => {\n return function(dispatch) {\n dispatch(requestingData());\n setTimeout(function() {\n let data = {\n users: ['Jeff', 'William', 'Alice']\n }\n dispatch(receivedData(data));\n }, 2500);\n }\n};\n\nconst defaultState = {\n fetching: false,\n users: []\n};\n\nconst asyncDataReducer = (state = defaultState, action) => {\n switch(action.type) {\n case REQUESTING_DATA:\n return {\n fetching: true,\n users: []\n }\n case RECEIVED_DATA:\n return {\n fetching: false,\n users: action.users\n }\n default:\n return state;\n }\n};\n\nconst store = Redux.createStore(\n asyncDataReducer,\n Redux.applyMiddleware(ReduxThunk.default)\n);" From 002e7d38c7b1e60a5cb2aa89bbfa0651e17970a8 Mon Sep 17 00:00:00 2001 From: Shane Farrar Date: Thu, 21 Dec 2017 01:24:59 -0500 Subject: [PATCH 006/108] fix(UX): corrected overflow of instruction content (#16236) --- common/app/Panes/Divider.jsx | 2 +- common/app/Panes/Pane.jsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/common/app/Panes/Divider.jsx b/common/app/Panes/Divider.jsx index a90fd88775..81787bb0f5 100644 --- a/common/app/Panes/Divider.jsx +++ b/common/app/Panes/Divider.jsx @@ -25,7 +25,7 @@ export function Divider({ left, dividerClicked }) { cursor: 'col-resize', height: '100%', left: left + '%', - marginLeft: '-4px', + marginLeft: '0px', position: 'absolute', right: 'auto', top: 0, diff --git a/common/app/Panes/Pane.jsx b/common/app/Panes/Pane.jsx index 15f95a4c64..b3c5dedc38 100644 --- a/common/app/Panes/Pane.jsx +++ b/common/app/Panes/Pane.jsx @@ -22,7 +22,9 @@ export function Pane({ overflowY: 'auto', position: 'absolute', right: right + '%', - top: 0 + top: 0, + paddingLeft: '4px', + paddingRight: '4px' }; return (
From 972466de1e8070f0b7c2bd88c12b1e5ac70b904c Mon Sep 17 00:00:00 2001 From: Zuzana Date: Thu, 21 Dec 2017 16:33:16 +0000 Subject: [PATCH 007/108] docs: Update to the contributing guidelines (#16225) --- CONTRIBUTING.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index da438914a9..27af9b4376 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,7 +40,7 @@ Working on your first Pull Request? You can learn how from this *free* series [H | ------------------------------------------- | ------- | | [MongoDB Community Server](https://docs.mongodb.com/manual/administration/install-community/) | `~ ^3` | | [MailHog](https://github.com/mailhog/MailHog) | `~ ^1` | -| [Node.js](http://nodejs.org) | `~ ^8` | +| [Node.js](http://nodejs.org) | `~ ^8.9.3` | | npm (comes with Node) | `~ ^5` | > _Updating to the latest releases is recommended_. @@ -188,12 +188,23 @@ Note: Not all keys are required, to run the app locally, however `MONGOHQ_URL` i You can leave the other keys as they are. Keep in mind if you want to use more services you'll have to get your own API keys for those services and edit those entries accordingly in the .env file. -Next you should setup MailHog, a local SMTP mail server that will catch all the outgoing freeCodeCamp messages generated locally. How you start up MailHog is dependent upon your OS, but here's an example for MacOS with Brew. +Next you should setup MailHog, a local SMTP mail server that will catch all the outgoing freeCodeCamp messages generated locally. How you start up MailHog is dependent upon your OS. + +Here is how to set up MailHog on macOS with [Homebrew](https://brew.sh/): ```bash +brew install mailhog brew services start mailhog ``` +Here is how to set up MailHog on Windows: + +Download the latest MailHog version from [MailHog's official repository](https://github.com/mailhog/MailHog/blob/master/docs/RELEASES.md). Click on the link for your Windows version (32 or 64 bit) and .exe file will be downloaded to your computer. + +Once it finishes downloading, click on the file. You will probably get a Windows firewall notification where you will have to allow access to MailHog. Once you do, a standard Windows command line prompt will open with MailHog already running. + +If you want to close MailHog, simply close the command prompt. To run it again, click on the same .exe file, there is no need to download a new one. + To access your MailHog inbox, open your browser and navigate to [http://localhost:8025](http://localhost:8025). For any other questions related to MailHog or for instructions on custom configurations, check out the [MailHog](https://github.com/mailhog/MailHog) repository. Now you will need to start MongoDB, and then seed the database, then you can start the application: From 5a18d1cf8091da919cd213017b55888ad83d320e Mon Sep 17 00:00:00 2001 From: Angel Eduardo Date: Thu, 21 Dec 2017 12:35:02 -0400 Subject: [PATCH 008/108] add tip for alt attribute for the add-images-to-your-website challenge (#16197) --- .../01-responsive-web-design/basic-html-and-html5.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/seed/challenges/01-responsive-web-design/basic-html-and-html5.json b/seed/challenges/01-responsive-web-design/basic-html-and-html5.json index 1a76b669fa..7d202abb09 100644 --- a/seed/challenges/01-responsive-web-design/basic-html-and-html5.json +++ b/seed/challenges/01-responsive-web-design/basic-html-and-html5.json @@ -619,6 +619,7 @@ "<img src=\"https://www.your-image-source.com/your-image.jpg\">", "Note that in most cases, img elements are self-closing.", "All img elements must have an alt attribute. The text inside an alt attribute is used for screen readers to improve accessibility and is displayed if the image fails to load.", + "Ideally the alt attribute should not contain special chars unless needed.", "Let's add an alt attribute to our img example above:", "<img src=\"https://www.your-image-source.com/your-image.jpg\" alt=\"Author standing on a beach with two thumbs up.\">", "
", @@ -2242,4 +2243,4 @@ "ru": {} } ] -} \ No newline at end of file +} From 7823c0dbe27ad854dac91b63ba8fce04e2d4e501 Mon Sep 17 00:00:00 2001 From: cpheimbach Date: Thu, 21 Dec 2017 18:44:39 +0000 Subject: [PATCH 009/108] feat(profile): Adds certificates to static profile path I added all boolean checks, buttons and routes of the new certificates to the view. (According to user.json) Closes #16246 --- server/views/account/show.jade | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/server/views/account/show.jade b/server/views/account/show.jade index 2f7f21a523..f666ffe2e1 100644 --- a/server/views/account/show.jade +++ b/server/views/account/show.jade @@ -56,6 +56,21 @@ block content if isBackEndCert .button-spacer a.btn.btn-primary.btn-block(href='/' + username + '/back-end-certification') View My Back End Development Certification + if isRespWebDesignCert + .button-spacer + a.btn.btn-primary.btn-block(href='/' + username + '/responsive-web-design-certification') View My Responsive Web Design Certification + if isFrontEndLibsCert + .button-spacer + a.btn.btn-primary.btn-block(href='/' + username + '/front-end-libraries-certification') View My Front End Libraries Certification + if isJsAlgoDataStructCert + .button-spacer + a.btn.btn-primary.btn-block(href='/' + username + '/javascript-algorithms-data-structures-certification') View My JavaScript Algorithms Data Structures Certification + if isApisMicroservicesCert + .button-spacer + a.btn.btn-primary.btn-block(href='/' + username + '/apis-microservices-certification') View My APIs Microservices Certification + if isInfosecQaCert + .button-spacer + a.btn.btn-primary.btn-block(href='/' + username + '/information-security-quality-assurance-certification') View My Information Sequrity Quality Assurance Certification if (user && user.username != username) .button-spacer a.btn.btn-primary.btn-block(href='/' + username + '/report-user/') Report this user's profile for abuse From 0cdf478f0ecb4c5eaaf8d5f96994b9707f509278 Mon Sep 17 00:00:00 2001 From: Ethan Arrowood Date: Thu, 21 Dec 2017 15:38:28 -0500 Subject: [PATCH 010/108] test(challenges): Test ES6 challenge (#16201) * test(challenges): Test ES6 challenge Added tests to 3rd ES6 challenge * test(challenges): ES6 challenges * test(challenges): ES6 chall c11-c15 * test(challenges): ES6 chall c16-c20 * test(challenges): ES6 chall c21-c27 * test(challenges): Refactor ES6 challenges Update tests to use getUserInput. Remove test for arrow function use Closes #16207 * test(challenges): Fix falsey case Add proper getUserInput syntax for !code.match tests Closes #16207 * test(challenges): QA ES6 Challenges QA and edit for ES6 challenges 1 - 18 Closes #16207 --- .../es6.json | 274 +++++++++--------- 1 file changed, 144 insertions(+), 130 deletions(-) diff --git a/seed/challenges/02-javascript-algorithms-and-data-structures/es6.json b/seed/challenges/02-javascript-algorithms-and-data-structures/es6.json index 1288c48591..d12880a8d9 100644 --- a/seed/challenges/02-javascript-algorithms-and-data-structures/es6.json +++ b/seed/challenges/02-javascript-algorithms-and-data-structures/es6.json @@ -38,17 +38,17 @@ "A new keyword called let was introduced in ES6 to solve the problems with the var keyword. With the let keyword, all the examples we just saw will cause an error to appear. We can no longer overwrite variables or use a variable before we declare it. Some modern browsers require you to add \"use strict\"; to the top of your code before you can use the new features of ES6.", "Let's try using the let keyword.", "
", - "Fix the code so that it only uses the let keyword and makes the errors go away.", - "Note
Remember to add \"use strict\"; to the top of your code." + "Fix the code so that it only uses the let keyword and makes the errors go away." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "var favorite = redNosedReindeer + \" is Santa's favorite reindeer.\";", "var redNosedReindeer = \"Rudolph\";", "var redNosedReindeer = \"Comet\";" ], "tests": [ "assert(redNosedReindeer === \"Rudolph\", 'message: redNosedReindeer should be Rudolph.');", - "assert(favorite === \"Rudolph is Santa's favorite reindeer.\", \"message: favorite should return Santa's favorite reindeer.\");" + "assert(favorite === \"Rudolph is Santa's favorite reindeer.\", 'message: favorite should return Santa's favorite reindeer.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -72,10 +72,10 @@ "i is not defined because it was not declared in the global scope. It is only declared within the for loop statement. printNumTwo() returned the correct value because three different i variables with unique values (0, 1, and 2) were created by the let keyword within the loop statement.", "
", "Fix the code so that i declared in the if statement is a separate variable than i declared in the first line of the function. Be certain not to use the var keyword anywhere in your code.", - "Note
Remember to add \"use strict\"; to the top of your code.", "This exercise is designed to illustrate the difference between how var and let keywords assign scope to the declared variable. When programming a function similar to the one used in this exercise, it is often better to use different variable names to avoid confusion." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "function checkScope() {", " var i = \"function scope\";", " if (true) {", @@ -90,7 +90,7 @@ ], "tests": [ "// TEMPORARILY COMMENTED OUT: assert(!/var/g.test(code) && /let/g.test(code), 'message: The var keyword should be replaced with let. (This test is temporarily disabled)');", - "assert(code.match(/(i\\s*=\\s*).*\\s*.*\\s*.*\\1('|\")block\\s*scope\\2/g), 'message: The variable i declared in the if statement should equal \"block scope\".');", + "getUserInput => assert(getUserInput('index').match(/(i\\s*=\\s*).*\\s*.*\\s*.*\\1('|\")block\\s*scope\\2/g), 'message: The variable i declared in the if statement should equal \"block scope\".');", "assert(checkScope() === \"function scope\", 'message: checkScope() should return \"function scope\"');" ], "type": "waypoint", @@ -107,12 +107,10 @@ "
\"use strict\"
const FAV_PET = \"Cats\";
FAV_PET = \"Dogs\"; // returns error
", "As you can see, trying to reassign a variable declared with const will throw an error. You should always name variables you don't want to reassign using the const keyword. This helps when you accidentally attempt to reassign a variable that is meant to stay constant. A common practice is to name your constants in all upper-cases and with an underscore to separate words (e.g. EXAMPLE_VARIABLE).", "
", - "Change the code so that all variables are declared using let or const. Use let when you want the variable to change, and const when you want the variable to remain constant. Also, rename variables declared with const to conform to common practices.", - "Note
Don't forget to add \"use strict\"; to the top of your code." + "Change the code so that all variables are declared using let or const. Use let when you want the variable to change, and const when you want the variable to remain constant. Also, rename variables declared with const to conform to common practices." ], - "challengeSeed": [ - "// change 'var' to 'let' or 'const'", - "// rename constant variables", + "challengeSeed": [ + "\"use strict\";", "var pi = 3.14;", "var radius = 10;", "var calculateCircumference = function(r) {", @@ -121,13 +119,15 @@ " return result;", "};", "// Test your code", + "console.log(calculateCircumference(radius));", + "radius = 5;", "console.log(calculateCircumference(radius));" ], "tests": [ - "// Test user replaced all var keyword", - "// Test PI is const", - "// Test calculateCircumference is const", - "// Test pi and calculateCircumference has been renamed" + "assert(!/var/g.test(code),'message: var does not exist in code.');", + "getUserInput => assert(getUserInput('index').match(/(const pi)/g), 'message: PI is const.');", + "getUserInput => assert(getUserInput('index').match(/(const calculateCircumference)/g), 'message: calculateCircumference is const.');", + "getUserInput => assert(getUserInput('index').match(/(let radius)/g), 'message: radius is let.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -144,10 +144,10 @@ "
\"use strict\";
const s = [5, 6, 7];
s = [1, 2, 3]; // throws error, trying to assign a const
s[2] = 45; // works just as it would with an array declared with var or let
console.log(s); // returns [5, 6, 45]
", "As you can see, you can mutate the object [5, 6, 7] itself and the variable s will still point to the altered array [5, 6, 45]. Like all arrays, the array elements in s are mutable, but because const was used, you cannot use the variable identifier s to point to a different array using the assignment operator.", "
", - "An array is declared as const s = [5, 7, 2]. Change the array to [2, 5, 7] using various element assignment.", - "Note
Don't forget to add \"use strict\"; to the top of your code." + "An array is declared as const s = [5, 7, 2]. Change the array to [2, 5, 7] using various element assignment." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "const s = [5, 7, 2];", "// change code below this line", "", @@ -158,9 +158,9 @@ "console.log(s);" ], "tests": [ - "assert(code.match(/const/g), 'message: Do not replace const keyword.');", - "assert(code.match(/const\\s+s/g), 'message: s is declared with const.');", - "assert(code.match(/const\\s+s\\s*?=\\s*?\\[\\s*?2\\s*?,\\s*?5\\s*?,\\s*?7\\s*?\\]\\s*?;/g), 'message: Do not change the original array declaration.');", + "getUserInput => assert(getUserInput('index').match(/const/g), 'message: Do not replace const keyword.');", + "getUserInput => assert(getUserInput('index').match(/const\\s+s/g), 'message: s is declared with const.');", + "getUserInput => assert(getUserInput('index').match(/const\\s+s\\s*=\\s*\\[\\s*5\\s*,\\s*7\\s*,\\s*2\\s*\\]\\s*;?/g), 'message: Do not change the original array declaration.');", "assert.deepEqual(s, [2, 5, 7], 'message: s should be equal to [2, 5, 7].');" ], "type": "waypoint", @@ -178,7 +178,8 @@ "
", "In this challenge you are going to use Object.freeze to prevent mathematical constants from changing. You need to freeze MATH_CONSTANTS object so that noone is able alter the value of PI or add any more properties to it." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "const MATH_CONSTANTS = {", " PI: 3.14", "};", @@ -191,9 +192,9 @@ "console.log(MATH_CONSTANTS.PI);// should show 3.14" ], "tests": [ - "// Do not replace const keyword.", - "// MATH_CONSTANTS is declared with const.", - "// Do not change original MATH_CONSTANTS", + "getUserInput => assert(getUserInput('index').match(/const/g), 'message: Do not replace const keyword.');", + "getUserInput => assert(getUserInput('index').match(/const\\s+MATH_CONSTANTS/g), 'message: MATH_CONSTANTS is declared with const.');", + "getUserInput => assert(getUserInput('index').match(/const\\s+MATH_CONSTANTS\\s+=\\s+{\\s+PI:\\s+3.14\\s+};/g), 'message: Do not change original MATH_CONSTANTS.');", "assert.deepEqual(MATH_CONSTANTS, {PI: 3.14}, 'message: MATH_CONSTANTS.PI should be equal to 3.14.');" ], "type": "waypoint", @@ -214,11 +215,10 @@ "
const myFunc= () => \"value\"
", "This code will still return value by default.", "
", - "Rewrite the function assigned to the variable magic which returns a new Date() to use arrow function syntax. Also make sure nothing is defined using the keyword var.", - "Note", - "Don't forget to use strict mode." + "Rewrite the function assigned to the variable magic which returns a new Date() to use arrow function syntax. Also make sure nothing is defined using the keyword var." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "// change code below this line", "var magic = function() {", " return new Date();", @@ -228,12 +228,11 @@ "console.log(magic());" ], "tests": [ - "// Test user did replace var keyword", - "// Test magic is const", - "// Test magic is a function", - "// Test magic() returns the correct date", - "// Test function keyword was not used", - "// Test arrow => was used" + "getUserInput => assert(!getUserInput('index').match(/var/g), 'message: User did replace var keyword.');", + "getUserInput => assert(getUserInput('index').match(/const\\s+magic/g), 'message: magic is const.');", + "assert(typeof magic === 'function', 'message: magic is a function.');", + "assert(magic().getDate() == new Date().getDate(), 'message: magic() returns correct date.');", + "getUserInput => assert(!getUserInput('index').match(/function/g), 'message: function keyword was not used.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -248,11 +247,10 @@ "
// doubles input value and returns it
const doubler = (item) => item * 2;
", "You can pass more than one argument into arrow functions as well.", "
", - "Rewrite the myConcat function which appends contents of arr2 to arr1 so that the function uses arrow function syntax.", - "Note", - "Don't forget to use strict mode." + "Rewrite the myConcat function which appends contents of arr2 to arr1 so that the function uses arrow function syntax." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "// change code below this line", "var myConcat = function(arr1, arr2) {", " return arr1.concat(arr2);", @@ -262,12 +260,11 @@ "console.log(myConcat([1, 2], [3, 4, 5]));" ], "tests": [ - "// Test user did replace var keyword", - "// Test myConcat is const", - "assert(typeof myConcat === \"function\", 'message: myConcat should be a function');", - "// Test myConcat() returns the correct array", - "// Test function keyword was not used", - "// Test arrow => was used" + "getUserInput => assert(!getUserInput('index').match(/var/g), 'message: User did replace var keyword.');", + "getUserInput => assert(getUserInput('index').match(/const\\s+myConcat/g), 'message: myConcat is const.');", + "assert(typeof myConcat === 'function', 'message: myConcat should be a function');", + "assert(() => { const a = myConcat([1], [2]); return a[0] == 1 && a[1] == 2; }, 'message: myConcat() returns the correct array');", + "getUserInput => assert(!getUserInput('index').match(/function/g), 'message: function keyword was not used.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -286,11 +283,10 @@ "
FBPosts.filter((post) => post.thumbnail !== null && post.shares > 100 && post.likes > 500)
", "This code is more succinct and accomplishes the same task with fewer lines of code.", "
", - "Use arrow function syntax to compute the square of only the positive integers (fractions are not integers) in the array realNumberArray and store the new array in the variable squaredIntegers.", - "Note", - "Don't forget to use strict mode." + "Use arrow function syntax to compute the square of only the positive integers (fractions are not integers) in the array realNumberArray and store the new array in the variable squaredIntegers." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "const realNumberArray = [4, 5.6, -9.8, 3.14, 42, 6, 8.34];", "// change code below this line", "var squaredIntegers = realNumberArray;", @@ -299,14 +295,13 @@ "console.log(squaredIntegers);" ], "tests": [ - "// Test user did replace var keyword", - "// Test squaredIntegers is const", + "getUserInput => assert(!getUserInput('index').match(/var/g), 'message: User did replace var keyword.');", + "getUserInput => assert(getUserInput('index').match(/const\\s+squaredIntegers/g), 'message: squaredIntegers is const.');", "assert(Array.isArray(squaredIntegers), 'message: squaredIntegers should be an array');", "assert(squaredIntegers[0] === 16 && squaredIntegers[1] === 1764 && squaredIntegers[2] === 36, 'message: squaredIntegers should be [16, 1764, 36]');", - "// Test function keyword was not used", - "// Test arrow => was used", - "assert(!code.match(/(for)|(while)/g), 'message: loop should not be used');", - "assert(code.match(/map/g) && code.match(/filter/g), 'message: map and filter should be used');" + "getUserInput => assert(!getUserInput('index').match(/function/g), 'message: function keyword was not used.');", + "getUserInput => assert(!getUserInput('index').match(/(for)|(while)/g), 'message: loop should not be used');", + "getUserInput => assert(getUserInput('index').match(/map|filter|reduce/g), 'message: map, filter, or reduce should be used');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -322,10 +317,10 @@ "
function greeting(name = \"Anonymous\") {
return \"Hello \" + name;
}
console.log(greeting(\"John\")); // Hello John
console.log(greeting()); // Hello Anonymous
", "The default parameter kicks in when the argument is not specified (it is undefined). As you can see in the example above, the parameter name will receive its default value \"Anonymous\" when you do not provide a value for the parameter. You can add default values for as many parameters as you want.", "
", - "Modify the function increment by adding default parameters so that it will add 1 to number if value is not specified.", - "Note
Don't forget to use strict mode." + "Modify the function increment by adding default parameters so that it will add 1 to number if value is not specified." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "function increment(number, value) {", " return number + value;", "}", @@ -333,9 +328,9 @@ "console.log(increment(5)); // returns NaN" ], "tests": [ - "assert(increment(5, 2) === 7, \"The result of increment(5, 2) should be 7\");", - "assert(increment(5) === 6, \"The result of increment(5) should be 6\");", - "// Test default parameter was used for 'value'" + "assert(increment(5, 2) === 7, 'message: The result of increment(5, 2) should be 7.');", + "assert(increment(5) === 6, 'message: The result of increment(5) should be 6.');", + "getUserInput => assert(getUserInput('index').match(/value\\s*=\\s*1/g), 'message: default parameter 1 was used for value.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -351,10 +346,10 @@ "
function howMany(...args) {
return \"You have passed \" + args.length + \" arguments.\";
}
console.log(howMany(0, 1, 2)); // You have passed 3 arguments
console.log(howMany(\"string\", null, [1, 2, 3], { })); // You have passed 4 arguments.
", "The rest operator eliminates the need to check the args array and allows us to apply map(), filter() and reduce() on the parameters array.", "
", - "Modify the function sum so that is uses the rest operator and it works in the same way with any number of parameters.", - "Note
Don't forget to use strict mode." + "Modify the function sum so that is uses the rest operator and it works in the same way with any number of parameters." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "function sum(x, y, z) {", " const array = [ x, y, z ];", " return array.reduce((a, b) => a + b, 0);", @@ -362,10 +357,11 @@ "console.log(sum(1, 2, 3)); // 6" ], "tests": [ - "assert(sum(0,1,2) === 3, 'The result of sum(0,1,2) should be 3');", - "assert(sum(1,2,3,4) === 10, 'The result of sum(1,2,3,4) should be 10');", - "assert(sum(5) === 5, 'The result of sum(5) should be 5');", - "assert(sum() === 0, 'The result of sum() should be 0');" + "assert(sum(0,1,2) === 3, 'message: The result of sum(0,1,2) should be 3');", + "assert(sum(1,2,3,4) === 10, 'message: The result of sum(1,2,3,4) should be 10');", + "assert(sum(5) === 5, 'message: The result of sum(5) should be 5');", + "assert(sum() === 0, 'message: The result of sum() should be 0');", + "getUserInput => assert(getUserInput('index').match(/function\\s+sum\\s*\\(\\s*...args\\s*\\)\\s*{/g), 'message: The sum function uses the ... spread operator on the args parameter.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -388,16 +384,16 @@ "
", "Copy all contents of arr1 into another array arr2 using the spread operator." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "const arr1 = ['JAN', 'FEB', 'MAR', 'APR', 'MAY'];", - "const arr2 = []; // change this line", - "arr1.push('JUN');", - "console.log(arr2); // arr2 should not be affected" + "const arr2 = [] // change this line", + "console.log(arr2);" ], "tests": [ - "// Test arr2 is correct copy of arr1", - "// Test arr1 has changed", - "// Test spread operator was used" + "assert(arr2.every((v, i) => v === arr1[i]), 'message: arr2 is correct copy of arr1.');", + "getUserInput => assert(getUserInput('index').match(/\\[\\s*...arr1\\s*\\]/g),'message: ... spread operator was used to duplicate arr1.');", + "assert((arr1, arr2) => {arr1.push('JUN'); return arr2.length < arr1.length},'message: arr2 remains unchanged when arr1 is changed.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -408,7 +404,7 @@ "id": "587d7b89367417b2b2512b49", "title": "Use Destructuring Assignment to Assign Variables from Objects", "description": [ - "We earlier saw how spread operator can effectively spread, or unpack, the contents of the array.", + "We saw earlier how spread operator can effectively spread, or unpack, the contents of the array.", "We can do something similar with objects as well. Destructuring assignment is special syntax for neatly assigning values taken directly from an object to variables.", "Consider the following ES5 code:", "
var voxel = {x: 3.6, y: 7.4, z: 6.54 };
var x = voxel.x; // x = 3.6
var y = voxel.y; // y = 7.4
var z = voxel.z; // z = 6.54
", @@ -418,18 +414,22 @@ "
const { x : a, y : b, z : c } = voxel // a = 3.6, b = 7.4, c = 6.54
", "You may read it as \"get the field x and copy the value into a,\" and so on.", "
", - "Use destructuring to obtain the length of the string greeting" + "Use destructuring to obtain the length of the string greeting, and assign the length to len" ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "const greeting = 'itadakimasu';", + "", "// change code below this line", "const length = 0; // change this", "// change code above this line", + "", "console.log(length); // should be using destructuring" ], "tests": [ - "// Test len is 11", - "// Test destructuring was used" + "assert(typeof len === 'number', 'message: variable len exists and is a number.');", + "assert(len === 11, 'message: len equals 11');", + "getUserInput => assert(getUserInput('index').match(/\\{\\s*length\\s*:\\s*len\\s*}\\s*=\\s*greeting/g),'message: destructuring was used');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -447,7 +447,8 @@ "
", "Use destructuring assignment to obtain max of forecast.tomorrow and assign it to maxOfTomorrow." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "const forecast = {", " today: { min: 72, max: 83 },", " tomorrow: { min: 73.3, max: 84.6 }", @@ -458,8 +459,8 @@ "console.log(maxOfTomorrow); // should be 84.6" ], "tests": [ - "// Test maxOfTomorrow to be 84.6", - "// Test destructuring was used" + "assert(maxOfTomorrow === 84.6, 'message: maxOfTomorrow equals 84.6');", + "getUserInput => assert(getUserInput('index').match(/\\{\\s*tomorrow\\s*:\\s*\\{\\s*max\\s*:\\s*maxOfTomorrow\\s*\\}\\s*\\}\\s*=\\s*forecast/g),'message: nested destructuring was used');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -480,7 +481,8 @@ "
", "Use destructuring assignment to swap the values of a and b so that a receives the value stored in b, and b receives the value stored in a." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "let a = 8, b = 6;", "// change code below this line", "", @@ -510,7 +512,8 @@ "
", "Use destructuring assignment with the rest operator to perform an effective Array.prototype.slice() so that arr is a sub-array of the original array source with the first two elements ommitted." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "const source = [1,2,3,4,5,6,7,8,9,10];", "// change code below this line", "const arr = source; // change this", @@ -519,10 +522,9 @@ "console.log(source); // should be [1,2,3,4,5,6,7,8,9,10];" ], "tests": [ - "// Test arr is [3,4,5,6,7,8,9,10];", - "// Test source is [1,2,3,4,5,6,7,8,9,10];", - "// Test destructuring was used", - "// Test slice was not used" + "assert(arr.every((v, i) => v === i + 3),'message: arr is [3,4,5,6,7,8,9,10]');", + "getUserInput => assert(getUserInput('index').match(/\\[\\s*\\w\\s*,\\s*\\w\\s*,\\s*...arr\\s*\\]/g),'message: destructuring was used.');", + "getUserInput => assert(!getUserInput('index').match(/Array.slice\\(\\)/g), 'message: Array.slice() was not used.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -543,7 +545,8 @@ "
", "Use destructuring assignment within the argument to the function half to send only max and min inside the function." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "const stats = {", " max: 56.78,", " standard_deviation: 4.34,", @@ -559,9 +562,9 @@ "console.log(half(stats)); // should be 28.015" ], "tests": [ - "// Test stats is an object", - "// Test half is 28.015", - "// Test destructuring was used" + "assert(typeof stats === 'object', 'message: stats is an object.');", + "assert(half(stats) === 28.015, 'message: half(stats) is 28.015');", + "getUserInput => assert(getUserInput('index').match(/\\(\\s*\\{\\s*\\w+\\s*,\\s*\\w+\\s*\\}\\s*\\)/g), 'message: destructuring was used.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -580,18 +583,19 @@ "Secondly, the example uses backticks (`), not quotes (' or \"), to wrap the string. Notice that the string is multi-line.", "This new way of creating strings gives you more flexibility to create robust strings.", "
", - "Use template literal syntax with backticks to display each entry of the result object's failure array. Each entry should be wrapped inside an li element with the class attribute text-warning." + "Use template literal syntax with backticks to display each entry of the result object's failure array. Each entry should be wrapped inside an li element with the class attribute text-warning, and listed within the resultDisplayArray." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "const result = {", " success: [\"max-length\", \"no-amd\", \"prefer-arrow-functions\"],", " failure: [\"no-var\", \"var-on-top\", \"linebreak\"],", " skipped: [\"id-blacklist\", \"no-dup-keys\"]", "};", "// change code below this line", - "const resultDisplay = null;", + "const resultDisplayArray = null;", "// change code above this line", - "console.log(resultDisplay);", + "console.log(resultDisplayArray);", "/**", " * should look like this", " *
  • no-var
  • ", @@ -600,9 +604,9 @@ " **/" ], "tests": [ - "// Test resultDisplay is a string", - "// Test resultDisplay is the desired output", - "// Test template strings were used" + "assert(typeof resultDisplayArray === 'object' && resultDisplayArray.length === 3, 'message: resultDisplayArray is a list containing result failure messages.');", + "assert(resultDisplayArray.every((v, i) => v === `
  • ${result.failure[i]}
  • `), 'message: resultDisplayArray is the desired output.');", + "getUserInput => assert(getUserInput('index').match(/\\`
  • \\$\\{v\\}<\\/li>\\`/g), 'message: Template strings were used');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -623,7 +627,8 @@ "
    ", "Use simple fields with object literals to create and return a Person object." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "// change code below this line", "const createPerson = (name, age, gender) => {", " return {", @@ -636,8 +641,8 @@ "console.log(createPerson(\"Zodiac Hasbro\", 56, \"male\")); // returns a proper object" ], "tests": [ - "// Test the output is {name: \"Zodiac Hasbro\", age: 56, gender: \"male\"}", - "// Test no : was present" + "assert(() => {const res={name:\"Zodiac Hasbro\",age:56,gender:\"male\"}; const person=createPerson(\"Zodiac Hasbro\", 56, \"male\"); return Object.keys(person).every(k => person[k] === res[k]);}, 'message: the output is {name: \"Zodiac Hasbro\", age: 56, gender: \"male\"}.');", + "getUserInput => assert(!getUserInput('index').match(/:/g), 'message: No : were used.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -655,7 +660,8 @@ "
    ", "Refactor the function setGear inside the object bicycle to use the shorthand syntax described above." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "// change code below this line", "const bicycle = {", " gear: 2,", @@ -668,8 +674,8 @@ "console.log(bicycle.gear);" ], "tests": [ - "// Test the output is Sending request to Yanoshi Mimoto", - "// Test no : was present" + "assert(() => { bicycle.setGear(48); return bicycle.gear === 48 }, 'message: setGear is a function and changes the gear variable.');", + "getUserInput => assert(!getUserInput('index').match(/:\\s*function\\s*\\(\\)/g), 'message: Declarative function was used.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -691,7 +697,8 @@ "Use class keyword and write a proper constructor to create the Vegetable class.", "The Vegetable lets you create a vegetable object, with a property name, to be passed to constructor." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "/* Alter code below this line */", "const Vegetable = undefined;", "/* Alter code above this line */", @@ -699,9 +706,9 @@ "console.log(carrot.name); // => should be 'carrot'" ], "tests": [ - "// Test the Vegetable is a class", - "// Test that class keyword was used", - "// Test that other objects could be created with the class" + "assert(typeof Vegetable === 'function' && typeof Vegetable.constructor === 'function', 'message: Vegetable is a class');", + "getUserInput => assert(getUserInput('index').match(/class/g),'message: class keyword was used.');", + "assert(() => {const a = new Vegetable(\"apple\"); return typeof a === 'object';},'message: Instances of Vegetable can be instantiated.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -722,13 +729,14 @@ "
    ", "Use class keyword to create a Thermostat class. The constructor accepts Farenheit temperature.", "Now create getter and setter in the class, to obtain the temperature in Celsius scale.", - "Remember that F = C * 9.0 / 5 + 32, where F is the value of temperature in Fahrenheit scale, and C is the value of the same temperature in Celsius scale", + "Remember that C = 5/9 * (F - 32) and F = C * 9.0 / 5 + 32, where F is the value of temperature in Fahrenheit scale, and C is the value of the same temperature in Celsius scale", "Note", "When you implement this, you would be tracking the temperature inside the class in one scale - either Fahrenheit or Celsius.", "This is the power of getter or setter - you are creating an API for another user, who would get the correct result, no matter which one you track.", "In other words, you are abstracting implementation details from the consumer." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "/* Alter code below this line */", "const Thermostat = undefined;", "/* Alter code above this line */", @@ -738,9 +746,9 @@ "temp = thermos.temperature; // 26 in C" ], "tests": [ - "// Test the Thermostat is a class", - "// Test that class keyword was used", - "// Test that other objects could be created with the class" + "assert(typeof Thermostat === 'function' && typeof Thermostat.constructor === 'function','message: Thermostat is a class');", + "getUserInput => assert(getUserInput('index').match(/class/g),'message: class keyword was used.');", + "assert(() => {const t = new Thermostat(32); return typeof t === 'object' && t.temperature === 0;}, 'message: Instances of Vegetable can be instantiated.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -758,16 +766,18 @@ "A description of the above code:", "
    import { function } from \"file_path_goes_here\"
    // We can also import variables the same way!
    ", "There are a few ways to write an import statement, but the above is a very common use-case.", - "Note
    the whitespace surrounding the function inside the curly braces is a best practice - it makes it easier to read the import statement.", - "Note
    The lessons in this section handle non-browser features. import, and the statements we introduce in the rest of these lessons, won't work on a browser directly, However, we can use various tools to create code out of this to make it work in browser.", + "Note
    The whitespace surrounding the function inside the curly braces is a best practice - it makes it easier to read the import statement.", + "Note
    The lessons in this section handle non-browser features. import, and the statements we introduce in the rest of these lessons, won't work on a browser directly. However, we can use various tools to create code out of this to make it work in browser.", + "Note
    In most cases, the file path requires a ./ before it; otherwise, node will look in the node_modules directory first trying to load it as a dependencie.", "
    ", "Add the appropriate import statement that will allow the current file to use the capitalizeString function. The file where this function lives is called \"string_functions\", and it is in the same directory as the current file." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "capitalizeString(\"hello!\");" ], "tests": [ - "assert(code.match(/import\\s+\\{\\s?capitalizeString\\s?\\}\\s+from\\s+\"string_functions\"/ig)" + "getUserInput => assert(getUserInput('index').match(/import\\s+\\{\\s?capitalizeString\\s?\\}\\s+from\\s+\"string_functions\"/g), 'message: valid import statement');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -787,13 +797,14 @@ "
    ", "Below are two variables that I want to make available for other files to use. Utilizing the first way I demonstrated export, export the two variables." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "const foo = \"bar\";", "const boo = \"far\";" ], "tests": [ - "assert(code.match(/export\\s+const\\s+foo\\s+=+\\s\"bar\"/ig))", - "assert(code.match(/export\\s+const\\s+boo\\s+=+\\s\"far\"/ig))" + "getUserInput => assert(getUserInput('index').match(/export\\s+const\\s+foo\\s+=+\\s\"bar\"/g), 'message: foo is exported.');", + "getUserInput => assert(getUserInput('index').match(/export\\s+const\\s+boo\\s+=+\\s\"far\"/g), 'message: bar is exported.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -809,16 +820,17 @@ "
    import * as myMathModule from \"math_functions\"
    myMathModule.add(2,3);
    myMathModule.subtract(5,3);
    ", "And breaking down that code:", "
    import * as object_with_name_of_your_choice from \"file_path_goes_here\"
    object_with_name_of_your_choice.imported_function
    ", - "You may use any name following the import * as portion of the statement. In order to utilize this method, it requires an object that receives the imported values. From here, you will use the dot notation to call your imported values.", + "You may use any name following the import * as portion of the statement. In order to utilize this method, it requires an object that receives the imported values. From here, you will use the dot notation to call your imported values.", "
    ", "The code below requires the contents of a file, \"capitalize_strings\", found in the same directory as it, imported. Add the appropriate import * statement to the top of the file, using the object provided." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "myStringModule.capitalize(\"foo\");", "myStringModule.lowercase(\"Foo\");" ], "tests": [ - "assert(code.match(/import\\s+\\*\\s+as\\s+myStringModule\\s+from\\s+\"capitalize_strings\"/ig))" + "getUserInput => assert(getUserInput('index').match(/import\\s+\\*\\s+as\\s+myStringModule\\s+from\\s+\"capitalize_strings\"/g), 'message: Properly uses import * as syntax.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -837,11 +849,12 @@ "
    ", "The following function should be the fallback value for the module. Please add the necessary code to do so." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "function subtract(x,y) {return x - y;}" ], "tests": [ - "assert(code.match(/export\\s+default\\s+function\\s+subtract\\(x,y\\)\\s+{return\\s+x\\s-\\s+y;}/ig))" + "getUserInput => assert(getUserInput('index').match(/export\\s+default\\s+function\\s+subtract\\(x,y\\)\\s+{return\\s+x\\s-\\s+y;}/g), 'message: Proper used of export fallback.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", @@ -859,11 +872,12 @@ "
    ", "In the following code, please import the default export, subtract, from the file \"math_functions\", found in the same directory as this file." ], - "challengeSeed": [ + "challengeSeed": [ + "\"use strict\";", "subtract(7,4);" ], "tests": [ - "assert(code.match(/import\\s+subtract\\s+from\\s+\"math_functions\"/ig))" + "getUserInput => assert(getUserInput('index').match(/import\\s+subtract\\s+from\\s+\"math_functions\"/g), 'message: Properly imports export default method.');" ], "type": "waypoint", "releasedOn": "Feb 17, 2017", From 8f6deff199952d9b14a8ceb26aeb00aa2f16fdaf Mon Sep 17 00:00:00 2001 From: mrugesh mohapatra Date: Fri, 22 Dec 2017 03:05:21 +0530 Subject: [PATCH 011/108] fix: Update text for GitHub and Settings (#16253) This commit adds back changes from the commit 9142aec8ad118fa4881a82a731e5d5c3ffc9752f Just updates the labels of some of the buttons --- common/app/routes/Settings/Social-Settings.jsx | 2 +- server/views/account/show.jade | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/app/routes/Settings/Social-Settings.jsx b/common/app/routes/Settings/Social-Settings.jsx index 33ed72dd59..2a2704961d 100644 --- a/common/app/routes/Settings/Social-Settings.jsx +++ b/common/app/routes/Settings/Social-Settings.jsx @@ -17,7 +17,7 @@ export default function SocialSettings({ }) { const githubCopy = isGithubCool ? 'Update my profile from GitHub' : - 'Link my GitHub to unlock my portfolio'; + 'Link my GitHub to enable my public profile'; const buttons = [
    ", + "

    Dragon curve

    ", + "", + "", + "", + "", + "'''Testing cases:'''", + "
    ",
    +        "Input parameters:",
    +        "",
    +        "ord scale x-shift y-shift color   [File name to save]",
    +        "-------------------------------------------",
    +        "11  7.    -265   -260   red       DC11.png",
    +        "15  2.    -205   -230   brown     DC15.png",
    +        "17  1.    -135    70    green     DC17.png",
    +        "19  0.6    380    440   navy      DC19.png",
    +        "21  0.22   1600   800   blue      DC21.png",
    +        "23  0.15   1100   800   violet    DC23.png",
    +        "25  0.07   2100   5400  darkgreen DC25.png",
    +        "===========================================",
    +        "
    ", + "", + "{{Output}} ", + "
    ",
    +        "Page with different plotted Dragon curves. Right-clicking on the canvas you can save each of them",
    +        "as a png-file. ",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e23", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var DRAGON = (function () {\n // MATRIX MATH\n // -----------\n\n var matrix = {\n mult: function ( m, v ) {\n return [ m[0][0] * v[0] + m[0][1] * v[1],\n m[1][0] * v[0] + m[1][1] * v[1] ];\n },\n\n minus: function ( a, b ) {\n return [ a[0]-b[0], a[1]-b[1] ];\n },\n\n plus: function ( a, b ) {\n return [ a[0]+b[0], a[1]+b[1] ];\n }\n };\n\n\n // SVG STUFF\n // ---------\n\n // Turn a pair of points into an SVG path like \"M1 1L2 2\".\n var toSVGpath = function (a, b) { // type system fail\n return \"M\" + a[0] + \" \" + a[1] + \"L\" + b[0] + \" \" + b[1];\n };\n\n\n // DRAGON MAKING\n // -------------\n\n // Make a dragon with a better fractal algorithm\n var fractalMakeDragon = function (svgid, ptA, ptC, state, lr, interval) {\n\n // make a new \n var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n path.setAttribute( \"class\", \"dragon\"); \n path.setAttribute( \"d\", toSVGpath(ptA, ptC) );\n\n // append the new path to the existing \n var svg = document.getElementById(svgid); // call could be eliminated\n svg.appendChild(path);\n\n // if we have more iterations to go...\n if (state > 1) {\n\n // make a new point, either to the left or right\n var growNewPoint = function (ptA, ptC, lr) {\n var left = [[ 1/2,-1/2 ], \n [ 1/2, 1/2 ]]; \n\n var right = [[ 1/2, 1/2 ],\n [-1/2, 1/2 ]];\n\n return matrix.plus(ptA, matrix.mult( lr ? left : right, \n matrix.minus(ptC, ptA) ));\n }; \n\n var ptB = growNewPoint(ptA, ptC, lr, state);\n\n // then recurse using each new line, one left, one right\n var recurse = function () {\n // when recursing deeper, delete this svg path\n svg.removeChild(path);\n\n // then invoke again for new pair, decrementing the state\n fractalMakeDragon(svgid, ptB, ptA, state-1, lr, interval);\n fractalMakeDragon(svgid, ptB, ptC, state-1, lr, interval);\n };\n\n window.setTimeout(recurse, interval);\n }\n };\n\n\n // Export these functions\n // ----------------------\n return {\n fractal: fractalMakeDragon\n\n // ARGUMENTS\n // ---------\n // svgid id of element\n // ptA first point [x,y] (from top left)\n // ptC second point [x,y]\n // state number indicating how many steps to recurse\n // lr true/false to make new point on left or right\n\n // CONFIG\n // ------\n // CSS rules should be made for the following\n // svg#fractal\n // svg path.dragon\n };\n\n}());\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Draw a clock", + "type": "Waypoint", + "description": [ + "Task:", + "

    Draw a clock.

    ", + "

    More specific:

    ", + "Draw a time keeping device. It can be a stopwatch, hourglass, sundial, a mouth counting \"one thousand and one\", anything. Only showing the seconds is required, e.g.: a watch with just a second hand will suffice. However, it must clearly change every second, and the change must cycle every so often (one minute, 30 seconds, etc.) It must be drawn; printing a string of numbers to your terminal doesn't qualify. Both text-based and graphical drawing are OK.", + "The clock is unlikely to be used to control space flights, so it needs not be hyper-accurate, but it should be usable, meaning if one can read the seconds off the clock, it must agree with the system clock.", + "A clock is rarely (never?) a major application: don't be a CPU hog and poll the system timer every microsecond, use a proper timer/signal/event from your system or language instead. For a bad example, many OpenGL programs update the frame-buffer in a busy loop even if no redraw is needed, which is very undesirable for this task.", + "A clock is rarely (never?) a major application: try to keep your code simple and to the point. Don't write something too elaborate or convoluted, instead do whatever is natural, concise and clear in your language.", + "Key points", + "animate simple object", + "timed event ", + "polling system resources ", + "code clarity" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Tested on Gecko. Put the following in a <script> tag somewhere, and call init_clock() after body load.", + "var sec_old = 0;", + "function update_clock() {", + "\tvar t = new Date();", + "\tvar arms = [t.getHours(), t.getMinutes(), t.getSeconds()];", + "\tif (arms[2] == sec_old) return;", + "\tsec_old = arms[2];", + "", + "\tvar c = document.getElementById('clock');", + "\tvar ctx = c.getContext('2d');", + "\tctx.fillStyle = \"rgb(0,200,200)\";", + "\tctx.fillRect(0, 0, c.width, c.height);", + "\tctx.fillStyle = \"white\";", + "\tctx.fillRect(3, 3, c.width - 6, c.height - 6);", + "\tctx.lineCap = 'round';", + "", + "\tvar orig = { x: c.width / 2, y: c.height / 2 };", + "\tarms[1] += arms[2] / 60;", + "\tarms[0] += arms[1] / 60;", + "\tdraw_arm(ctx, orig, arms[0] * 30, c.width/2.5 - 15, c.width / 20, \"green\");", + "\tdraw_arm(ctx, orig, arms[1] * 6, c.width/2.2 - 10, c.width / 30, \"navy\");", + "\tdraw_arm(ctx, orig, arms[2] * 6, c.width/2.0 - 6, c.width / 100, \"maroon\");", + "}", + "", + "function draw_arm(ctx, orig, deg, len, w, style)", + "{", + "\tctx.save();", + "\tctx.lineWidth = w;", + "\tctx.lineCap = 'round';", + "\tctx.translate(orig.x, orig.y);", + "\tctx.rotate((deg - 90) * Math.PI / 180);", + "\tctx.strokeStyle = style;", + "\tctx.beginPath();", + "\tctx.moveTo(-len / 10, 0);", + "\tctx.lineTo(len, 0);", + "\tctx.stroke();", + "\tctx.restore();", + "}", + "", + "function init_clock() {", + "\tvar clock = document.createElement('canvas');", + "\tclock.width = 100;", + "\tclock.height = 100;", + "\tclock.id = \"clock\";", + "\tdocument.body.appendChild(clock);", + "", + "\twindow.setInterval(update_clock, 200);", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e24", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var sec_old = 0;\nfunction update_clock() {\n\tvar t = new Date();\n\tvar arms = [t.getHours(), t.getMinutes(), t.getSeconds()];\n\tif (arms[2] == sec_old) return;\n\tsec_old = arms[2];\n\n\tvar c = document.getElementById('clock');\n\tvar ctx = c.getContext('2d');\n\tctx.fillStyle = \"rgb(0,200,200)\";\n\tctx.fillRect(0, 0, c.width, c.height);\n\tctx.fillStyle = \"white\";\n\tctx.fillRect(3, 3, c.width - 6, c.height - 6);\n\tctx.lineCap = 'round';\n\n\tvar orig = { x: c.width / 2, y: c.height / 2 };\n\tarms[1] += arms[2] / 60;\n\tarms[0] += arms[1] / 60;\n\tdraw_arm(ctx, orig, arms[0] * 30, c.width/2.5 - 15, c.width / 20, \"green\");\n\tdraw_arm(ctx, orig, arms[1] * 6, c.width/2.2 - 10, c.width / 30, \"navy\");\n\tdraw_arm(ctx, orig, arms[2] * 6, c.width/2.0 - 6, c.width / 100, \"maroon\");\n}\n\nfunction draw_arm(ctx, orig, deg, len, w, style)\n{\n\tctx.save();\n\tctx.lineWidth = w;\n\tctx.lineCap = 'round';\n\tctx.translate(orig.x, orig.y);\n\tctx.rotate((deg - 90) * Math.PI / 180);\n\tctx.strokeStyle = style;\n\tctx.beginPath();\n\tctx.moveTo(-len / 10, 0);\n\tctx.lineTo(len, 0);\n\tctx.stroke();\n\tctx.restore();\n}\n\nfunction init_clock() {\n\tvar clock = document.createElement('canvas');\n\tclock.width = 100;\n\tclock.height = 100;\n\tclock.id = \"clock\";\n\tdocument.body.appendChild(clock);\n\n\twindow.setInterval(update_clock, 200);\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Draw a cuboid", + "type": "Waypoint", + "description": [ + "Task:", + "

    Draw a cuboid with relative dimensions of 2x3x4. The cuboid can be represented graphically, or in ASCII art, depending on the language capabilities. To fulfill the criteria of being a cuboid, three faces must be visible.

    Either static or rotational projection is acceptable for this task.

    ", + "Related tasks", + "Draw a rotating cube" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e25", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Draw a rotating cube", + "type": "Waypoint", + "description": [ + "Task", + "

    Draw a rotating cube.

    It should be oriented with one vertex pointing straight up, and its opposite vertex on the main diagonal (the one farthest away) straight down. It can be solid or wire-frame, and you can use ASCII art if your language doesn't have graphical capabilities. Perspective is optional.

    ", + "Related tasks", + "Draw a cuboid" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e26", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Draw a sphere", + "type": "Waypoint", + "description": [ + "Task:", + "

    Draw a sphere.

    The sphere can be represented graphically, or in ASCII art, depending on the language capabilities.

    Either static or rotational projection is acceptable for this task.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "{{trans|C}}", + "", + "This Javascript entry uses an HTML wrapper to offer easy running and some interactivity. It is made as such, though, that the entire HTML wrapper can be removed (except for a canvas with id c) and still work. If you remove the HTML, call the draw_sphere function to draw the thing.", + "", + "", + "", + "", + "", + "Draw a sphere", + "", + "", + "", + "R=", + "
    ", + "k=", + "
    ", + "ambient=", + "
    ", + "Unsupportive browser...
    ", + "", + "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e27", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n\n\n\nDraw a sphere\n\n\n\nR=\n
    \nk=\n
    \nambient=\n
    \nUnsupportive browser...
    \n\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Dutch national flag problem", + "type": "Waypoint", + "description": [ + "

    The Dutch national flag is composed of three coloured bands in the order red then white and lastly blue. The problem posed by Edsger Dijkstra is:

    ", + "

    Given a number of red, blue and white balls in random order, arrange them in the order of the colours Dutch national flag.

    ", + "

    When the problem was first posed, Dijkstra then went on to successively refine a solution, minimising the number of swaps and the number of times the colour of a ball needed to determined and restricting the balls to end in an array, ...

    Task", + "Generate a randomized order of balls ensuring that they are not in the order of the Dutch national flag.", + "Sort the balls in a way idiomatic to your language.", + "Check the sorted balls are in the order of the Dutch national flag.C.f.:", + "Dutch national flag problem", + "Probabilistic analysis of algorithms for the Dutch national flag problem by Wei-Mei Chen. (pdf)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e28", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Dynamic variable names", + "type": "Waypoint", + "description": [ + "Task:", + "

    Create a variable with a user-defined name.

    The variable name should not be written in the program text, but should be taken from the user dynamically.

    ", + "See also", + " Eval in environment is a similar task." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "var varname = 'foo'; // pretend a user input that", + "var value = 42;", + "eval('var ' + varname + '=' + value);", + "Alternatively, without using eval:", + "var varname = prompt('Variable name:');", + "var value = 42;", + "this[varname] = value;", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e29", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var varname = 'foo'; // pretend a user input that\nvar value = 42;\neval('var ' + varname + '=' + value);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Euler's sum of powers conjecture", + "type": "Waypoint", + "description": [ + "

    There is a conjecture in mathematics that held for over two hundred years before it was disproved by the finding of a counterexample in 1966 by Lander and Parkin.

    ", + "Euler's (disproved) sum of powers conjecture:", + "

    At least k positive kth powers are required to sum to a kth power,

    ", + "

    except for the trivial case of one kth power: yk = yk

    Lander and Parkin are known to have used a brute-force search on a CDC 6600 computer restricting numbers to those less than 250.

    ", + "Task:", + "

    Write a program to search for an integer solution for:

    ", + "

    ", + "

    x05 + x15 + x25 + x35 == y5

    ", + "
    ", + "

    Where all xi's and y are distinct integers between 0 and 250 (exclusive).

    Show an answer here.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "var eulers_sum_of_powers = function (iMaxN) {", + "", + " var aPow5 = [];", + " var oPow5ToN = {};", + "", + " for (var iP = 0; iP <= iMaxN; iP++) {", + " var iPow5 = Math.pow(iP, 5);", + " aPow5.push(iPow5);", + " oPow5ToN[iPow5] = iP;", + " }", + "", + " for (var i0 = 1; i0 <= iMaxN; i0++) {", + " for (var i1 = 1; i1 <= i0; i1++) {", + " for (var i2 = 1; i2 <= i1; i2++) {", + " for (var i3 = 1; i3 <= i2; i3++) {", + " var iPow5Sum = aPow5[i0] + aPow5[i1] + aPow5[i2] + aPow5[i3];", + " if (typeof oPow5ToN[iPow5Sum] != 'undefined') {", + " return {", + " i0: i0,", + " i1: i1,", + " i2: i2,", + " i3: i3,", + " iSum: oPow5ToN[iPow5Sum]", + " };", + " }", + " }", + " }", + " }", + " }", + "", + "};", + "", + "var oResult = eulers_sum_of_powers(250);", + "", + "console.log(oResult.i0 + '^5 + ' + oResult.i1 + '^5 + ' + oResult.i2 +", + " '^5 + ' + oResult.i3 + '^5 = ' + oResult.iSum + '^5');", + "", + "{{Out}}", + " 133^5 + 110^5 + 84^5 + 27^5 = 144^5", + "'''This'''{{trans|D}} that verify: a^5 + b^5 + c^5 + d^5 = x^5", + "var N=1000, first=false", + "var ns={}, npv=[]", + "for (var n=0; n<=N; n++) {", + "\tvar np=Math.pow(n,5); ns[np]=n; npv.push(np)", + "}", + "loop:", + "for (var a=1; a<=N; a+=1) ", + "for (var b=a+1; b<=N; b+=1)", + "for (var c=b+1; c<=N; c+=1)", + "for (var d=c+1; d<=N; d+=1) {", + "\tvar x = ns[ npv[a]+npv[b]+npv[c]+npv[d] ]", + "\tif (!x) continue", + "\tprint( [a, b, c, d, x] )", + "\tif (first) break loop", + "}", + "function print(c) {", + "\tvar e='5', ep=e+' + '", + "\tdocument.write(c[0], ep, c[1], ep, c[2], ep, c[3], e, ' = ', c[4], e, '
    ')", + "}
    ", + "'''Or this'''{{trans|C}} that verify: a^5 + b^5 + c^5 + d^5 = x^5", + "var N=1000, first=false", + "var npv=[], M=30 // x^5 == x modulo M (=2*3*5) ", + "for (var n=0; n<=N; n+=1) npv[n]=Math.pow(n, 5)", + "var mx=1+npv[N]; while(n<=N+M) npv[n++]=mx", + "", + "loop:", + "for (var a=1; a<=N; a+=1)", + "for (var b=a+1; b<=N; b+=1)", + "for (var c=b+1; c<=N; c+=1)", + "for (var t=npv[a]+npv[b]+npv[c], d=c+1, x=t%M+d; (n=t+npv[d])d", + "\tif (npv[x] != n) continue", + "\tprint( [a, b, c, d, x] )", + "\tif (first) break loop;", + "}", + "function print(c) {", + "\tvar e='5', ep=e+' + '", + "\tdocument.write(c[0], ep, c[1], ep, c[2], ep, c[3], e, ' = ', c[4], e, '
    ')", + "}
    ", + "'''Or this'''{{trans|EchoLisp}} that verify: a^5 + b^5 + c^5 = x^5 - d^5", + "var N=1000, first=false", + "var dxs={}, pow=Math.pow ", + "for (var d=1; d<=N; d+=1)", + "\tfor (var dp=pow(d,5), x=d+1; x<=N; x+=1)", + "\t\tdxs[pow(x,5)-dp]=[d,x]", + "loop:", + "for (var a=1; a= dx[0]) continue", + "\tprint( [a, b, c].concat( dx ) ) ", + "\tif (first) break loop", + "}", + "function print(c) {", + "\tvar e='5', ep=e+' + '", + "\tdocument.write(c[0], ep, c[1], ep, c[2], ep, c[3], e, ' = ', c[4], e, '
    ')", + "}
    ", + "'''Or this'''{{trans|Python}} that verify: a^5 + b^5 = x^5 - (c^5 + d^5)", + "var N=1000, first=false", + "var is={}, ipv=[], ijs={}, ijpv=[], pow=Math.pow", + "for (var i=1; i<=N; i+=1) {", + "\tvar ip=pow(i,5); is[ip]=i; ipv.push(ip)", + "\tfor (var j=i+1; j<=N; j+=1) {", + "\t\tvar ijp=ip+pow(j,5); ijs[ijp]=[i,j]; ijpv.push(ijp)", + "\t} ", + "}", + "ijpv.sort( function (a,b) {return a - b } )", + "loop:", + "for (var i=0, ei=ipv.length; i= xp) break", + "\tvar cd = ijs[xp-cdp]", + "\tif (!cd) continue", + "\tvar ab = ijs[cdp]", + "\tif (ab[1] >= cd[0]) continue", + "\tprint( [].concat(ab, cd, is[xp]) )", + "\tif (first) break loop", + "}", + "function print(c) {", + "\tvar e='5', ep=e+' + '", + "\tdocument.write(c[0], ep, c[1], ep, c[2], ep, c[3], e, ' = ', c[4], e, '
    ')", + "}
    ", + "{{output}}", + " 275 + 845 + 1105 + 133 = 1445", + " 545 + 1685 + 2205 + 266 = 2885", + " 815 + 2525 + 3305 + 399 = 4325", + " 1085 + 3365 + 4405 + 532 = 5765", + " 1355 + 4205 + 5505 + 665 = 7205", + " 1625 + 5045 + 6605 + 798 = 8645", + "", + "===ES6===", + "(() => {", + " 'use strict';", + "", + " const eulersSumOfPowers = intMax => {", + " const", + " pow = Math.pow,", + " xs = range(0, intMax)", + " .map(x => pow(x, 5)),", + " dct = xs.reduce((a, x, i) =>", + " (a[x] = i,", + " a", + " ), {});", + "", + " for (let a = 1; a <= intMax; a++) {", + " for (let b = 2; b <= a; b++) {", + " for (let c = 3; c <= b; c++) {", + " for (let d = 4; d <= c; d++) {", + " const sumOfPower = dct[xs[a] + xs[b] + xs[c] + xs[d]];", + " if (sumOfPower !== undefined) {", + " return [a, b, c, d, sumOfPower];", + " }", + " }", + " }", + " }", + " }", + " return undefined;", + " };", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // TEST", + " const soln = eulersSumOfPowers(250);", + " return soln ? soln.slice(0, 4)", + " .map(x => `${x}^5`)", + " .join(' + ') + ` = ${soln[4]}^5` : 'No solution found.'", + "", + "})();", + "{{Out}}", + "
    133^5 + 110^5 + 84^5 + 27^5 = 144^5
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e38", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var eulers_sum_of_powers = function (iMaxN) {\n\n var aPow5 = [];\n var oPow5ToN = {};\n\n for (var iP = 0; iP <= iMaxN; iP++) {\n var iPow5 = Math.pow(iP, 5);\n aPow5.push(iPow5);\n oPow5ToN[iPow5] = iP;\n }\n\n for (var i0 = 1; i0 <= iMaxN; i0++) {\n for (var i1 = 1; i1 <= i0; i1++) {\n for (var i2 = 1; i2 <= i1; i2++) {\n for (var i3 = 1; i3 <= i2; i3++) {\n var iPow5Sum = aPow5[i0] + aPow5[i1] + aPow5[i2] + aPow5[i3];\n if (typeof oPow5ToN[iPow5Sum] != 'undefined') {\n return {\n i0: i0,\n i1: i1,\n i2: i2,\n i3: i3,\n iSum: oPow5ToN[iPow5Sum]\n };\n }\n }\n }\n }\n }\n\n};\n\nvar oResult = eulers_sum_of_powers(250);\n\nconsole.log(oResult.i0 + '^5 + ' + oResult.i1 + '^5 + ' + oResult.i2 +\n '^5 + ' + oResult.i3 + '^5 = ' + oResult.iSum + '^5');\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Evolutionary algorithm", + "type": "Waypoint", + "description": [ + "

    Starting with:

    ", + "The target string: \"METHINKS IT IS LIKE A WEASEL\".", + "An array of random characters chosen from the set of upper-case letters together with the space, and of the same length as the target string. (Call it the parent).", + "A fitness function that computes the ‘closeness’ of its argument to the target string.", + "A mutate function that given a string and a mutation rate returns a copy of the string, with some characters probably mutated.", + "While the parent is not yet the target:* copy the parent C times, each time allowing some random probability that another character might be substituted using mutate.", + "

    * Assess the fitness of the parent and all the copies to the target and make the most fit string the new parent, discarding the others.

    ", + "

    * repeat until the parent converges, (hopefully), to the target.

    ", + "See also:", + " Weasel algorithm.", + " Evolutionary algorithm.", + "

    Note: to aid comparison, try and ensure the variables and functions mentioned in the task description appear in solutions

    ", + "

    A cursory examination of a few of the solutions reveals that the instructions have not been followed rigorously in some solutions. Specifically,

    ", + "While the parent is not yet the target:* copy the parent C times, each time allowing some random probability that another character might be substituted using mutate.

    Note that some of the the solutions given retain characters in the mutated string that are correct in the target string. However, the instruction above does not state to retain any of the characters while performing the mutation. Although some may believe to do so is implied from the use of \"converges\"

    (:* repeat until the parent converges, (hopefully), to the target.

    Strictly speaking, the new parent should be selected from the new pool of mutations, and then the new parent used to generate the next set of mutations with parent characters getting retained only by not being mutated. It then becomes possible that the new set of mutations has no member that is fitter than the parent!

    As illustration of this error, the code for 8th has the following remark.

    Create a new string based on the TOS, '''changing randomly any characters which

    ", + "

    don't already match the target''':

    NOTE: this has been changed, the 8th version is completely random now

    Clearly, this algo will be applying the mutation function only to the parent characters that don't match to the target characters!

    To ensure that the new parent is never less fit than the prior parent, both the parent and all of the latest mutations are subjected to the fitness test to select the next parent.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Using cross-browser techniques to support Array.reduce and Array.map", + "", + "// ------------------------------------- Cross-browser Compatibility -------------------------------------", + "", + "/* Compatibility code to reduce an array", + " * Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/Reduce", + " */", + "if (!Array.prototype.reduce) {", + " Array.prototype.reduce = function (fun /*, initialValue */ ) {", + " \"use strict\";", + "", + " if (this === void 0 || this === null) throw new TypeError();", + "", + " var t = Object(this);", + " var len = t.length >>> 0;", + " if (typeof fun !== \"function\") throw new TypeError();", + "", + " // no value to return if no initial value and an empty array", + " if (len == 0 && arguments.length == 1) throw new TypeError();", + "", + " var k = 0;", + " var accumulator;", + " if (arguments.length >= 2) {", + " accumulator = arguments[1];", + " } else {", + " do {", + " if (k in t) {", + " accumulator = t[k++];", + " break;", + " }", + "", + " // if array contains no values, no initial value to return", + " if (++k >= len) throw new TypeError();", + " }", + " while (true);", + " }", + "", + " while (k < len) {", + " if (k in t) accumulator = fun.call(undefined, accumulator, t[k], k, t);", + " k++;", + " }", + "", + " return accumulator;", + " };", + "}", + "", + "/* Compatibility code to map an array", + " * Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/Map", + " */", + "if (!Array.prototype.map) {", + " Array.prototype.map = function (fun /*, thisp */ ) {", + " \"use strict\";", + "", + " if (this === void 0 || this === null) throw new TypeError();", + "", + " var t = Object(this);", + " var len = t.length >>> 0;", + " if (typeof fun !== \"function\") throw new TypeError();", + "", + " var res = new Array(len);", + " var thisp = arguments[1];", + " for (var i = 0; i < len; i++) {", + " if (i in t) res[i] = fun.call(thisp, t[i], i, t);", + " }", + "", + " return res;", + " };", + "}", + "", + "/* ------------------------------------- Generator -------------------------------------", + " * Generates a fixed length gene sequence via a gene strategy object.", + " * The gene strategy object must have two functions:", + " *\t- \"create\": returns create a new gene ", + " *\t- \"mutate(existingGene)\": returns mutation of an existing gene ", + " */", + "function Generator(length, mutationRate, geneStrategy) {", + " this.size = length;", + " this.mutationRate = mutationRate;", + " this.geneStrategy = geneStrategy;", + "}", + "", + "Generator.prototype.spawn = function () {", + " var genes = [],", + " x;", + " for (x = 0; x < this.size; x += 1) {", + " genes.push(this.geneStrategy.create());", + " }", + " return genes;", + "};", + "", + "Generator.prototype.mutate = function (parent) {", + " return parent.map(function (char) {", + " if (Math.random() > this.mutationRate) {", + " return char;", + " }", + " return this.geneStrategy.mutate(char);", + " }, this);", + "};", + "", + "/* ------------------------------------- Population -------------------------------------", + " * Helper class that holds and spawns a new population.", + " */", + "function Population(size, generator) {", + " this.size = size;", + " this.generator = generator;", + "", + " this.population = [];", + " // Build initial popuation;", + " for (var x = 0; x < this.size; x += 1) {", + " this.population.push(this.generator.spawn());", + " }", + "}", + "", + "Population.prototype.spawn = function (parent) {", + " this.population = [];", + " for (var x = 0; x < this.size; x += 1) {", + " this.population.push(this.generator.mutate(parent));", + " }", + "};", + "", + "/* ------------------------------------- Evolver -------------------------------------", + " * Attempts to converge a population based a fitness strategy object.", + " * The fitness strategy object must have three function ", + " *\t- \"score(individual)\": returns a score for an individual.", + " *\t- \"compare(scoreA, scoreB)\": return true if scoreA is better (ie more fit) then scoreB", + " *\t- \"done( score )\": return true if score is acceptable (ie we have successfully converged). ", + " */", + "function Evolver(size, generator, fitness) {", + " this.done = false;", + " this.fitness = fitness;", + " this.population = new Population(size, generator);", + "}", + "", + "Evolver.prototype.getFittest = function () {", + " return this.population.population.reduce(function (best, individual) {", + " var currentScore = this.fitness.score(individual);", + " if (best === null || this.fitness.compare(currentScore, best.score)) {", + " return {", + " score: currentScore,", + " individual: individual", + " };", + " } else {", + " return best;", + " }", + " }, null);", + "};", + "", + "Evolver.prototype.doGeneration = function () {", + " this.fittest = this.getFittest();", + " this.done = this.fitness.done(this.fittest.score);", + " if (!this.done) {", + " this.population.spawn(this.fittest.individual);", + " }", + "};", + "", + "Evolver.prototype.run = function (onCheckpoint, checkPointFrequency) {", + " checkPointFrequency = checkPointFrequency || 10; // Default to Checkpoints every 10 generations", + " var generation = 0;", + " while (!this.done) {", + " this.doGeneration();", + " if (generation % checkPointFrequency === 0) {", + " onCheckpoint(generation, this.fittest);", + " }", + " generation += 1;", + " }", + " onCheckpoint(generation, this.fittest);", + " return this.fittest;", + "};", + "", + "// ------------------------------------- Exports -------------------------------------", + "window.Generator = Generator;", + "window.Evolver = Evolver;", + "", + "", + "// helper utitlity to combine elements of two arrays.", + "Array.prototype.zip = function (b, func) {", + " var result = [],", + " max = Math.max(this.length, b.length),", + " x;", + " for (x = 0; x < max; x += 1) {", + " result.push(func(this[x], b[x]));", + " }", + " return result;", + "};", + "", + "var target = \"METHINKS IT IS LIKE A WEASEL\", geneStrategy, fitness, target, generator, evolver, result;", + " ", + "geneStrategy = {", + " // The allowed character set (as an array) ", + " characterSet: \"ABCDEFGHIJKLMNOPQRSTUVWXYZ \".split(\"\"),", + "", + " /*", + " Pick a random character from the characterSet", + " */", + " create: function getRandomGene() {", + " var randomNumber = Math.floor(Math.random() * this.characterSet.length);", + " return this.characterSet[randomNumber];", + " }", + "};", + "geneStrategy.mutate = geneStrategy.create; // Our mutation stragtegy is to simply get a random gene", + "fitness = {", + " // The target (as an array of characters)", + " target: target.split(\"\"),", + " equal: function (geneA, geneB) {", + " return (geneA === geneB ? 0 : 1);", + " },", + " sum: function (runningTotal, value) {", + " return runningTotal + value;", + " },", + "", + " /*", + " We give one point to for each corect letter", + " */", + " score: function (genes) {", + " var diff = genes.zip(this.target, this.equal); // create an array of ones and zeros ", + " return diff.reduce(this.sum, 0); // Sum the array values together.", + " },", + " compare: function (scoreA, scoreB) {", + " return scoreA <= scoreB; // Lower scores are better", + " },", + " done: function (score) {", + " return score === 0; // We have matched the target string.", + " }", + "};", + "", + "generator = new Generator(target.length, 0.05, geneStrategy);", + "evolver = new Evolver(100, generator, fitness);", + "", + "function showProgress(generation, fittest) {", + " document.write(\"Generation: \" + generation + \", Best: \" + fittest.individual.join(\"\") + \", fitness:\" + fittest.score + \"
    \");", + "}", + "result = evolver.run(showProgress);
    ", + "Output:", + "
    ",
    +        "Generation: 0, Best: KSTFOKJC XZYLWCLLGYZJNXYEGHE, fitness:25",
    +        "Generation: 10, Best: KOTFINJC XX LS LIGYZT WEPSHL, fitness:14",
    +        "Generation: 20, Best: KBTHINKS BT LS LIGNZA WEPSEL, fitness:8",
    +        "Generation: 30, Best: KETHINKS IT BS LISNZA WEASEL, fitness:5",
    +        "Generation: 40, Best: KETHINKS IT IS LIKEZA WEASEL, fitness:2",
    +        "Generation: 50, Best: METHINKS IT IS LIKEZA WEASEL, fitness:1",
    +        "Generation: 52, Best: METHINKS IT IS LIKE A WEASEL, fitness:0",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e3c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// ------------------------------------- Cross-browser Compatibility -------------------------------------\n\n/* Compatibility code to reduce an array\n * Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/Reduce\n */\nif (!Array.prototype.reduce) {\n Array.prototype.reduce = function (fun /*, initialValue */ ) {\n \"use strict\";\n\n if (this === void 0 || this === null) throw new TypeError();\n\n var t = Object(this);\n var len = t.length >>> 0;\n if (typeof fun !== \"function\") throw new TypeError();\n\n // no value to return if no initial value and an empty array\n if (len == 0 && arguments.length == 1) throw new TypeError();\n\n var k = 0;\n var accumulator;\n if (arguments.length >= 2) {\n accumulator = arguments[1];\n } else {\n do {\n if (k in t) {\n accumulator = t[k++];\n break;\n }\n\n // if array contains no values, no initial value to return\n if (++k >= len) throw new TypeError();\n }\n while (true);\n }\n\n while (k < len) {\n if (k in t) accumulator = fun.call(undefined, accumulator, t[k], k, t);\n k++;\n }\n\n return accumulator;\n };\n}\n\n/* Compatibility code to map an array\n * Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/Map\n */\nif (!Array.prototype.map) {\n Array.prototype.map = function (fun /*, thisp */ ) {\n \"use strict\";\n\n if (this === void 0 || this === null) throw new TypeError();\n\n var t = Object(this);\n var len = t.length >>> 0;\n if (typeof fun !== \"function\") throw new TypeError();\n\n var res = new Array(len);\n var thisp = arguments[1];\n for (var i = 0; i < len; i++) {\n if (i in t) res[i] = fun.call(thisp, t[i], i, t);\n }\n\n return res;\n };\n}\n\n/* ------------------------------------- Generator -------------------------------------\n * Generates a fixed length gene sequence via a gene strategy object.\n * The gene strategy object must have two functions:\n *\t- \"create\": returns create a new gene \n *\t- \"mutate(existingGene)\": returns mutation of an existing gene \n */\nfunction Generator(length, mutationRate, geneStrategy) {\n this.size = length;\n this.mutationRate = mutationRate;\n this.geneStrategy = geneStrategy;\n}\n\nGenerator.prototype.spawn = function () {\n var genes = [],\n x;\n for (x = 0; x < this.size; x += 1) {\n genes.push(this.geneStrategy.create());\n }\n return genes;\n};\n\nGenerator.prototype.mutate = function (parent) {\n return parent.map(function (char) {\n if (Math.random() > this.mutationRate) {\n return char;\n }\n return this.geneStrategy.mutate(char);\n }, this);\n};\n\n/* ------------------------------------- Population -------------------------------------\n * Helper class that holds and spawns a new population.\n */\nfunction Population(size, generator) {\n this.size = size;\n this.generator = generator;\n\n this.population = [];\n // Build initial popuation;\n for (var x = 0; x < this.size; x += 1) {\n this.population.push(this.generator.spawn());\n }\n}\n\nPopulation.prototype.spawn = function (parent) {\n this.population = [];\n for (var x = 0; x < this.size; x += 1) {\n this.population.push(this.generator.mutate(parent));\n }\n};\n\n/* ------------------------------------- Evolver -------------------------------------\n * Attempts to converge a population based a fitness strategy object.\n * The fitness strategy object must have three function \n *\t- \"score(individual)\": returns a score for an individual.\n *\t- \"compare(scoreA, scoreB)\": return true if scoreA is better (ie more fit) then scoreB\n *\t- \"done( score )\": return true if score is acceptable (ie we have successfully converged). \n */\nfunction Evolver(size, generator, fitness) {\n this.done = false;\n this.fitness = fitness;\n this.population = new Population(size, generator);\n}\n\nEvolver.prototype.getFittest = function () {\n return this.population.population.reduce(function (best, individual) {\n var currentScore = this.fitness.score(individual);\n if (best === null || this.fitness.compare(currentScore, best.score)) {\n return {\n score: currentScore,\n individual: individual\n };\n } else {\n return best;\n }\n }, null);\n};\n\nEvolver.prototype.doGeneration = function () {\n this.fittest = this.getFittest();\n this.done = this.fitness.done(this.fittest.score);\n if (!this.done) {\n this.population.spawn(this.fittest.individual);\n }\n};\n\nEvolver.prototype.run = function (onCheckpoint, checkPointFrequency) {\n checkPointFrequency = checkPointFrequency || 10; // Default to Checkpoints every 10 generations\n var generation = 0;\n while (!this.done) {\n this.doGeneration();\n if (generation % checkPointFrequency === 0) {\n onCheckpoint(generation, this.fittest);\n }\n generation += 1;\n }\n onCheckpoint(generation, this.fittest);\n return this.fittest;\n};\n\n// ------------------------------------- Exports -------------------------------------\nwindow.Generator = Generator;\nwindow.Evolver = Evolver;\n\n\n// helper utitlity to combine elements of two arrays.\nArray.prototype.zip = function (b, func) {\n var result = [],\n max = Math.max(this.length, b.length),\n x;\n for (x = 0; x < max; x += 1) {\n result.push(func(this[x], b[x]));\n }\n return result;\n};\n\nvar target = \"METHINKS IT IS LIKE A WEASEL\", geneStrategy, fitness, target, generator, evolver, result;\n \ngeneStrategy = {\n // The allowed character set (as an array) \n characterSet: \"ABCDEFGHIJKLMNOPQRSTUVWXYZ \".split(\"\"),\n\n /*\n Pick a random character from the characterSet\n */\n create: function getRandomGene() {\n var randomNumber = Math.floor(Math.random() * this.characterSet.length);\n return this.characterSet[randomNumber];\n }\n};\ngeneStrategy.mutate = geneStrategy.create; // Our mutation stragtegy is to simply get a random gene\nfitness = {\n // The target (as an array of characters)\n target: target.split(\"\"),\n equal: function (geneA, geneB) {\n return (geneA === geneB ? 0 : 1);\n },\n sum: function (runningTotal, value) {\n return runningTotal + value;\n },\n\n /*\n We give one point to for each corect letter\n */\n score: function (genes) {\n var diff = genes.zip(this.target, this.equal); // create an array of ones and zeros \n return diff.reduce(this.sum, 0); // Sum the array values together.\n },\n compare: function (scoreA, scoreB) {\n return scoreA <= scoreB; // Lower scores are better\n },\n done: function (score) {\n return score === 0; // We have matched the target string.\n }\n};\n\ngenerator = new Generator(target.length, 0.05, geneStrategy);\nevolver = new Evolver(100, generator, fitness);\n\nfunction showProgress(generation, fittest) {\n document.write(\"Generation: \" + generation + \", Best: \" + fittest.individual.join(\"\") + \", fitness:\" + fittest.score + \"
    \");\n}\nresult = evolver.run(showProgress);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Execute HQ9+", + "type": "Waypoint", + "description": [ + "Task:", + "

    Implement a HQ9+ interpreter or compiler.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "The function below executes a HQ9+ program and returns the program output as a string.", + "function hq9plus(code) {", + " var out = '';", + " var acc = 0;", + " ", + " for (var i=0; i1; j--) {", + " out += j + \" bottles of beer on the wall, \" + j + \" bottles of beer.\\n\";", + " out += \"Take one down and pass it around, \" + (j-1) + \" bottles of beer.\\n\\n\";", + " }", + " out += \"1 bottle of beer on the wall, 1 bottle of beer.\\n\" +", + " \"Take one down and pass it around, no more bottles of beer on the wall.\\n\\n\" +", + " \"No more bottles of beer on the wall, no more bottles of beer.\\n\" +", + " \"Go to the store and buy some more, 99 bottles of beer on the wall.\\n\";", + " break;", + " case '+': acc++; break;", + " }", + " }", + " return out;", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e43", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function hq9plus(code) {\n var out = '';\n var acc = 0;\n \n for (var i=0; i1; j--) {\n out += j + \" bottles of beer on the wall, \" + j + \" bottles of beer.\\n\";\n out += \"Take one down and pass it around, \" + (j-1) + \" bottles of beer.\\n\\n\";\n }\n out += \"1 bottle of beer on the wall, 1 bottle of beer.\\n\" +\n \"Take one down and pass it around, no more bottles of beer on the wall.\\n\\n\" +\n \"No more bottles of beer on the wall, no more bottles of beer.\\n\" +\n \"Go to the store and buy some more, 99 bottles of beer on the wall.\\n\";\n break;\n case '+': acc++; break;\n }\n }\n return out;\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Execute SNUSP", + "type": "Waypoint", + "description": [ + "

    RCSNUSP is a set of SNUSP compilers and interpreters written for Rosetta Code in a variety of languages. Below are links to each of the versions of RCSNUSP.

    An implementation need only properly implement the Core SNUSP instructions ('$', '\\', '/', '+', '-', '<', '>', ',', '.', '!', and '?'). Modular SNUSP ('#', '@') and Bloated SNUSP (':', ';', '%', and '&') are also allowed, but not required. Any extra characters that you implement should be noted in the description of your implementation. Any cell size is allowed, EOF support is optional, as is whether you have bounded or unbounded memory.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "See [[RCSNUSP/JavaScript]].", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e44", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "null\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "FASTA format", + "type": "Waypoint", + "description": [ + "

    In bioinformatics, long character strings are often encoded in a format called FASTA.

    A FASTA file can contain several strings, each identified by a name marked by a > (greater than) character at the beginning of the line.

    ", + "Task:", + "

    Write a program that reads a FASTA file such as:

    ", + "
    ",
    +        ">Rosetta_Example_1",
    +        "THERECANBENOSPACE",
    +        ">Rosetta_Example_2",
    +        "THERECANBESEVERAL",
    +        "LINESBUTTHEYALLMUST",
    +        "BECONCATENATED",
    +        "
    ",
    +        "Rosetta_Example_1: THERECANBENOSPACE",
    +        "Rosetta_Example_2: THERECANBESEVERALLINESBUTTHEYALLMUSTBECONCATENATED",
    +        "
    ", + "

    Note that a high-quality implementation will not hold the entire file in memory at once; real FASTA files can be multiple gigabytes in size.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e4e", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Fast Fourier transform", + "type": "Waypoint", + "description": [ + "Task:", + "

    Calculate the FFT (Fast Fourier Transform) of an input sequence.

    The most general case allows for complex numbers at the input

    ", + "

    and results in a sequence of equal length, again of complex numbers.

    ", + "

    If you need to restrict yourself to real numbers, the output should

    ", + "

    be the magnitude (i.e. sqrt(re²+im²)) of the complex result.

    The classic version is the recursive Cooley–Tukey FFT. Wikipedia has pseudo-code for that.

    ", + "

    Further optimizations are possible but not required.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Complex fourier transform & it's inverse reimplemented from the C++ & Python", + "variants on this page.", + "", + "/*", + "complex fast fourier transform and inverse from", + "http://rosettacode.org/wiki/Fast_Fourier_transform#C.2B.2B", + "*/", + "function icfft(amplitudes)", + "{", + "\tvar N = amplitudes.length;", + "\tvar iN = 1 / N;", + "\t", + "\t//conjugate if imaginary part is not 0", + "\tfor(var i = 0 ; i < N; ++i)", + "\t\tif(amplitudes[i] instanceof Complex)", + "\t\t\tamplitudes[i].im = -amplitudes[i].im;", + "\t\t\t", + "\t//apply fourier transform", + "\tamplitudes = cfft(amplitudes)", + "\t", + "\tfor(var i = 0 ; i < N; ++i)", + "\t{", + "\t\t//conjugate again", + "\t\tamplitudes[i].im = -amplitudes[i].im;", + "\t\t//scale", + "\t\tamplitudes[i].re *= iN;", + "\t\tamplitudes[i].im *= iN;", + "\t}", + "\treturn amplitudes;", + "}", + "", + "function cfft(amplitudes)", + "{", + "\tvar N = amplitudes.length;", + "\tif( N <= 1 )", + "\t\treturn amplitudes;", + "\t", + "\tvar hN = N / 2;", + "\tvar even = [];", + "\tvar odd = [];", + "\teven.length = hN;", + "\todd.length = hN;", + "\tfor(var i = 0; i < hN; ++i)", + "\t{", + "\t\teven[i] = amplitudes[i*2];", + "\t\todd[i] = amplitudes[i*2+1];", + "\t}", + "\teven = cfft(even);", + "\todd = cfft(odd);", + "\t", + "\tvar a = -2*Math.PI;", + "\tfor(var k = 0; k < hN; ++k)", + "\t{", + "\t\tif(!(even[k] instanceof Complex))", + "\t\t\teven[k] = new Complex(even[k], 0);", + "\t\tif(!(odd[k] instanceof Complex))", + "\t\t\todd[k] = new Complex(odd[k], 0);", + "\t\tvar p = k/N;", + "\t\tvar t = new Complex(0, a * p);", + "\t\tt.cexp(t).mul(odd[k], t);", + "\t\tamplitudes[k] = even[k].add(t, odd[k]);", + "\t\tamplitudes[k + hN] = even[k].sub(t, even[k]);", + "\t}", + "\treturn amplitudes;", + "}", + "", + "//test code", + "//console.log( cfft([1,1,1,1,0,0,0,0]) );", + "//console.log( icfft(cfft([1,1,1,1,0,0,0,0])) );", + "Very very basic Complex number that provides only the components", + "required by the code above.", + "/*", + "basic complex number arithmetic from ", + "http://rosettacode.org/wiki/Fast_Fourier_transform#Scala", + "*/", + "function Complex(re, im) ", + "{", + "\tthis.re = re;", + "\tthis.im = im || 0.0;", + "}", + "Complex.prototype.add = function(other, dst)", + "{", + "\tdst.re = this.re + other.re;", + "\tdst.im = this.im + other.im;", + "\treturn dst;", + "}", + "Complex.prototype.sub = function(other, dst)", + "{", + "\tdst.re = this.re - other.re;", + "\tdst.im = this.im - other.im;", + "\treturn dst;", + "}", + "Complex.prototype.mul = function(other, dst)", + "{", + "\t//cache re in case dst === this", + "\tvar r = this.re * other.re - this.im * other.im;", + "\tdst.im = this.re * other.im + this.im * other.re;", + "\tdst.re = r;", + "\treturn dst;", + "}", + "Complex.prototype.cexp = function(dst)", + "{", + "\tvar er = Math.exp(this.re);", + "\tdst.re = er * Math.cos(this.im);", + "\tdst.im = er * Math.sin(this.im);", + "\treturn dst;", + "}", + "Complex.prototype.log = function()", + "{", + "\t/*", + "\talthough 'It's just a matter of separating out the real and imaginary parts of jw.' is not a helpful quote", + "\tthe actual formula I found here and the rest was just fiddling / testing and comparing with correct results.", + "\thttp://cboard.cprogramming.com/c-programming/89116-how-implement-complex-exponential-functions-c.html#post637921", + "\t*/", + "\tif( !this.re )", + "\t\tconsole.log(this.im.toString()+'j');", + "\telse if( this.im < 0 )", + "\t\tconsole.log(this.re.toString()+this.im.toString()+'j');", + "\telse", + "\t\tconsole.log(this.re.toString()+'+'+this.im.toString()+'j');", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e4f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "/*\ncomplex fast fourier transform and inverse from\nhttp://rosettacode.org/wiki/Fast_Fourier_transform#C.2B.2B\n*/\nfunction icfft(amplitudes)\n{\n\tvar N = amplitudes.length;\n\tvar iN = 1 / N;\n\t\n\t//conjugate if imaginary part is not 0\n\tfor(var i = 0 ; i < N; ++i)\n\t\tif(amplitudes[i] instanceof Complex)\n\t\t\tamplitudes[i].im = -amplitudes[i].im;\n\t\t\t\n\t//apply fourier transform\n\tamplitudes = cfft(amplitudes)\n\t\n\tfor(var i = 0 ; i < N; ++i)\n\t{\n\t\t//conjugate again\n\t\tamplitudes[i].im = -amplitudes[i].im;\n\t\t//scale\n\t\tamplitudes[i].re *= iN;\n\t\tamplitudes[i].im *= iN;\n\t}\n\treturn amplitudes;\n}\n\nfunction cfft(amplitudes)\n{\n\tvar N = amplitudes.length;\n\tif( N <= 1 )\n\t\treturn amplitudes;\n\t\n\tvar hN = N / 2;\n\tvar even = [];\n\tvar odd = [];\n\teven.length = hN;\n\todd.length = hN;\n\tfor(var i = 0; i < hN; ++i)\n\t{\n\t\teven[i] = amplitudes[i*2];\n\t\todd[i] = amplitudes[i*2+1];\n\t}\n\teven = cfft(even);\n\todd = cfft(odd);\n\t\n\tvar a = -2*Math.PI;\n\tfor(var k = 0; k < hN; ++k)\n\t{\n\t\tif(!(even[k] instanceof Complex))\n\t\t\teven[k] = new Complex(even[k], 0);\n\t\tif(!(odd[k] instanceof Complex))\n\t\t\todd[k] = new Complex(odd[k], 0);\n\t\tvar p = k/N;\n\t\tvar t = new Complex(0, a * p);\n\t\tt.cexp(t).mul(odd[k], t);\n\t\tamplitudes[k] = even[k].add(t, odd[k]);\n\t\tamplitudes[k + hN] = even[k].sub(t, even[k]);\n\t}\n\treturn amplitudes;\n}\n\n//test code\n//console.log( cfft([1,1,1,1,0,0,0,0]) );\n//console.log( icfft(cfft([1,1,1,1,0,0,0,0])) );\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Filter", + "type": "Waypoint", + "description": [ + "Task:", + "

    Select certain elements from an Array into a new Array in a generic way.

    ", + "

    To demonstrate, select all even numbers from an Array.

    As an option, give a second solution which filters destructively,

    ", + "

    by modifying the original Array rather than creating a new Array.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "The standard way is to use the [https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/filter Array.prototype.filter] function ({{works with|JavaScript|1.6}}):", + "var arr = [1,2,3,4,5];", + "var evens = arr.filter(function(a) {return a % 2 == 0});", + "", + "Other ways:", + "var arr = [1,2,3,4,5];", + "var evens = [];", + "for (var i=0, ilen=arr.length; i", + "", + "{{works with|Firefox|2.0}}", + "", + "var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];", + "var evens = [i for (i in numbers) if (i % 2 == 0)];", + "", + "function range(limit) {", + " for(var i = 0; i < limit; i++) {", + " yield i;", + " }", + "}", + "", + "var evens2 = [i for (i in range(100)) if (i % 2 == 0)];", + "", + "{{libheader|Functional}}", + "Functional.select(\"+1&1\", [1,2,3,4]) // [2, 4]", + "", + "===ES6===", + "", + "(() => {", + " 'use strict';", + "", + " // isEven :: Int -> Bool", + " const isEven = n => n % 2 === 0;", + "", + "", + " // TEST", + " ", + " return [1,2,3,4,5,6,7,8,9]", + " .filter(isEven);", + "", + " // [2, 4, 6, 8]", + "})();", + "", + "{{Out}}", + "[2, 4, 6, 8]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e57", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var arr = [1,2,3,4,5];\nvar evens = arr.filter(function(a) {return a % 2 == 0});\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Find common directory path", + "type": "Waypoint", + "description": [ + "

    Create a routine that, given a set of strings representing directory paths and a single character directory separator, will return a string representing that part of the directory tree that is common to all the directories.

    Test your routine using the forward slash '/' character as the directory separator and the following three strings as input paths:

    ", + "

    '/home/user1/tmp/coverage/test'

    ", + "

    '/home/user1/tmp/covert/operator'

    ", + "

    '/home/user1/tmp/coven/members'

    Note: The resultant path should be the valid directory '/home/user1/tmp' and not the longest common string '/home/user1/tmp/cove'.

    ", + "

    If your language has a routine that performs this function (even if it does not have a changeable separator character), then mention it as part of the task.

    ", + "Related tasks", + "Longest common prefix" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e58", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Find largest left truncatable prime in a given base", + "type": "Waypoint", + "description": [ + "

    A truncatable prime is one where all non-empty substrings that finish at the end of the number (right-substrings) are also primes when understood as numbers in a particular base. The largest such prime in a given (integer) base is therefore computable, provided the base is larger than 2.

    Let's consider what happens in base 10. Obviously the right most digit must be prime, so in base 10 candidates are 2,3,5,7. Putting a digit in the range 1 to base-1 in front of each candidate must result in a prime. So 2 and 5, like the whale and the petunias in The Hitchhiker's Guide to the Galaxy, come into existence only to be extinguished before they have time to realize it, because 2 and 5 preceded by any digit in the range 1 to base-1 is not prime. Some numbers formed by preceding 3 or 7 by a digit in the range 1 to base-1 are prime. So 13,17,23,37,43,47,53,67,73,83,97 are candidates. Again, putting a digit in the range 1 to base-1 in front of each candidate must be a prime. Repeating until there are no larger candidates finds the largest left truncatable prime.

    Let's work base 3 by hand:

    0 and 1 are not prime so the last digit must be 2. 123 = 510 which is prime, 223 = 810 which is not so 123 is the only candidate. 1123 = 1410 which is not prime, 2123 = 2310 which is, so 2123 is the only candidate. 12123 = 5010 which is not prime, 22123 = 7710 which also is not prime. So there are no more candidates, therefore 23 is the largest left truncatable prime in base 3.

    The task is to reconstruct as much, and possibly more, of the table in the OEIS as you are able.

    Related Tasks:

    ", + "Miller-Rabin primality test" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e59", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Find palindromic numbers in both binary and ternary bases", + "type": "Waypoint", + "description": [ + "The task:

    Find and show (in decimal) the first six numbers (non-negative integers) that are palindromes in both base 2 and base 3.

    Use zero (0) as the first number found, even though some other definitions ignore it.

    Optionally, show the decimal number found in its binary and ternary form.

    It's permissible to assume the first two numbers and simply list them.

    ", + "See also", + " Sequence A60792, numbers that are palindromic in bases 2 and 3 on The On-Line Encyclopedia of Integer Sequences." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES6===", + "{{Trans|Haskell}}", + "(() => {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // compose :: (b -> c) -> (a -> b) -> (a -> c)", + " const compose = (f, g) => x => f(g(x));", + "", + " // listApply :: [(a -> b)] -> [a] -> [b]", + " const listApply = (fs, xs) =>", + " [].concat.apply([], fs.map(f =>", + " [].concat.apply([], xs.map(x => [f(x)]))));", + "", + " // pure :: a -> [a]", + " const pure = x => [x];", + "", + " // curry :: Function -> Function", + " const curry = (f, ...args) => {", + " const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :", + " function () {", + " return go(xs.concat([].slice.apply(arguments)));", + " };", + " return go([].slice.call(args, 1));", + " };", + "", + " // transpose :: [[a]] -> [[a]]", + " const transpose = xs =>", + " xs[0].map((_, iCol) => xs.map(row => row[iCol]));", + "", + " // reverse :: [a] -> [a]", + " const reverse = xs =>", + " typeof xs === 'string' ? (", + " xs.split('')", + " .reverse()", + " .join('')", + " ) : xs.slice(0)", + " .reverse();", + "", + " // take :: Int -> [a] -> [a]", + " const take = (n, xs) => xs.slice(0, n);", + "", + " // drop :: Int -> [a] -> [a]", + " const drop = (n, xs) => xs.slice(n);", + "", + " // maximum :: [a] -> a", + " const maximum = xs =>", + " xs.reduce((a, x) => (x > a || a === undefined ? x : a), undefined);", + "", + " // quotRem :: Integral a => a -> a -> (a, a)", + " const quotRem = (m, n) => [Math.floor(m / n), m % n];", + "", + " // length :: [a] -> Int", + " const length = xs => xs.length;", + "", + " // justifyLeft :: Int -> Char -> Text -> Text", + " const justifyLeft = (n, cFiller, strText) =>", + " n > strText.length ? (", + " (strText + cFiller.repeat(n))", + " .substr(0, n)", + " ) : strText;", + "", + " // unwords :: [String] -> String", + " const unwords = xs => xs.join(' ');", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + "", + " // BASES AND PALINDROMES", + "", + " // show, showBinary, showTernary :: Int -> String", + " const show = n => n.toString(10);", + " const showBinary = n => n.toString(2);", + " const showTernary = n => n.toString(3);", + "", + " // readBase3 :: String -> Int", + " const readBase3 = s => parseInt(s, 3);", + "", + " // base3Palindrome :: Int -> String", + " const base3Palindrome = n => {", + " const s = showTernary(n);", + " return s + '1' + reverse(s);", + " };", + "", + " // isBinPal :: Int -> Bool", + " const isBinPal = n => {", + " const", + " s = showBinary(n),", + " [q, r] = quotRem(s.length, 2);", + " return (r !== 0) && drop(q + 1, s) === reverse(take(q, s));", + " };", + "", + " // solutions :: [Int]", + " const solutions = [0, 1].concat(range(1, 10E5)", + " .map(compose(readBase3, base3Palindrome))", + " .filter(isBinPal));", + "", + " // TABULATION", + "", + " // cols :: [[Int]]", + " const cols = transpose(", + " [", + " ['Decimal', 'Ternary', 'Binary']", + " ].concat(", + " solutions.map(", + " compose(", + " xs => listApply([show, showTernary, showBinary], xs),", + " pure", + " )", + " )", + " )", + " );", + "", + " return unlines(", + " transpose(cols.map(col => col.map(", + " curry(justifyLeft)(maximum(col.map(length)) + 1, ' ')", + " )))", + " .map(unwords));", + "})();", + "{{Out}}", + "
    Decimal      Ternary                  Binary                                ",
    +        "0            0                        0                                     ",
    +        "1            1                        1                                     ",
    +        "6643         100010001                1100111110011                         ",
    +        "1422773      2200021200022            101011011010110110101                 ",
    +        "5415589      101012010210101          10100101010001010100101               ",
    +        "90396755477  22122022220102222022122  1010100001100000100010000011000010101 
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e5b", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n 'use strict';\n\n // GENERIC FUNCTIONS\n\n // range :: Int -> Int -> [Int]\n const range = (m, n) =>\n Array.from({\n length: Math.floor(n - m) + 1\n }, (_, i) => m + i);\n\n // compose :: (b -> c) -> (a -> b) -> (a -> c)\n const compose = (f, g) => x => f(g(x));\n\n // listApply :: [(a -> b)] -> [a] -> [b]\n const listApply = (fs, xs) =>\n [].concat.apply([], fs.map(f =>\n [].concat.apply([], xs.map(x => [f(x)]))));\n\n // pure :: a -> [a]\n const pure = x => [x];\n\n // curry :: Function -> Function\n const curry = (f, ...args) => {\n const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :\n function () {\n return go(xs.concat([].slice.apply(arguments)));\n };\n return go([].slice.call(args, 1));\n };\n\n // transpose :: [[a]] -> [[a]]\n const transpose = xs =>\n xs[0].map((_, iCol) => xs.map(row => row[iCol]));\n\n // reverse :: [a] -> [a]\n const reverse = xs =>\n typeof xs === 'string' ? (\n xs.split('')\n .reverse()\n .join('')\n ) : xs.slice(0)\n .reverse();\n\n // take :: Int -> [a] -> [a]\n const take = (n, xs) => xs.slice(0, n);\n\n // drop :: Int -> [a] -> [a]\n const drop = (n, xs) => xs.slice(n);\n\n // maximum :: [a] -> a\n const maximum = xs =>\n xs.reduce((a, x) => (x > a || a === undefined ? x : a), undefined);\n\n // quotRem :: Integral a => a -> a -> (a, a)\n const quotRem = (m, n) => [Math.floor(m / n), m % n];\n\n // length :: [a] -> Int\n const length = xs => xs.length;\n\n // justifyLeft :: Int -> Char -> Text -> Text\n const justifyLeft = (n, cFiller, strText) =>\n n > strText.length ? (\n (strText + cFiller.repeat(n))\n .substr(0, n)\n ) : strText;\n\n // unwords :: [String] -> String\n const unwords = xs => xs.join(' ');\n\n // unlines :: [String] -> String\n const unlines = xs => xs.join('\\n');\n\n\n // BASES AND PALINDROMES\n\n // show, showBinary, showTernary :: Int -> String\n const show = n => n.toString(10);\n const showBinary = n => n.toString(2);\n const showTernary = n => n.toString(3);\n\n // readBase3 :: String -> Int\n const readBase3 = s => parseInt(s, 3);\n\n // base3Palindrome :: Int -> String\n const base3Palindrome = n => {\n const s = showTernary(n);\n return s + '1' + reverse(s);\n };\n\n // isBinPal :: Int -> Bool\n const isBinPal = n => {\n const\n s = showBinary(n),\n [q, r] = quotRem(s.length, 2);\n return (r !== 0) && drop(q + 1, s) === reverse(take(q, s));\n };\n\n // solutions :: [Int]\n const solutions = [0, 1].concat(range(1, 10E5)\n .map(compose(readBase3, base3Palindrome))\n .filter(isBinPal));\n\n // TABULATION\n\n // cols :: [[Int]]\n const cols = transpose(\n [\n ['Decimal', 'Ternary', 'Binary']\n ].concat(\n solutions.map(\n compose(\n xs => listApply([show, showTernary, showBinary], xs),\n pure\n )\n )\n )\n );\n\n return unlines(\n transpose(cols.map(col => col.map(\n curry(justifyLeft)(maximum(col.map(length)) + 1, ' ')\n )))\n .map(unwords));\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Find the last Sunday of each month", + "type": "Waypoint", + "description": [ + "

    Write a program or a script that returns the last Sundays of each month of a given year. The year may be given through any simple input method in your language (command line, std in, etc).

    Example of an expected output:

    ./last_sundays 2013",
    +        "2013-01-27",
    +        "2013-02-24",
    +        "2013-03-31",
    +        "2013-04-28",
    +        "2013-05-26",
    +        "2013-06-30",
    +        "2013-07-28",
    +        "2013-08-25",
    +        "2013-09-29",
    +        "2013-10-27",
    +        "2013-11-24",
    +        "2013-12-29
    ", + "Related tasks", + "Day of the week", + "Five weekends", + "Last Friday of each month" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "====Iteration====", + "function lastSundayOfEachMonths(year) {", + "\tvar lastDay = [31,28,31,30,31,30,31,31,30,31,30,31]", + "\tif (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) lastDay[2] = 29", + "\tfor (var date = new Date(), month=0; month<12; month+=1) {", + "\t\tdate.setFullYear(year, month, lastDay[month])", + "\t\tdate.setDate(date.getDate()-date.getDay())", + "\t\tdocument.write(date.toISOString().substring(0,10), '
    ')", + "\t} ", + "}", + "\t", + "lastSundayOfEachMonths(2013)
    ", + "{{output}}", + "
    2013-01-27",
    +        "2013-02-24",
    +        "2013-03-31",
    +        "2013-04-28",
    +        "2013-05-26",
    +        "2013-06-30",
    +        "2013-07-28",
    +        "2013-08-25",
    +        "2013-09-29",
    +        "2013-10-27",
    +        "2013-11-24",
    +        "2013-12-29
    ", + "", + "====Functional composition====", + "(function () {", + " 'use strict';", + "", + " // lastSundaysOfYear :: Int -> [Date]", + " function lastSundaysOfYear(y) {", + " return lastWeekDaysOfYear(y, days.sunday);", + " }", + "", + " // lastWeekDaysOfYear :: Int -> Int -> [Date]", + " function lastWeekDaysOfYear(y, iWeekDay) {", + " return [", + " 31,", + " 0 === y % 4 && 0 !== y % 100 || 0 === y % 400 ? 29 : 28,", + " 31, 30, 31, 30, 31, 31, 30, 31, 30, 31", + " ]", + " .map(function (d, m) {", + " var dte = new Date(Date.UTC(y, m, d));", + "", + " return new Date(Date.UTC(", + " y, m, d - (", + " (dte.getDay() + (7 - iWeekDay)) % 7", + " )", + " ));", + " });", + " }", + "", + " // isoDateString :: Date -> String", + " function isoDateString(dte) {", + " return dte.toISOString()", + " .substr(0, 10);", + " }", + "", + " // range :: Int -> Int -> [Int]", + " function range(m, n) {", + " return Array.apply(null, Array(n - m + 1))", + " .map(function (x, i) {", + " return m + i;", + " });", + " }", + "", + " // transpose :: [[a]] -> [[a]]", + " function transpose(lst) {", + " return lst[0].map(function (_, iCol) {", + " return lst.map(function (row) {", + " return row[iCol];", + " });", + " });", + " }", + "", + " var days = {", + " sunday: 0,", + " monday: 1,", + " tuesday: 2,", + " wednesday: 3,", + " thursday: 4,", + " friday: 5,", + " saturday: 6", + " }", + "", + " // TEST", + "", + " return transpose(", + " range(2012, 2016)", + " .map(lastSundaysOfYear)", + " )", + " .map(function (row) {", + " return row", + " .map(isoDateString)", + " .join('\\t');", + " })", + " .join('\\n');", + "", + "})();", + "", + "{{Out}}", + "
    2013-01-27\t2014-01-26\t2015-01-25\t2016-01-31\t2017-01-29",
    +        "2013-02-24\t2014-02-23\t2015-02-22\t2016-02-28\t2017-02-26",
    +        "2013-03-31\t2014-03-30\t2015-03-29\t2016-03-27\t2017-03-26",
    +        "2013-04-28\t2014-04-27\t2015-04-26\t2016-04-24\t2017-04-30",
    +        "2013-05-26\t2014-05-25\t2015-05-31\t2016-05-29\t2017-05-28",
    +        "2013-06-30\t2014-06-29\t2015-06-28\t2016-06-26\t2017-06-25",
    +        "2013-07-28\t2014-07-27\t2015-07-26\t2016-07-31\t2017-07-30",
    +        "2013-08-25\t2014-08-31\t2015-08-30\t2016-08-28\t2017-08-27",
    +        "2013-09-29\t2014-09-28\t2015-09-27\t2016-09-25\t2017-09-24",
    +        "2013-10-27\t2014-10-26\t2015-10-25\t2016-10-30\t2017-10-29",
    +        "2013-11-24\t2014-11-30\t2015-11-29\t2016-11-27\t2017-11-26",
    +        "2013-12-29\t2014-12-28\t2015-12-27\t2016-12-25\t2017-12-31
    ", + "", + "===ES6===", + "(() => {", + " 'use strict'", + "", + " // lastWeekDaysOfYear :: Int -> Int -> [Date]", + " const lastWeekDaysOfYear = (iWeekDay, y) => [", + " 31,", + " 0 === y % 4 && 0 !== y % 100 || 0 === y % 400 ? 29 : 28,", + " 31, 30, 31, 30, 31, 31, 30, 31, 30, 31", + " ]", + " .map((d, m) =>", + " new Date(Date.UTC(", + " y, m, d - ((new Date(Date.UTC(y, m, d))", + " .getDay() + (7 - iWeekDay)) % 7))));", + "", + " const days = {", + " sunday: 0,", + " monday: 1,", + " tuesday: 2,", + " wednesday: 3,", + " thursday: 4,", + " friday: 5,", + " saturday: 6", + " };", + "", + " // GENERIC FUNCTIONS", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " const curry = f => a => b => f(a, b);", + "", + " // isoDateString :: Date -> String", + " const isoDateString = dte =>", + " dte.toISOString()", + " .substr(0, 10);", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // transpose :: [[a]] -> [[a]]", + " const transpose = lst =>", + " lst[0].map((_, iCol) =>", + " lst.map(row => row[iCol]));", + "", + " // TEST", + " return transpose(", + " range(2015, 2019)", + " .map(curry(lastWeekDaysOfYear)(days.sunday))", + " )", + " .map(row => row", + " .map(isoDateString)", + " .join('\\t'))", + " .join('\\n');", + "})();", + "{{Out}}", + "
    2015-01-25    2016-01-31    2017-01-29    2018-01-28    2019-01-27",
    +        "2015-02-22    2016-02-28    2017-02-26    2018-02-25    2019-02-24",
    +        "2015-03-29    2016-03-27    2017-03-26    2018-03-25    2019-03-31",
    +        "2015-04-26    2016-04-24    2017-04-30    2018-04-29    2019-04-28",
    +        "2015-05-31    2016-05-29    2017-05-28    2018-05-27    2019-05-26",
    +        "2015-06-28    2016-06-26    2017-06-25    2018-06-24    2019-06-30",
    +        "2015-07-26    2016-07-31    2017-07-30    2018-07-29    2019-07-28",
    +        "2015-08-30    2016-08-28    2017-08-27    2018-08-26    2019-08-25",
    +        "2015-09-27    2016-09-25    2017-09-24    2018-09-30    2019-09-29",
    +        "2015-10-25    2016-10-30    2017-10-29    2018-10-28    2019-10-27",
    +        "2015-11-29    2016-11-27    2017-11-26    2018-11-25    2019-11-24",
    +        "2015-12-27    2016-12-25    2017-12-31    2018-12-30    2019-12-29
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e5c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function lastSundayOfEachMonths(year) {\n\tvar lastDay = [31,28,31,30,31,30,31,31,30,31,30,31]\n\tif (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) lastDay[2] = 29\n\tfor (var date = new Date(), month=0; month<12; month+=1) {\n\t\tdate.setFullYear(year, month, lastDay[month])\n\t\tdate.setDate(date.getDate()-date.getDay())\n\t\tdocument.write(date.toISOString().substring(0,10), '
    ')\n\t} \n}\n\t\nlastSundayOfEachMonths(2013)\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Find the missing permutation", + "type": "Waypoint", + "description": [ + "
    ",
    +        "ABCD",
    +        "CABD",
    +        "ACDB",
    +        "DACB",
    +        "BCDA",
    +        "ACBD",
    +        "ADCB",
    +        "CDAB",
    +        "DABC",
    +        "BCAD",
    +        "CADB",
    +        "CDBA",
    +        "CBAD",
    +        "ABDC",
    +        "ADBC",
    +        "BDCA",
    +        "DCBA",
    +        "BACD",
    +        "BADC",
    +        "BDAC",
    +        "CBDA",
    +        "DBCA",
    +        "DCAB",
    +        "
    ", + "

    Listed above are all of the permutations of the symbols A, B, C, and D, except for one permutation that's not listed.

    ", + "Task:", + "

    Find that missing permutation.

    ", + "Methods:", + "Obvious method: enumerate all permutations of A, B, C, and D, ", + "

    and then look for the missing permutation.

    alternate method: Hint: if all permutations were shown above, how many ", + "

    times would A appear in each position?

    ", + "

    What is the parity of this number?

    another alternate method: Hint: if you add up the letter values of each column, ", + "

    does a missing letter A, B, C, and D from each

    ", + "

    column cause the total value for each column to be unique?

    ", + "Related task:", + " Permutations)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "====Imperative====", + "", + "The permute() function taken from http://snippets.dzone.com/posts/show/1032 ", + "permute = function(v, m){ //v1.0", + " for(var p = -1, j, k, f, r, l = v.length, q = 1, i = l + 1; --i; q *= i);", + " for(x = [new Array(l), new Array(l), new Array(l), new Array(l)], j = q, k = l + 1, i = -1;", + " ++i < l; x[2][i] = i, x[1][i] = x[0][i] = j /= --k);", + " for(r = new Array(q); ++p < q;)", + " for(r[p] = new Array(l), i = -1; ++i < l; !--x[1][i] && (x[1][i] = x[0][i],", + " x[2][i] = (x[2][i] + 1) % l), r[p][i] = m ? x[3][i] : v[x[3][i]])", + " for(x[3][i] = x[2][i], f = 0; !f; f = !f)", + " for(j = i; j; x[3][--j] == x[2][i] && (x[3][i] = x[2][i] = (x[2][i] + 1) % l, f = 1));", + " return r;", + "};", + "", + "list = [ 'ABCD', 'CABD', 'ACDB', 'DACB', 'BCDA', 'ACBD', 'ADCB', 'CDAB',", + " 'DABC', 'BCAD', 'CADB', 'CDBA', 'CBAD', 'ABDC', 'ADBC', 'BDCA',", + " 'DCBA', 'BACD', 'BADC', 'BDAC', 'CBDA', 'DBCA', 'DCAB'];", + "", + "all = permute(list[0].split('')).map(function(elem) {return elem.join('')});", + "", + "missing = all.filter(function(elem) {return list.indexOf(elem) == -1});", + "print(missing); // ==> DBAC", + "", + "====Functional====", + "", + "(function (strList) {", + "", + " // [a] -> [[a]]", + " function permutations(xs) {", + " return xs.length ? (", + " chain(xs, function (x) {", + " return chain(permutations(deleted(x, xs)), function (ys) {", + " return [[x].concat(ys).join('')];", + " })", + " })) : [[]];", + " }", + "", + " // Monadic bind/chain for lists", + " // [a] -> (a -> b) -> [b]", + " function chain(xs, f) {", + " return [].concat.apply([], xs.map(f));", + " }", + "", + " // a -> [a] -> [a]", + " function deleted(x, xs) {", + " return xs.length ? (", + " x === xs[0] ? xs.slice(1) : [xs[0]].concat(", + " deleted(x, xs.slice(1))", + " )", + " ) : [];", + " }", + "", + " // Provided subset", + " var lstSubSet = strList.split('\\n');", + "", + " // Any missing permutations", + " // (we can use fold/reduce, filter, or chain (concat map) here)", + " return chain(permutations('ABCD'.split('')), function (x) {", + " return lstSubSet.indexOf(x) === -1 ? [x] : [];", + " });", + "", + "})(", + " 'ABCD\\nCABD\\nACDB\\nDACB\\nBCDA\\nACBD\\nADCB\\nCDAB\\nDABC\\nBCAD\\nCADB\\n\\", + "CDBA\\nCBAD\\nABDC\\nADBC\\nBDCA\\nDCBA\\nBACD\\nBADC\\nBDAC\\nCBDA\\nDBCA\\nDCAB'", + ");", + "", + "{{Out}}", + "", + "[\"DBAC\"]", + "", + "===ES6===", + "====Statistical====", + "=====Using a dictionary=====", + "(() => {", + " 'use strict';", + "", + " // transpose :: [[a]] -> [[a]]", + " let transpose = xs =>", + " xs[0].map((_, iCol) => xs", + " .map((row) => row[iCol]));", + "", + "", + " let xs = 'ABCD CABD ACDB DACB BCDA ACBD ADCB CDAB' +", + " ' DABC BCAD CADB CDBA CBAD ABDC ADBC BDCA DCBA' +", + " ' BACD BADC BDAC CBDA DBCA DCAB'", + "", + " return transpose(xs.split(' ')", + " .map(x => x.split('')))", + " .map(col => col.reduce((a, x) => ( // count of each character in each column", + " a[x] = (a[x] || 0) + 1,", + " a", + " ), {}))", + " .map(dct => { // character with frequency below mean of distribution ?", + " let ks = Object.keys(dct),", + " xs = ks.map(k => dct[k]),", + " mean = xs.reduce((a, b) => a + b, 0) / xs.length;", + "", + " return ks.reduce(", + " (a, k) => a ? a : (dct[k] < mean ? k : undefined),", + " undefined", + " );", + " })", + " .join(''); // 4 chars as single string", + "", + " // --> 'DBAC'", + "})();", + "", + "{{Out}}", + "
    DBAC
    ", + "", + "", + "=====Composing functional primitives=====", + "{{Trans|Haskell}}", + "(() => {", + " 'use strict';", + "", + " // MISSING PERMUTATION ---------------------------------------------------", + "", + " // missingPermutation :: [String] -> String", + " const missingPermutation = xs =>", + " map(", + " // Rarest letter,", + " compose([", + " sort,", + " group,", + " curry(minimumBy)(comparing(length)),", + " head", + " ]),", + "", + " // in each column.", + " transpose(map(stringChars, xs))", + " )", + " .join('');", + "", + "", + " // GENERIC FUNCTIONAL PRIMITIVES -----------------------------------------", + "", + " // transpose :: [[a]] -> [[a]]", + " const transpose = xs =>", + " xs[0].map((_, iCol) => xs.map(row => row[iCol]));", + "", + " // sort :: Ord a => [a] -> [a]", + " const sort = xs => xs.sort();", + "", + " // group :: Eq a => [a] -> [[a]]", + " const group = xs => groupBy((a, b) => a === b, xs);", + "", + " // groupBy :: (a -> a -> Bool) -> [a] -> [[a]]", + " const groupBy = (f, xs) => {", + " const dct = xs.slice(1)", + " .reduce((a, x) => {", + " const", + " h = a.active.length > 0 ? a.active[0] : undefined,", + " blnGroup = h !== undefined && f(h, x);", + "", + " return {", + " active: blnGroup ? a.active.concat(x) : [x],", + " sofar: blnGroup ? a.sofar : a.sofar.concat([a.active])", + " };", + " }, {", + " active: xs.length > 0 ? [xs[0]] : [],", + " sofar: []", + " });", + " return dct.sofar.concat(dct.active.length > 0 ? [dct.active] : []);", + " };", + "", + " // length :: [a] -> Int", + " const length = xs => xs.length;", + "", + " // comparing :: (a -> b) -> (a -> a -> Ordering)", + " const comparing = f =>", + " (x, y) => {", + " const", + " a = f(x),", + " b = f(y);", + " return a < b ? -1 : a > b ? 1 : 0", + " };", + "", + " // minimumBy :: (a -> a -> Ordering) -> [a] -> a", + " const minimumBy = (f, xs) =>", + " xs.reduce((a, x) => a === undefined ? x : (", + " f(x, a) < 0 ? x : a", + " ), undefined);", + "", + " // head :: [a] -> a", + " const head = xs => xs.length ? xs[0] : undefined;", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = (f, xs) => xs.map(f)", + "", + " // compose :: [(a -> a)] -> (a -> a)", + " const compose = fs => x => fs.reduce((a, f) => f(a), x);", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " const curry = f => a => b => f(a, b);", + "", + " // stringChars :: String -> [Char]", + " const stringChars = s => s.split('');", + "", + "", + " // TEST ------------------------------------------------------------------", + "", + " return missingPermutation([\"ABCD\", \"CABD\", \"ACDB\", \"DACB\", \"BCDA\", \"ACBD\",", + " \"ADCB\", \"CDAB\", \"DABC\", \"BCAD\", \"CADB\", \"CDBA\", \"CBAD\", \"ABDC\", \"ADBC\",", + " \"BDCA\", \"DCBA\", \"BACD\", \"BADC\", \"BDAC\", \"CBDA\", \"DBCA\", \"DCAB\"", + " ]);", + "", + " // -> \"DBAC\"", + "})();", + "{{Out}}", + "
    DBAC
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e5d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "permute = function(v, m){ //v1.0\n for(var p = -1, j, k, f, r, l = v.length, q = 1, i = l + 1; --i; q *= i);\n for(x = [new Array(l), new Array(l), new Array(l), new Array(l)], j = q, k = l + 1, i = -1;\n ++i < l; x[2][i] = i, x[1][i] = x[0][i] = j /= --k);\n for(r = new Array(q); ++p < q;)\n for(r[p] = new Array(l), i = -1; ++i < l; !--x[1][i] && (x[1][i] = x[0][i],\n x[2][i] = (x[2][i] + 1) % l), r[p][i] = m ? x[3][i] : v[x[3][i]])\n for(x[3][i] = x[2][i], f = 0; !f; f = !f)\n for(j = i; j; x[3][--j] == x[2][i] && (x[3][i] = x[2][i] = (x[2][i] + 1) % l, f = 1));\n return r;\n};\n\nlist = [ 'ABCD', 'CABD', 'ACDB', 'DACB', 'BCDA', 'ACBD', 'ADCB', 'CDAB',\n 'DABC', 'BCAD', 'CADB', 'CDBA', 'CBAD', 'ABDC', 'ADBC', 'BDCA',\n 'DCBA', 'BACD', 'BADC', 'BDAC', 'CBDA', 'DBCA', 'DCAB'];\n\nall = permute(list[0].split('')).map(function(elem) {return elem.join('')});\n\nmissing = all.filter(function(elem) {return list.indexOf(elem) == -1});\nprint(missing); // ==> DBAC\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "First class environments", + "type": "Waypoint", + "description": [ + "

    According to Wikipedia, \"In computing, a first-class object ... is an entity that can be constructed at run-time, passed as a parameter, returned from a subroutine, or assigned into a variable\".

    Often this term is used in the context of \"first class functions\". In an analogous way, a programming language may support \"first class environments\".

    The environment is minimally, the set of variables accessable to a statement being executed. Change the environments and the same statement could produce different results when executed.

    Often an environment is captured in a closure, which encapsulates a function together with an environment. That environment, however, is not first-class, as it cannot be created, passed etc. independently from the function's code.

    Therefore, a first class environment is a set of variable bindings which can be constructed at run-time, passed as a parameter, returned from a subroutine, or assigned into a variable. It is like a closure without code. A statement must be able to be executed within a stored first class environment and act according to the environment variable values stored within.

    The task: Build a dozen environments, and a single piece of code to be run repeatedly in each of these envionments.

    Each environment contains the bindings for two variables: A value in the Hailstone sequence, and a count which is incremented until the value drops to 1. The initial hailstone values are 1 through 12, and the count in each environment is zero.

    When the code runs, it calculates the next hailstone step in the current environment (unless the value is already 1) and counts the steps. Then it prints the current value in a tabular form.

    When all hailstone values dropped to 1, processing stops, and the total number of hailstone steps for each environment is printed.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e5e", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "First-class functions", + "type": "Waypoint", + "description": [ + "

    A language has first-class functions if it can do each of the following without recursively invoking a compiler or interpreter or otherwise metaprogramming:

    Create new functions from preexisting functions at run-time", + "Store functions in collections", + "Use functions as arguments to other functions", + "Use functions as return values of other functions", + "Task:", + "

    Write a program to create an ordered collection A of functions of a real number. At least one function should be built-in and at least one should be user-defined; try using the sine, cosine, and cubing functions. Fill another collection B with the inverse of each function in A. Implement function composition as in Functional Composition. Finally, demonstrate that the result of applying the composition of each function in A and its inverse in B to a value, is the original value. (Within the limits of computational accuracy).

    (A solution need not actually call the collections \"A\" and \"B\". These names are only used in the preceding paragraph for clarity.)

    ", + "Related task: ", + "

    First-class Numbers

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "// Functions as values of a variable", + "var cube = function (x) {", + " return Math.pow(x, 3);", + "};", + "var cuberoot = function (x) {", + " return Math.pow(x, 1 / 3);", + "};", + "", + "// Higher order function", + "var compose = function (f, g) {", + " return function (x) {", + " return f(g(x));", + " };", + "};", + "", + "// Storing functions in a array", + "var fun = [Math.sin, Math.cos, cube];", + "var inv = [Math.asin, Math.acos, cuberoot];", + "", + "for (var i = 0; i < 3; i++) {", + " // Applying the composition to 0.5", + " console.log(compose(inv[i], fun[i])(0.5));", + "}", + "", + "===ES6===", + "// Functions as values of a variable", + "var cube = x => Math.pow(x, 3);", + "", + "var cuberoot = x => Math.pow(x, 1 / 3);", + "", + "", + "// Higher order function", + "var compose = (f, g) => (x => f(g(x)));", + "", + "// Storing functions in a array", + "var fun = [ Math.sin, Math.cos, cube ];", + "var inv = [ Math.asin, Math.acos, cuberoot ];", + "", + "for (var i = 0; i < 3; i++) {", + " // Applying the composition to 0.5", + " console.log(compose(inv[i], fun[i])(0.5));", + "}", + "", + "", + "Result is always: ", + "
    0.5",
    +        "0.4999999999999999",
    +        "0.5
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e5f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// Functions as values of a variable\nvar cube = function (x) {\n return Math.pow(x, 3);\n};\nvar cuberoot = function (x) {\n return Math.pow(x, 1 / 3);\n};\n\n// Higher order function\nvar compose = function (f, g) {\n return function (x) {\n return f(g(x));\n };\n};\n\n// Storing functions in a array\nvar fun = [Math.sin, Math.cos, cube];\nvar inv = [Math.asin, Math.acos, cuberoot];\n\nfor (var i = 0; i < 3; i++) {\n // Applying the composition to 0.5\n console.log(compose(inv[i], fun[i])(0.5));\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "First-class functions/Use numbers analogously", + "type": "Waypoint", + "description": [ + "

    In First-class functions, a language is showing how its manipulation of functions is similar to its manipulation of other types.

    This tasks aim is to compare and contrast a language's implementation of first class functions, with its normal handling of numbers.

    ", + "

    Write a program to create an ordered collection of a mixture of literally typed and expressions producing a real number, together with another ordered collection of their multiplicative inverses. Try and use the following pseudo-code to generate the numbers for the ordered collections:

    ", + "

    x = 2.0

    ", + "

    xi = 0.5

    ", + "

    y = 4.0

    ", + "

    yi = 0.25

    ", + "

    z = x + y

    ", + "

    zi = 1.0 / ( x + y )

    Create a function multiplier, that given two numbers as arguments returns a function that when called with one argument, returns the result of multiplying the two arguments to the call to multiplier that created it and the argument in the call:

    ", + "

    new_function = multiplier(n1,n2)

    ", + "

    # where new_function(m) returns the result of n1 * n2 * m

    Applying the multiplier of a number and its inverse from the two ordered collections of numbers in pairs, show that the result in each case is one.

    ", + "

    Compare and contrast the resultant program with the corresponding entry in First-class functions. They should be close.

    To paraphrase the task description: Do what was done before, but with numbers rather than functions

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e60", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Five weekends", + "type": "Waypoint", + "description": [ + "

    The month of October in 2010 has five Fridays, five Saturdays, and five Sundays.

    ", + "Task:", + "Write a program to show all months that have this same characteristic of five full weekends from the year 1900 through 2100 (Gregorian calendar). ", + "Show the number of months with this property (there should be 201).", + "Show at least the first and last five dates, in order.

    Algorithm suggestions

    ", + "Count the number of Fridays, Saturdays, and Sundays in every month.", + "Find all of the 31-day months that begin on Friday.

    Extra credit

    Count and/or show all of the years which do not have at least one five-weekend month (there should be 29).

    ", + "Related tasks", + "Day of the week", + "Last Friday of each month", + "Find last sunday of each month" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "====Imperative====", + "function startsOnFriday(month, year)", + "{", + " // 0 is Sunday, 1 is Monday, ... 5 is Friday, 6 is Saturday", + " return new Date(year, month, 1).getDay() === 5;", + "}", + "function has31Days(month, year)", + "{", + " return new Date(year, month, 31).getDate() === 31;", + "}", + "function checkMonths(year)", + "{", + " var month, count = 0;", + " for (month = 0; month < 12; month += 1)", + " {", + " if (startsOnFriday(month, year) && has31Days(month, year))", + " {", + " count += 1;", + " document.write(year + ' ' + month + '
    ');", + " }", + " }", + " return count;", + "}", + "function fiveWeekends()", + "{", + " var", + " startYear = 1900,", + " endYear = 2100,", + " year,", + " monthTotal = 0,", + " yearsWithoutFiveWeekends = [],", + " total = 0;", + " for (year = startYear; year <= endYear; year += 1)", + " {", + " monthTotal = checkMonths(year);", + " total += monthTotal;", + " // extra credit", + " if (monthTotal === 0)", + " yearsWithoutFiveWeekends.push(year);", + " }", + " document.write('Total number of months: ' + total + '
    ');", + " document.write('
    ');", + " document.write(yearsWithoutFiveWeekends + '
    ');", + " document.write('Years with no five-weekend months: ' + yearsWithoutFiveWeekends.length + '
    ');", + "}", + "fiveWeekends();
    ", + "", + "{{out|Sample output}}", + "
    1901 2",
    +        "1902 7",
    +        "1903 4",
    +        "1904 0",
    +        "1904 6",
    +        "...",
    +        "2097 2",
    +        "2098 7",
    +        "2099 4",
    +        "2100 0",
    +        "2100 9",
    +        "Total number of months: 201",
    +        "",
    +        "1900,1906,1917,1923,1928,1934,1945,1951,1956,1962,1973,1979,1984,1990,2001,2007,2012,2018,2029,2035,2040,2046,2057,2063,2068,2074,2085,2091,2096",
    +        "Years with no five-weekend months: 29
    ", + "", + "", + "Here is an alternative solution that uses the offset between the first day of every month, generating the same solution but without relying on the Date object.", + "var Months = [", + " 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',", + " 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'", + "];", + "", + "var leap = 0,", + " // Relative offsets between first day of each month", + " offset = [3,0,3,2,3,2,3,3,2,3,2,3],", + "", + " // Months that contain 31 days", + " longMonths = [1,3,5,7,8,10,12],", + "", + " startYear = 1900,", + " year = startYear,", + " endYear = 2100,", + "", + " // Jan 1, 1900 starts on a Monday", + " day = 1,", + "", + " totalPerYear = 0,", + " total = 0,", + " without = 0;", + "", + "for (; year < endYear + 1; year++) {", + " leap = totalPerYear = 0;", + "", + " if (year % 4 === 0) {", + " if (year % 100 === 0) {", + " if (year % 400 === 0) {", + " leap = 1;", + " }", + " } else {", + " leap = 1;", + " }", + " }", + "", + " for (var i = 0; i < offset.length; i++) {", + " for (var j = 0; day === 5 && j < longMonths.length; j++) {", + " if (i + 1 === longMonths[j]) {", + " console.log(year + '-' + Months[i]);", + " totalPerYear++;", + " total++;", + " break;", + " }", + " }", + "", + " // February -- if leap year, then +1 day", + " if (i == 1) {", + " day = (day + leap) % 7; ", + " } else {", + " day = (day + offset[i]) % 7;", + " }", + " }", + "", + " if (totalPerYear === 0) {", + " without++;", + " }", + "}", + "", + "console.log('Number of months that have five full weekends from 1900 to 2100: ' + total);", + "console.log('Number of years without any five full weekend months: ' + without);", + "{{out}}", + "
    1901-Mar",
    +        "1902-Aug",
    +        "1903-May",
    +        "1904-Jan",
    +        "1904-Jul",
    +        "...",
    +        "2097-Mar",
    +        "2098-Aug",
    +        "2099-May",
    +        "2100-Jan",
    +        "2100-Oct",
    +        "Number of months that have five full weekends from 1900 to 2100: 201",
    +        "Number of years without any five full weekend months: 29
    ", + "", + "====Functional====", + "(function () {", + " 'use strict';", + "", + " // longMonthsStartingFriday :: Int -> Int", + " function longMonthsStartingFriday(y) {", + " return [0, 2, 4, 6, 7, 9, 11]", + " .filter(function (m) {", + " return (new Date(Date.UTC(y, m, 1)))", + " .getDay() === 5;", + " });", + " }", + "", + " // range :: Int -> Int -> [Int]", + " function range(m, n) {", + " return Array.apply(null, Array(n - m + 1))", + " .map(function (x, i) {", + " return m + i;", + " });", + " }", + "", + " var lstNames = [", + " 'January', '', 'March', '', 'May', '',", + " 'July', 'August', '', 'October', '', 'December'", + " ],", + "", + " lstYears = range(1900, 2100),", + "", + " lstFullMonths = lstYears", + " .reduce(function (a, y) {", + " var strYear = y.toString();", + "", + " return a.concat(", + " longMonthsStartingFriday(y)", + " .map(function (m) {", + " return strYear + ' ' + lstNames[m];", + " })", + " );", + " }, []),", + "", + " lstLeanYears = lstYears", + " .filter(function (y) {", + " return longMonthsStartingFriday(y)", + " .length === 0;", + " });", + "", + " return JSON.stringify({", + " number: lstFullMonths.length,", + " firstFive: lstFullMonths.slice(0, 5),", + " lastFive: lstFullMonths.slice(-5),", + " leanYearCount: lstLeanYears.length", + " },", + " null, 2", + " );", + "})();", + "{{Out}}", + "
    {",
    +        "  \"number\": 201,",
    +        "  \"firstFive\": [",
    +        "    \"1901 March\",",
    +        "    \"1902 August\",",
    +        "    \"1903 May\",",
    +        "    \"1904 January\",",
    +        "    \"1904 July\"",
    +        "  ],",
    +        "  \"lastFive\": [",
    +        "    \"2097 March\",",
    +        "    \"2098 August\",",
    +        "    \"2099 May\",",
    +        "    \"2100 January\",",
    +        "    \"2100 October\"",
    +        "  ],",
    +        "  \"leanYearCount\": 29",
    +        "}
    ", + "", + "===ES6===", + "(() => {", + " // longMonthsStartingFriday :: Int -> [Int]", + " const longMonthsStartingFriday = y =>", + " filter(m => (new Date(Date.UTC(y, m, 1)))", + " .getDay() === 5, [0, 2, 4, 6, 7, 9, 11]);", + "", + " // Years -> YearMonths", + " // fullMonths :: [Int] -> [String]", + " const fullMonths = xs =>", + " foldl((a, y) => a.concat(", + " map(m => `${y.toString()} ${[", + " 'January', '', 'March', '', 'May', '',", + " 'July', 'August', '', 'October', '', 'December'", + " ][m]}`, longMonthsStartingFriday(y))", + " ), [], xs);", + "", + " // leanYears :: [Int] -> [Int]", + " const leanYears = years =>", + " filter(y => longMonthsStartingFriday(y)", + " .length === 0, years);", + "", + " // GENERIC ----------------------------------------------------------------", + "", + " // A list of functions applied to a list of arguments", + " // <*> :: [(a -> b)] -> [a] -> [b]", + " const ap = (fs, xs) => //", + " [].concat.apply([], fs.map(f => //", + " [].concat.apply([], xs.map(x => [f(x)]))));", + "", + " // enumFromTo :: Int -> Int -> [Int]", + " const enumFromTo = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // filter :: (a -> Bool) -> [a] -> [a]", + " const filter = (f, xs) => xs.filter(f);", + "", + " // foldl :: (b -> a -> b) -> b -> [a] -> b", + " const foldl = (f, a, xs) => xs.reduce(f, a);", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = (f, xs) => xs.map(f);", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x, null, 2);", + "", + "", + " // TEST -------------------------------------------------------------------", + " const [lstFullMonths, lstLeanYears] = ap(", + " [fullMonths, leanYears], [enumFromTo(1900, 2100)]", + " );", + "", + " return show({", + " number: lstFullMonths.length,", + " firstFive: lstFullMonths.slice(0, 5),", + " lastFive: lstFullMonths.slice(-5),", + " leanYearCount: lstLeanYears.length", + " });", + "})();", + "{{Out}}", + "
    {",
    +        "  \"number\": 201,",
    +        "  \"firstFive\": [",
    +        "    \"1901 March\",",
    +        "    \"1902 August\",",
    +        "    \"1903 May\",",
    +        "    \"1904 January\",",
    +        "    \"1904 July\"",
    +        "  ],",
    +        "  \"lastFive\": [",
    +        "    \"2097 March\",",
    +        "    \"2098 August\",",
    +        "    \"2099 May\",",
    +        "    \"2100 January\",",
    +        "    \"2100 October\"",
    +        "  ],",
    +        "  \"leanYearCount\": 29",
    +        "}
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e61", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function startsOnFriday(month, year)\n{\n // 0 is Sunday, 1 is Monday, ... 5 is Friday, 6 is Saturday\n return new Date(year, month, 1).getDay() === 5;\n}\nfunction has31Days(month, year)\n{\n return new Date(year, month, 31).getDate() === 31;\n}\nfunction checkMonths(year)\n{\n var month, count = 0;\n for (month = 0; month < 12; month += 1)\n {\n if (startsOnFriday(month, year) && has31Days(month, year))\n {\n count += 1;\n document.write(year + ' ' + month + '
    ');\n }\n }\n return count;\n}\nfunction fiveWeekends()\n{\n var\n startYear = 1900,\n endYear = 2100,\n year,\n monthTotal = 0,\n yearsWithoutFiveWeekends = [],\n total = 0;\n for (year = startYear; year <= endYear; year += 1)\n {\n monthTotal = checkMonths(year);\n total += monthTotal;\n // extra credit\n if (monthTotal === 0)\n yearsWithoutFiveWeekends.push(year);\n }\n document.write('Total number of months: ' + total + '
    ');\n document.write('
    ');\n document.write(yearsWithoutFiveWeekends + '
    ');\n document.write('Years with no five-weekend months: ' + yearsWithoutFiveWeekends.length + '
    ');\n}\nfiveWeekends();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "FizzBuzz", + "type": "Waypoint", + "description": [ + "Task:", + "

    Write a program that prints the integers from 1 to 100 (inclusive).

    ", + "

    But:

    ", + "

    * for multiples of three, print Fizz (instead of the number)

    ", + "

    * for multiples of five, print Buzz (instead of the number)

    ", + "

    * for multiples of both three and five, print FizzBuzz (instead of the number)

    ", + "

    The FizzBuzz problem was presented as the lowest level of comprehension required to illustrate adequacy.

    ", + "Also see:", + " (a blog) dont-overthink-fizzbuzz", + " (a blog) fizzbuzz-the-programmers-stairway-to-heaven" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "var fizzBuzz = function () {", + " var i, output;", + " for (i = 1; i < 101; i += 1) {", + " output = '';", + " if (!(i % 3)) { output += 'Fizz'; }", + " if (!(i % 5)) { output += 'Buzz'; }", + " console.log(output || i);//empty string is false, so we short-circuit", + " }", + "};", + "", + "Alternate version with ghetto pattern matching", + "for (var i = 1; i <= 100; i++) {", + " console.log({", + " truefalse: 'Fizz', ", + " falsetrue: 'Buzz', ", + " truetrue: 'FizzBuzz'", + " }[(i%3==0) + '' + (i%5==0)] || i)", + "}", + "", + "Or very tersely:", + "for(i=1;i<101;i++)console.log((x=(i%3?'':'Fizz')+(i%5?'':'Buzz'))?x:i);", + "", + "Or with even less characters:", + "for(i=1;i<101;i++)console.log((i%3?'':'Fizz')+(i%5?'':'Buzz')||i)", + "", + "Or, in a more functional style, without mutations", + "(function rng(i) {", + " return i ? rng(i - 1).concat(i) : []", + "})(100).map(", + " function (n) {", + " return n % 3 ? (", + " n % 5 ? n : \"Buzz\"", + " ) : (", + " n % 5 ? \"Fizz\" : \"FizzBuzz\"", + " )", + " }", + ").join(' ')", + "", + "===ES6===", + "", + "(() => {", + "", + " // fizzBuzz :: Int -> String", + " const fizzBuzz = n =>", + " caseOf(n, [", + " [x => x % 15 === 0, \"FizzBuzz\"],", + " [x => x % 3 === 0, \"Fizz\"],", + " [x => x % 5 === 0, \"Buzz\"]", + " ], n.toString());", + "", + "", + "", + " // GENERIC -------------------------------------------------", + "", + " // caseOf :: a -> [(a -> Bool, b)] -> b -> b", + " const caseOf = (e, pvs, otherwise) =>", + " pvs.reduce((a, [p, v]) =>", + " a !== otherwise ? a : (p(e) ? v : a), otherwise);", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + "", + " // TEST ----------------------------------------------------", + " return range(1, 100)", + " .map(fizzBuzz)", + " .join('\\n');", + "})();", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e62", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var fizzBuzz = function () {\n var i, output;\n for (i = 1; i < 101; i += 1) {\n output = '';\n if (!(i % 3)) { output += 'Fizz'; }\n if (!(i % 5)) { output += 'Buzz'; }\n console.log(output || i);//empty string is false, so we short-circuit\n }\n};\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Flatten a list", + "type": "Waypoint", + "description": [ + "Task:", + "

    Write a function to flatten the nesting in an arbitrary list of values.

    ", + "

    Your program should work on the equivalent of this list:

    ", + "

    1], 2, [[3, 4], 5], [[[], [6], 7, 8, []]

    ", + "

    Where the correct result would be the list:

    ", + "

    [1, 2, 3, 4, 5, 6, 7, 8]

    ", + "Related task:", + " Tree traversal" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "function flatten(list) {", + " return list.reduce(function (acc, val) {", + " return acc.concat(val.constructor === Array ? flatten(val) : val);", + " }, []);", + "}", + "", + "", + "Or, expressed in terms of the more generic '''concatMap''' function:", + "", + "(function () {", + " 'use strict';", + "", + " // flatten :: Tree a -> [a]", + " function flatten(t) {", + " return (t instanceof Array ? concatMap(flatten, t) : t);", + " }", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " function concatMap(f, xs) {", + " return [].concat.apply([], xs.map(f));", + " }", + "", + " return flatten(", + " [[1], 2, [[3, 4], 5], [[[]]], [[[6]]], 7, 8, []]", + " );", + "", + "})();", + "", + "", + "From fusion of ''flatten'' with ''concatMap'' we can then derive:", + "", + " // flatten :: Tree a -> [a]", + " function flatten(a) {", + " return a instanceof Array ? [].concat.apply([], a.map(flatten)) : a;", + " }", + "", + "For example:", + "", + "(function () {", + " 'use strict';", + "", + " // flatten :: Tree a -> [a]", + " function flatten(a) {", + " return a instanceof Array ? [].concat.apply([], a.map(flatten)) : a;", + " }", + "", + " return flatten(", + " [[1], 2, [[3, 4], 5], [[[]]], [[[6]]], 7, 8, []]", + " );", + "", + "})();", + "", + "{{Out}}", + "", + "
    [1, 2, 3, 4, 5, 6, 7, 8]
    ", + "", + "===ES6===", + "====Recursive====", + "let flatten = list => list.reduce(", + " (a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []", + ");", + "", + "====Iterative====", + "function flatten(list) {", + " for (let i = 0; i < list.length; i++) {", + " while (true) {", + " if (Array.isArray(list[i])) {", + " \tlist.splice(i, 1, ...list[i]);", + " } else {", + " \tbreak;", + " }", + " }", + " }", + " return list;", + "}", + "", + "Result is always: ", + "
    [1, 2, 3, 4, 5, 6, 7, 8]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e63", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function flatten(list) {\n return list.reduce(function (acc, val) {\n return acc.concat(val.constructor === Array ? flatten(val) : val);\n }, []);\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Floyd's triangle", + "type": "Waypoint", + "description": [ + "

    Floyd's triangle lists the natural numbers in a right triangle aligned to the left where

    ", + "the first row is 1 (unity)", + "successive rows start towards the left with the next number followed by successive naturals listing one more number than the line above.

    The first few lines of a Floyd triangle looks like this:

    ", + "
    ",
    +        " 1",
    +        " 2  3",
    +        " 4  5  6",
    +        " 7  8  9 10",
    +        "11 12 13 14 15",
    +        "
    ", + "Task:", + "

    # Write a program to generate and display here the first n lines of a Floyd triangle. (Use n=5 and n=14 rows).

    ", + "

    # Ensure that when displayed in a mono-space font, the numbers line up in vertical columns as shown and that only one space separates numbers of the last row.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "=== ES5 ===", + "(In a functional idiom of JavaScript)", + "", + "Two main functions:", + ":#An expression of the Floyd triangle as a list of lists (a function of the number of rows),", + ":#and a mapping of that expression to a formatted string.", + "", + "(function () {", + " 'use strict';", + "", + " // FLOYD's TRIANGLE -------------------------------------------------------", + "", + " // floyd :: Int -> [[Int]]", + " function floyd(n) {", + " return snd(mapAccumL(function (start, row) {", + " return [start + row + 1, enumFromTo(start, start + row)];", + " }, 1, enumFromTo(0, n - 1)));", + " };", + "", + " // showFloyd :: [[Int]] -> String", + " function showFloyd(xss) {", + " var ws = map(compose([succ, length, show]), last(xss));", + " return unlines(map(function (xs) {", + " return concat(zipWith(function (w, x) {", + " return justifyRight(w, ' ', show(x));", + " }, ws, xs));", + " }, xss));", + " };", + "", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // compose :: [(a -> a)] -> (a -> a)", + " function compose(fs) {", + " return function (x) {", + " return fs.reduceRight(function (a, f) {", + " return f(a);", + " }, x);", + " };", + " };", + "", + " // concat :: [[a]] -> [a] | [String] -> String", + " function concat(xs) {", + " if (xs.length > 0) {", + " var unit = typeof xs[0] === 'string' ? '' : [];", + " return unit.concat.apply(unit, xs);", + " } else return [];", + " };", + "", + " // enumFromTo :: Int -> Int -> [Int]", + " function enumFromTo(m, n) {", + " return Array.from({", + " length: Math.floor(n - m) + 1", + " }, function (_, i) {", + " return m + i;", + " });", + " };", + "", + " // justifyRight :: Int -> Char -> Text -> Text", + " function justifyRight(n, cFiller, strText) {", + " return n > strText.length ? (cFiller.repeat(n) + strText)", + " .slice(-n) : strText;", + " };", + "", + " // last :: [a] -> a", + " function last(xs) {", + " return xs.length ? xs.slice(-1)[0] : undefined;", + " };", + "", + " // length :: [a] -> Int", + " function length(xs) {", + " return xs.length;", + " };", + "", + " // map :: (a -> b) -> [a] -> [b]", + " function map(f, xs) {", + " return xs.map(f);", + " };", + "", + " // 'The mapAccumL function behaves like a combination of map and foldl;", + " // it applies a function to each element of a list, passing an accumulating", + " // parameter from left to right, and returning a final value of this", + " // accumulator together with the new list.' (See hoogle )", + "", + " // mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])", + " function mapAccumL(f, acc, xs) {", + " return xs.reduce(function (a, x) {", + " var pair = f(a[0], x);", + "", + " return [pair[0], a[1].concat([pair[1]])];", + " }, [acc, []]);", + " };", + "", + " // show ::", + " // (a -> String) f, Num n =>", + " // a -> maybe f -> maybe n -> String", + " var show = JSON.stringify;", + "", + " // snd :: (a, b) -> b", + " function snd(tpl) {", + " return Array.isArray(tpl) ? tpl[1] : undefined;", + " };", + "", + " // succ :: Int -> Int", + " function succ(x) {", + " return x + 1;", + " };", + "", + " // unlines :: [String] -> String", + " function unlines(xs) {", + " return xs.join('\\n');", + " };", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " function zipWith(f, xs, ys) {", + " var ny = ys.length;", + " return (xs.length <= ny ? xs : xs.slice(0, ny))", + " .map(function (x, i) {", + " return f(x, ys[i]);", + " });", + " };", + "", + " // TEST ( n=5 and n=14 rows ) ---------------------------------------------", + "", + " return unlines(map(function (n) {", + " return showFloyd(floyd(n)) + '\\n';", + " }, [5, 14]));", + "})();", + "{{Out}}", + "
      1",
    +        "  2  3",
    +        "  4  5  6",
    +        "  7  8  9 10",
    +        " 11 12 13 14 15",
    +        "",
    +        "  1",
    +        "  2  3",
    +        "  4  5  6",
    +        "  7  8  9 10",
    +        " 11 12 13 14 15",
    +        " 16 17 18 19 20 21",
    +        " 22 23 24 25 26 27 28",
    +        " 29 30 31 32 33 34 35 36",
    +        " 37 38 39 40 41 42 43 44  45",
    +        " 46 47 48 49 50 51 52 53  54  55",
    +        " 56 57 58 59 60 61 62 63  64  65  66",
    +        " 67 68 69 70 71 72 73 74  75  76  77  78",
    +        " 79 80 81 82 83 84 85 86  87  88  89  90  91",
    +        " 92 93 94 95 96 97 98 99 100 101 102 103 104 105
    ", + "", + "===ES6===", + "{{Trans|Haskell}} (mapAccumL version)", + "(() => {", + " 'use strict';", + "", + " // FLOYD's TRIANGLE -------------------------------------------------------", + "", + " // floyd :: Int -> [[Int]]", + " const floyd = n => snd(mapAccumL(", + " (start, row) => [start + row + 1, enumFromTo(start, start + row)],", + " 1, enumFromTo(0, n - 1)", + " ));", + "", + " // showFloyd :: [[Int]] -> String", + " const showFloyd = xss => {", + " const ws = map(compose([succ, length, show]), last(xss));", + " return unlines(", + " map(xs => concat(zipWith(", + " (w, x) => justifyRight(w, ' ', show(x)), ws, xs", + " )),", + " xss", + " )", + " );", + " };", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // compose :: [(a -> a)] -> (a -> a)", + " const compose = fs => x => fs.reduceRight((a, f) => f(a), x);", + "", + " // concat :: [[a]] -> [a] | [String] -> String", + " const concat = xs => {", + " if (xs.length > 0) {", + " const unit = typeof xs[0] === 'string' ? '' : [];", + " return unit.concat.apply(unit, xs);", + " } else return [];", + " };", + "", + " // enumFromTo :: Int -> Int -> [Int]", + " const enumFromTo = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // justifyRight :: Int -> Char -> Text -> Text", + " const justifyRight = (n, cFiller, strText) =>", + " n > strText.length ? (", + " (cFiller.repeat(n) + strText)", + " .slice(-n)", + " ) : strText;", + "", + " // last :: [a] -> a", + " const last = xs => xs.length ? xs.slice(-1)[0] : undefined;", + "", + " // length :: [a] -> Int", + " const length = xs => xs.length;", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = (f, xs) => xs.map(f)", + "", + " // 'The mapAccumL function behaves like a combination of map and foldl;", + " // it applies a function to each element of a list, passing an accumulating", + " // parameter from left to right, and returning a final value of this", + " // accumulator together with the new list.' (See hoogle )", + "", + " // mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])", + " const mapAccumL = (f, acc, xs) =>", + " xs.reduce((a, x) => {", + " const pair = f(a[0], x);", + "", + " return [pair[0], a[1].concat([pair[1]])];", + " }, [acc, []]);", + "", + " // show ::", + " // (a -> String) f, Num n =>", + " // a -> maybe f -> maybe n -> String", + " const show = JSON.stringify;", + "", + " // snd :: (a, b) -> b", + " const snd = tpl => Array.isArray(tpl) ? tpl[1] : undefined;", + "", + " // succ :: Int -> Int", + " const succ = x => x + 1", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " const zipWith = (f, xs, ys) => {", + " const ny = ys.length;", + " return (xs.length <= ny ? xs : xs.slice(0, ny))", + " .map((x, i) => f(x, ys[i]));", + " };", + "", + " // TEST ( n=5 and n=14 rows ) ---------------------------------------------", + "", + " return unlines(map(n => showFloyd(floyd(n)) + '\\n', [5, 14]))", + "})();", + "{{Out}}", + "
      1",
    +        "  2  3",
    +        "  4  5  6",
    +        "  7  8  9 10",
    +        " 11 12 13 14 15",
    +        "",
    +        "  1",
    +        "  2  3",
    +        "  4  5  6",
    +        "  7  8  9 10",
    +        " 11 12 13 14 15",
    +        " 16 17 18 19 20 21",
    +        " 22 23 24 25 26 27 28",
    +        " 29 30 31 32 33 34 35 36",
    +        " 37 38 39 40 41 42 43 44  45",
    +        " 46 47 48 49 50 51 52 53  54  55",
    +        " 56 57 58 59 60 61 62 63  64  65  66",
    +        " 67 68 69 70 71 72 73 74  75  76  77  78",
    +        " 79 80 81 82 83 84 85 86  87  88  89  90  91",
    +        " 92 93 94 95 96 97 98 99 100 101 102 103 104 105
    ", + "", + "=== Spidermonkey ===", + "", + "(Used TCL example as a starting point.)", + "", + "#!/usr/bin/env js", + "", + "function main() {", + " print('Floyd 5:');", + " floyd(5);", + " print('\\nFloyd 14:');", + " floyd(14);", + "}", + "", + "", + "function padLeft(s, w) {", + " for (s = String(s); s.length < w; s = ' ' + s);", + " return s;", + "}", + "", + "", + "function floyd(nRows) {", + " var lowerLeft = nRows * (nRows - 1) / 2 + 1;", + " var lowerRight = nRows * (nRows + 1) / 2;", + " ", + " var colWidths = [];", + " for (var col = lowerLeft; col <= lowerRight; col++) {", + " colWidths.push(String(col).length);", + " }", + "", + " var num = 1;", + " for (var row = 0; row < nRows; row++) {", + " var line = [];", + " for (var col = 0; col <= row; col++, num++) {", + " line.push(padLeft(num, colWidths[col]));", + " }", + " print(line.join(' '));", + " }", + "}", + "", + "main();", + "", + "{{out}}", + "
     Floyd 5:",
    +        "  1",
    +        "  2  3",
    +        "  4  5  6",
    +        "  7  8  9 10",
    +        " 11 12 13 14 15",
    +        " ",
    +        " Floyd 14:",
    +        "  1",
    +        "  2  3",
    +        "  4  5  6",
    +        "  7  8  9 10",
    +        " 11 12 13 14 15",
    +        " 16 17 18 19 20 21",
    +        " 22 23 24 25 26 27 28",
    +        " 29 30 31 32 33 34 35 36",
    +        " 37 38 39 40 41 42 43 44  45",
    +        " 46 47 48 49 50 51 52 53  54  55",
    +        " 56 57 58 59 60 61 62 63  64  65  66",
    +        " 67 68 69 70 71 72 73 74  75  76  77  78",
    +        " 79 80 81 82 83 84 85 86  87  88  89  90  91",
    +        " 92 93 94 95 96 97 98 99 100 101 102 103 104 105
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e66", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function () {\n 'use strict';\n\n // FLOYD's TRIANGLE -------------------------------------------------------\n\n // floyd :: Int -> [[Int]]\n function floyd(n) {\n return snd(mapAccumL(function (start, row) {\n return [start + row + 1, enumFromTo(start, start + row)];\n }, 1, enumFromTo(0, n - 1)));\n };\n\n // showFloyd :: [[Int]] -> String\n function showFloyd(xss) {\n var ws = map(compose([succ, length, show]), last(xss));\n return unlines(map(function (xs) {\n return concat(zipWith(function (w, x) {\n return justifyRight(w, ' ', show(x));\n }, ws, xs));\n }, xss));\n };\n\n\n // GENERIC FUNCTIONS ------------------------------------------------------\n\n // compose :: [(a -> a)] -> (a -> a)\n function compose(fs) {\n return function (x) {\n return fs.reduceRight(function (a, f) {\n return f(a);\n }, x);\n };\n };\n\n // concat :: [[a]] -> [a] | [String] -> String\n function concat(xs) {\n if (xs.length > 0) {\n var unit = typeof xs[0] === 'string' ? '' : [];\n return unit.concat.apply(unit, xs);\n } else return [];\n };\n\n // enumFromTo :: Int -> Int -> [Int]\n function enumFromTo(m, n) {\n return Array.from({\n length: Math.floor(n - m) + 1\n }, function (_, i) {\n return m + i;\n });\n };\n\n // justifyRight :: Int -> Char -> Text -> Text\n function justifyRight(n, cFiller, strText) {\n return n > strText.length ? (cFiller.repeat(n) + strText)\n .slice(-n) : strText;\n };\n\n // last :: [a] -> a\n function last(xs) {\n return xs.length ? xs.slice(-1)[0] : undefined;\n };\n\n // length :: [a] -> Int\n function length(xs) {\n return xs.length;\n };\n\n // map :: (a -> b) -> [a] -> [b]\n function map(f, xs) {\n return xs.map(f);\n };\n\n // 'The mapAccumL function behaves like a combination of map and foldl;\n // it applies a function to each element of a list, passing an accumulating\n // parameter from left to right, and returning a final value of this\n // accumulator together with the new list.' (See hoogle )\n\n // mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])\n function mapAccumL(f, acc, xs) {\n return xs.reduce(function (a, x) {\n var pair = f(a[0], x);\n\n return [pair[0], a[1].concat([pair[1]])];\n }, [acc, []]);\n };\n\n // show ::\n // (a -> String) f, Num n =>\n // a -> maybe f -> maybe n -> String\n var show = JSON.stringify;\n\n // snd :: (a, b) -> b\n function snd(tpl) {\n return Array.isArray(tpl) ? tpl[1] : undefined;\n };\n\n // succ :: Int -> Int\n function succ(x) {\n return x + 1;\n };\n\n // unlines :: [String] -> String\n function unlines(xs) {\n return xs.join('\\n');\n };\n\n // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]\n function zipWith(f, xs, ys) {\n var ny = ys.length;\n return (xs.length <= ny ? xs : xs.slice(0, ny))\n .map(function (x, i) {\n return f(x, ys[i]);\n });\n };\n\n // TEST ( n=5 and n=14 rows ) ---------------------------------------------\n\n return unlines(map(function (n) {\n return showFloyd(floyd(n)) + '\\n';\n }, [5, 14]));\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Floyd-Warshall algorithm", + "type": "Waypoint", + "description": [ + "

    The Floyd–Warshall algorithm is an algorithm for finding shortest paths in a weighted graph with positive or negative edge weights.

    ", + "Task", + "

    Find the lengths of the shortest paths between all pairs of vertices of the given directed graph. Your code may assume that the input has already been checked for loops, parallel edges and negative cycles.

    ", + "

    Print the pair, the distance and (optionally) the path.

    ", + "Example", + "
    pair     dist    path",
    +        "1 -> 2    -1     1 -> 3 -> 4 -> 2",
    +        "1 -> 3    -2     1 -> 3",
    +        "1 -> 4     0     1 -> 3 -> 4",
    +        "2 -> 1     4     2 -> 1",
    +        "2 -> 3     2     2 -> 1 -> 3",
    +        "2 -> 4     4     2 -> 1 -> 3 -> 4",
    +        "3 -> 1     5     3 -> 4 -> 2 -> 1",
    +        "3 -> 2     1     3 -> 4 -> 2",
    +        "3 -> 4     2     3 -> 4",
    +        "4 -> 1     3     4 -> 2 -> 1",
    +        "4 -> 2    -1     4 -> 2",
    +        "4 -> 3     1     4 -> 2 -> 1 -> 3
    ", + "See also", + "Floyd-Warshall Algorithm - step by step guide (youtube)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "var graph = [];", + "for (i = 0; i < 10; ++i) {", + " graph.push([]);", + " for (j = 0; j < 10; ++j)", + " graph[i].push(i == j ? 0 : 9999999);", + "}", + "", + "for (i = 1; i < 10; ++i) {", + " graph[0][i] = graph[i][0] = parseInt(Math.random() * 9 + 1);", + "}", + "", + "for (k = 0; k < 10; ++k) {", + " for (i = 0; i < 10; ++i) {", + " for (j = 0; j < 10; ++j) {", + " if (graph[i][j] > graph[i][k] + graph[k][j])", + " graph[i][j] = graph[i][k] + graph[k][j]", + " }", + " }", + "}", + "", + "console.log(graph);", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e67", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var graph = [];\nfor (i = 0; i < 10; ++i) {\n graph.push([]);\n for (j = 0; j < 10; ++j)\n graph[i].push(i == j ? 0 : 9999999);\n}\n\nfor (i = 1; i < 10; ++i) {\n graph[0][i] = graph[i][0] = parseInt(Math.random() * 9 + 1);\n}\n\nfor (k = 0; k < 10; ++k) {\n for (i = 0; i < 10; ++i) {\n for (j = 0; j < 10; ++j) {\n if (graph[i][j] > graph[i][k] + graph[k][j])\n graph[i][j] = graph[i][k] + graph[k][j]\n }\n }\n}\n\nconsole.log(graph);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Formal power series", + "type": "Waypoint", + "description": [ + "

    A power series is an infinite sum of the form

    $a_0 + a_1 \\cdot x + a_2 \\cdot x^2 + a_3 \\cdot x^3 + \\cdots$

    The ai are called the coefficients of the series. Such sums can be added, multiplied etc., where the new coefficients of the powers of x are calculated according to the usual rules.

    If one is not interested in evaluating such a series for particular values of x, or in other words, if convergence doesn't play a role, then such a collection of coefficients is called formal power series. It can be treated like a new kind of number.

    Task: Implement formal power series as a numeric type. Operations should at least include addition, multiplication, division and additionally non-numeric operations like differentiation and integration (with an integration constant of zero). Take care that your implementation deals with the potentially infinite number of coefficients.

    As an example, define the power series of sine and cosine in terms of each other using integration, as in

    $\\sin x = \\int_0^x \\cos t\\, dt$

    $\\cos x = 1 - \\int_0^x \\sin t\\, dt$

    Goals: Demonstrate how the language handles new numeric types and delayed (or lazy) evaluation.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e6a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Formatted numeric output", + "type": "Waypoint", + "description": [ + "Task:", + "

    Express a number in decimal as a fixed-length string with leading zeros.

    ", + "

    For example, the number 7.125 could be expressed as 00007.125.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "var n = 123;", + "var str = (\"00000\" + n).slice(-5);", + "alert(str);", + "", + "or, put in browser URL: javascript:n=123;alert((\"00000\"+n).slice(-5));", + "", + "Also, a 60-line implementation of sprintf can be found [http://code.google.com/p/sprintf/ here].", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e6b", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var n = 123;\nvar str = (\"00000\" + n).slice(-5);\nalert(str);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Forward difference", + "type": "Waypoint", + "description": [ + "Task:", + "

    Provide code that produces a list of numbers which is the nth order forward difference, given a non-negative integer (specifying the order) and a list of numbers.

    ", + "

    The first-order forward difference of a list of numbers A is a new list B, where Bn = An+1 - An.

    List B should have one fewer element as a result.

    The second-order forward difference of A will be:

    ", + "
    ",
    +        "tdefmodule Diff do",
    +        "\tdef forward(arr,i\\\\1) do",
    +        "\t\tforward(arr,[],i)",
    +        "\tend\tdef forward([_|[]],diffs,i) do",
    +        "\t\tif i == 1 do",
    +        "\t\t\tIO.inspect diffs",
    +        "\t\telse ",
    +        "\t\t\tforward(diffs,[],i-1)",
    +        "\t\tend",
    +        "\tend\tdef forward([val1|[val2|vals]],diffs,i) do",
    +        "\t\tforward([val2|vals],diffs++[val2-val1],i) ",
    +        "\tend",
    +        "end ",
    +        "
    ", + "

    The same as the first-order forward difference of B.

    That new list will have two fewer elements than A and one less than B.

    The goal of this task is to repeat this process up to the desired order.

    For a more formal description, see the related Mathworld article.

    ", + "Algorithmic options:", + "Iterate through all previous forward differences and re-calculate a new array each time.", + "Use this formula (from Wikipedia):", + "

    :: $\\Delta^n [f](x)= \\sum_{k=0}^n {n \\choose k} (-1)^{n-k} f(x+k)$

    ", + "
    ", + "

    :: (Pascal's Triangle may be useful for this option.)

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES6===", + "", + "(() => {", + " 'use strict';", + "", + " // forwardDifference :: [Int] -> [Int]", + " const forwardDifference = (n, xs) => {", + " const fd = xs => zipWith((a, b) => a - b, tail(xs), xs);", + " return until(", + " m => m.index < 1,", + " m => ({", + " index: m.index - 1,", + " list: fd(m.list)", + " }), {", + " index: n,", + " list: xs", + " }", + " )", + " .list;", + " };", + "", + "", + " // GENERIC FUNCTIONS ---------------------------------------", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " const zipWith = (f, xs, ys) => {", + " const ny = ys.length;", + " return (xs.length <= ny ? xs : xs.slice(0, ny))", + " .map((x, i) => f(x, ys[i]));", + " };", + "", + " // until :: (a -> Bool) -> (a -> a) -> a -> a", + " const until = (p, f, x) => {", + " const go = x => p(x) ? x : go(f(x));", + " return go(x);", + " };", + "", + " // tail :: [a] -> [a]", + " const tail = xs => xs.length ? xs.slice(1) : undefined;", + "", + "", + " // TEST ----------------------------------------------------", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x);", + "", + " // Sample", + " const test = [90, 47, 58, 29, 22, 32, 55, 5, 55, 73];", + "", + " return range(1, 9)", + " .map(x => `${x} ${show(forwardDifference(x, test))}`)", + " .join('\\n');", + "})();", + "", + "{{Out}}", + "
    1    [-43,11,-29,-7,10,23,-50,50,18]",
    +        "2    [54,-40,22,17,13,-73,100,-32]",
    +        "3    [-94,62,-5,-4,-86,173,-132]",
    +        "4    [156,-67,1,-82,259,-305]",
    +        "5    [-223,68,-83,341,-564]",
    +        "6    [291,-151,424,-905]",
    +        "7    [-442,575,-1329]",
    +        "8    [1017,-1904]",
    +        "9    [-2921]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e6c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n 'use strict';\n\n // forwardDifference :: [Int] -> [Int]\n const forwardDifference = (n, xs) => {\n const fd = xs => zipWith((a, b) => a - b, tail(xs), xs);\n return until(\n m => m.index < 1,\n m => ({\n index: m.index - 1,\n list: fd(m.list)\n }), {\n index: n,\n list: xs\n }\n )\n .list;\n };\n\n\n // GENERIC FUNCTIONS ---------------------------------------\n\n // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]\n const zipWith = (f, xs, ys) => {\n const ny = ys.length;\n return (xs.length <= ny ? xs : xs.slice(0, ny))\n .map((x, i) => f(x, ys[i]));\n };\n\n // until :: (a -> Bool) -> (a -> a) -> a -> a\n const until = (p, f, x) => {\n const go = x => p(x) ? x : go(f(x));\n return go(x);\n };\n\n // tail :: [a] -> [a]\n const tail = xs => xs.length ? xs.slice(1) : undefined;\n\n\n // TEST ----------------------------------------------------\n\n // range :: Int -> Int -> [Int]\n const range = (m, n) =>\n Array.from({\n length: Math.floor(n - m) + 1\n }, (_, i) => m + i);\n\n // show :: a -> String\n const show = x => JSON.stringify(x);\n\n // Sample\n const test = [90, 47, 58, 29, 22, 32, 55, 5, 55, 73];\n\n return range(1, 9)\n .map(x => `${x} ${show(forwardDifference(x, test))}`)\n .join('\\n');\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Four bit adder", + "type": "Waypoint", + "description": [ + "Task:", + "

    \"Simulate\" a four-bit adder \"chip\".

    This \"chip\" can be realized using four 1-bit full adders.

    ", + "

    Each of these 1-bit full adders can be built with two half adders and an or gate. Finally a half adder can be made using a xor gate and an and gate.

    ", + "

    The xor gate can be made using two nots, two ands and one or.

    Not, or and and, the only allowed \"gates\" for the task, can be \"imitated\" by using the bitwise operators of your language.

    ", + "

    If there is not a bit type in your language, to be sure that the not does not \"invert\" all the other bits of the basic type (e.g. a byte) we are not interested in, you can use an extra nand (and then not) with the constant 1 on one input.

    Instead of optimizing and reducing the number of gates used for the final 4-bit adder, build it in the most straightforward way, connecting the other \"constructive blocks\", in turn made of \"simpler\" and \"smaller\" ones.

    {|

    ", + "

    |+Schematics of the \"constructive blocks\"

    ", + "

    !Xor gate done with ands, ors and nots

    ", + "

    !A half adder

    ", + "

    !A full adder

    ", + "

    !A 4-bit adder

    ", + "

    |-

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |}

    Solutions should try to be as descriptive as possible, making it as easy as possible to identify \"connections\" between higher-order \"blocks\".

    ", + "

    It is not mandatory to replicate the syntax of higher-order blocks in the atomic \"gate\" blocks, i.e. basic \"gate\" operations can be performed as usual bitwise operations, or they can be \"wrapped\" in a block in order to expose the same syntax of higher-order blocks, at implementers' choice.

    To test the implementation, show the sum of two four-bit numbers (in binary).

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Error Handling===", + "In order to keep the binary-ness obvious, all operations will occur on ", + "0s and 1s. To enforce this, we'll first create a couple of helper functions.", + "", + "", + "function acceptedBinFormat(bin) {", + " if (bin == 1 || bin === 0 || bin === '0')", + " return true;", + " else", + " return bin;", + "}", + "", + "function arePseudoBin() {", + " var args = [].slice.call(arguments), len = args.length;", + " while(len--)", + " if (acceptedBinFormat(args[len]) !== true)", + " throw new Error('argument must be 0, \\'0\\', 1, or \\'1\\', argument ' + len + ' was ' + args[len]);", + " return true;", + "}", + "", + "", + "===Implementation===", + "Now we build up the gates, starting with 'not' and 'and' as building blocks.", + "Those allow us to construct 'nand', 'or', and 'xor' then a half and full adders", + "and, finally, the four bit adder.", + "", + "", + "// basic building blocks allowed by the rules are ~, &, and |, we'll fake these", + "// in a way that makes what they do (at least when you use them) more obvious ", + "// than the other available options do.", + "", + "function not(a) {", + " if (arePseudoBin(a))", + " return a == 1 ? 0 : 1;", + "}", + "", + "function and(a, b) {", + " if (arePseudoBin(a, b))", + " return a + b < 2 ? 0 : 1;", + "}", + "", + "function nand(a, b) {", + " if (arePseudoBin(a, b))", + " return not(and(a, b));", + "}", + "", + "function or(a, b) {", + " if (arePseudoBin(a, b))", + " return nand(nand(a,a), nand(b,b));", + "}", + "", + "function xor(a, b) {", + " if (arePseudoBin(a, b))", + " return nand(nand(nand(a,b), a), nand(nand(a,b), b));", + "}", + "", + "function halfAdder(a, b) {", + " if (arePseudoBin(a, b))", + " return { carry: and(a, b), sum: xor(a, b) };", + "}", + "", + "function fullAdder(a, b, c) {", + " if (arePseudoBin(a, b, c)) {", + " var h0 = halfAdder(a, b), ", + " h1 = halfAdder(h0.sum, c);", + " return {carry: or(h0.carry, h1.carry), sum: h1.sum };", + " }", + "}", + "", + "function fourBitAdder(a, b) {", + " if (typeof a.length == 'undefined' || typeof b.length == 'undefined')", + " throw new Error('bad values');", + " // not sure if the rules allow this, but we need to pad the values ", + " // if they're too short and trim them if they're too long", + " var inA = Array(4), ", + " inB = Array(4), ", + " out = Array(4), ", + " i = 4, ", + " pass;", + " ", + " while (i--) {", + " inA[i] = a[i] != 1 ? 0 : 1;", + " inB[i] = b[i] != 1 ? 0 : 1;", + " }", + "", + " // now we can start adding... I'd prefer to do this in a loop, ", + " // but that wouldn't be \"connecting the other 'constructive blocks', ", + " // in turn made of 'simpler' and 'smaller' ones\"", + " ", + " pass = halfAdder(inA[3], inB[3]);", + " out[3] = pass.sum;", + " pass = fullAdder(inA[2], inB[2], pass.carry);", + " out[2] = pass.sum;", + " pass = fullAdder(inA[1], inB[1], pass.carry);", + " out[1] = pass.sum;", + " pass = fullAdder(inA[0], inB[0], pass.carry);", + " out[0] = pass.sum;", + " return out.join('');", + "}", + "", + "===Example Use===", + "fourBitAdder('1010', '0101'); // 1111 (15)", + "", + "all results:", + "", + "", + "// run this in your browsers console", + "var outer = inner = 16, a, b;", + "", + "while(outer--) {", + " a = (8|outer).toString(2);", + " while(inner--) {", + " b = (8|inner).toString(2);", + " console.log(a + ' + ' + b + ' = ' + fourBitAdder(a, b));", + " }", + " inner = outer;", + "}", + "", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e6d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nfunction acceptedBinFormat(bin) {\n if (bin == 1 || bin === 0 || bin === '0')\n return true;\n else\n return bin;\n}\n\nfunction arePseudoBin() {\n var args = [].slice.call(arguments), len = args.length;\n while(len--)\n if (acceptedBinFormat(args[len]) !== true)\n throw new Error('argument must be 0, \\'0\\', 1, or \\'1\\', argument ' + len + ' was ' + args[len]);\n return true;\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Fractran", + "type": "Waypoint", + "description": [ + "

    FRACTRAN is a Turing-complete esoteric programming language invented by the mathematician John Horton Conway.

    A FRACTRAN program is an ordered list of positive fractions $P = (f_1, f_2, \\ldots, f_m)$, together with an initial positive integer input $n$.

    ", + "

    The program is run by updating the integer $n$ as follows:

    for the first fraction, $f_i$, in the list for which $nf_i$ is an integer, replace $n$ with $nf_i$ ;", + "repeat this rule until no fraction in the list produces an integer when multiplied by $n$, then halt.", + "

    Conway gave a program for primes in FRACTRAN:

    $17/91$, $78/85$, $19/51$, $23/38$, $29/33$, $77/29$, $95/23$, $77/19$, $1/17$, $11/13$, $13/11$, $15/14$, $15/2$, $55/1$

    Starting with $n=2$, this FRACTRAN program will change $n$ to $15=2\\times (15/2)$, then $825=15\\times (55/1)$, generating the following sequence of integers:

    $2$, $15$, $825$, $725$, $1925$, $2275$, $425$, $390$, $330$, $290$, $770$, $\\ldots$

    After 2, this sequence contains the following powers of 2:

    $2^2=4$, $2^3=8$, $2^5=32$, $2^7=128$, $2^{11}=2048$, $2^{13}=8192$, $2^{17}=131072$, $2^{19}=524288$, $\\ldots$

    which are the prime powers of 2.

    ", + "Task:", + "

    Write a program that reads a list of fractions in a natural format from the keyboard or from a string,

    ", + "

    to parse it into a sequence of fractions (i.e. two integers),

    ", + "

    and runs the FRACTRAN starting from a provided integer, writing the result at each step.

    ", + "

    It is also required that the number of step is limited (by a parameter easy to find).

    ", + "Extra credit:", + "

    Use this program to derive the first 20 or so prime numbers.

    ", + "See also:", + "

    For more on how to program FRACTRAN as a universal programming language, see:

    ", + "J. H. Conway (1987). Fractran: A Simple Universal Programming Language for Arithmetic. In: Open Problems in Communication and Computation, pages 4–26. Springer.", + "J. H. Conway (2010). \"FRACTRAN: A simple universal programming language for arithmetic\". In Jeffrey C. Lagarias. The Ultimate Challenge: the 3x+1 problem. American Mathematical Society. pp. 249–264. ISBN 978-0-8218-4940-8. Zbl 1216.68068.", + "Number Pathology: Fractran by Mark C. Chu-Carroll; October 27, 2006." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "var num = new Array();", + "var den = new Array();", + "var val ;", + "", + "function compile(prog){", + " var regex = /\\s*(\\d*)\\s*\\/\\s*(\\d*)\\s*(.*)/m;", + " while(regex.test(prog)){", + " num.push(regex.exec(prog)[1]);", + " den.push(regex.exec(prog)[2]);", + " prog = regex.exec(prog)[3];", + " }", + "}", + "", + "function dump(prog){", + " for(var i=0; i\";", + "}", + "", + "function step(val){", + " var i=0;", + " while(i\";", + " val = step(val);", + " i ++;", + " }", + "}", + "", + "// Main", + "compile(\"17/91 78/85 19/51 23/38 29/33 77/29 95/23 77/19 1/17 11/13 13/11 15/14 15/2 55/1\");", + "dump(); ", + "var limit = 15;", + "exec(2);", + "", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e6f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nvar num = new Array();\nvar den = new Array();\nvar val ;\n\nfunction compile(prog){\n var regex = /\\s*(\\d*)\\s*\\/\\s*(\\d*)\\s*(.*)/m;\n while(regex.test(prog)){\n num.push(regex.exec(prog)[1]);\n den.push(regex.exec(prog)[2]);\n prog = regex.exec(prog)[3];\n }\n}\n\nfunction dump(prog){\n for(var i=0; i\";\n}\n\nfunction step(val){\n var i=0;\n while(i\";\n val = step(val);\n i ++;\n }\n}\n\n// Main\ncompile(\"17/91 78/85 19/51 23/38 29/33 77/29 95/23 77/19 1/17 11/13 13/11 15/14 15/2 55/1\");\ndump(); \nvar limit = 15;\nexec(2);\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Gamma function", + "type": "Waypoint", + "description": [ + "Task:", + "

    Implement one algorithm (or more) to compute the Gamma ($\\Gamma$) function (in the real field only).

    If your language has the function as built-in or you know a library which has it, compare your implementation's results with the results of the built-in/library function.

    The Gamma function can be defined as:

    ::::: $\\Gamma(x) = \\displaystyle\\int_0^\\infty t^{x-1}e^{-t} dt$

    This suggests a straightforward (but inefficient) way of computing the $\\Gamma$ through numerical integration.

    ", + "

    Better suggested methods:

    ", + "Lanczos approximation", + "Stirling's approximation" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Implementation of Lanczos approximation.", + "function gamma(x) {", + " var p = [0.99999999999980993, 676.5203681218851, -1259.1392167224028,", + " 771.32342877765313, -176.61502916214059, 12.507343278686905,", + " -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7", + " ];", + "", + " var g = 7;", + " if (x < 0.5) {", + " return Math.PI / (Math.sin(Math.PI * x) * gamma(1 - x));", + " }", + "", + " x -= 1;", + " var a = p[0];", + " var t = x + g + 0.5;", + " for (var i = 1; i < p.length; i++) {", + " a += p[i] / (x + i);", + " }", + "", + " return Math.sqrt(2 * Math.PI) * Math.pow(t, x + 0.5) * Math.exp(-t) * a;", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e76", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function gamma(x) {\n var p = [0.99999999999980993, 676.5203681218851, -1259.1392167224028,\n 771.32342877765313, -176.61502916214059, 12.507343278686905,\n -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7\n ];\n\n var g = 7;\n if (x < 0.5) {\n return Math.PI / (Math.sin(Math.PI * x) * gamma(1 - x));\n }\n\n x -= 1;\n var a = p[0];\n var t = x + g + 0.5;\n for (var i = 1; i < p.length; i++) {\n a += p[i] / (x + i);\n }\n\n return Math.sqrt(2 * Math.PI) * Math.pow(t, x + 0.5) * Math.exp(-t) * a;\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Gaussian elimination", + "type": "Waypoint", + "description": [ + "

    Problem: Solve Ax=b using Gaussian elimination then backwards substitution. A being an n by n matrix. Also, x and b are n by 1 vectors. To improve accuracy, please use partial pivoting and scaling.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "From Numerical Recipes in C:", + "// Lower Upper Solver", + "function lusolve(A, b, update) {", + "\tvar lu = ludcmp(A, update)", + "\tif (lu === undefined) return // Singular Matrix!", + "\treturn lubksb(lu, b, update)", + "}", + "", + "// Lower Upper Decomposition", + "function ludcmp(A, update) {", + "\t// A is a matrix that we want to decompose into Lower and Upper matrices.", + "\tvar d = true", + "\tvar n = A.length", + "\tvar idx = new Array(n) // Output vector with row permutations from partial pivoting", + "\tvar vv = new Array(n) // Scaling information", + "", + "\tfor (var i=0; i max) max = temp", + "\t\t}", + "\t\tif (max == 0) return // Singular Matrix!", + "\t\tvv[i] = 1 / max // Scaling", + "\t}", + "\t", + "\tif (!update) { // make a copy of A ", + "\t\tvar Acpy = new Array(n)", + "\t\tfor (var i=0; i= max) {", + "\t\t\t\tmax = temp", + "\t\t\t\tjmax = j", + "\t\t\t}", + "\t\t}", + "\t\tif (i <= jmax) {", + "\t\t\tfor (var j=0; j -1)", + "\t\t\tfor (var j=ii; j=0; i--) {", + "\t\tvar sum = b[i]", + "\t\tfor (var j=i+1; j", + "", + "{{output}}", + "
    -0.01000000000000004, 1.6027903945021095, -1.6132030599055475, 1.2454941213714232, -0.4909897195846526, 0.06576069617523138
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e77", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// Lower Upper Solver\nfunction lusolve(A, b, update) {\n\tvar lu = ludcmp(A, update)\n\tif (lu === undefined) return // Singular Matrix!\n\treturn lubksb(lu, b, update)\n}\n\n// Lower Upper Decomposition\nfunction ludcmp(A, update) {\n\t// A is a matrix that we want to decompose into Lower and Upper matrices.\n\tvar d = true\n\tvar n = A.length\n\tvar idx = new Array(n) // Output vector with row permutations from partial pivoting\n\tvar vv = new Array(n) // Scaling information\n\n\tfor (var i=0; i max) max = temp\n\t\t}\n\t\tif (max == 0) return // Singular Matrix!\n\t\tvv[i] = 1 / max // Scaling\n\t}\n\t\n\tif (!update) { // make a copy of A \n\t\tvar Acpy = new Array(n)\n\t\tfor (var i=0; i= max) {\n\t\t\t\tmax = temp\n\t\t\t\tjmax = j\n\t\t\t}\n\t\t}\n\t\tif (i <= jmax) {\n\t\t\tfor (var j=0; j -1)\n\t\t\tfor (var j=ii; j=0; i--) {\n\t\tvar sum = b[i]\n\t\tfor (var j=i+1; jreplaceMe is a function.');" + ] + }, + { + "title": "General FizzBuzz", + "type": "Waypoint", + "description": [ + "Task:", + "

    Write a generalized version of FizzBuzz that works for any list of factors, along with their words.

    This is basically a \"fizzbuzz\" implementation where the user supplies the parameters.

    The user will enter the max number, then they will enter the factors to be calculated along with the corresponding word to be printed.

    For simplicity's sake, assume the user will input an integer as the max number and 3 factors, each with a word associated with them.

    ", + "

    For example, given:

    ", + "
    ",
    +        ">20      #This is the maximum number, supplied by the user",
    +        ">3 Fizz  #The user now enters the starting factor (3) and the word they want associated with it (Fizz)",
    +        ">5 Buzz  #The user now enters the next factor (5) and the word they want associated with it (Buzz)",
    +        ">7 Baxx  #The user now enters the next factor (7) and the word they want associated with it (Baxx)",
    +        "

    In other words: For this example, print the numbers 1 through 20, replacing every multiple of 3 with \"Fizz\", every multiple of 5 with \"Buzz\", and every multiple of 7 with \"Baxx\".

    In the case where a number is a multiple of at least two factors, print each of the words associated with those factors in the order of least to greatest factor.

    For instance, the number 15 is a multiple of both 3 and 5; print \"FizzBuzz\".

    If the max number was 105 instead of 20, you would print \"FizzBuzzBaxx\" because it's a multiple of 3, 5, and 7.

    ", + "
    ",
    +        "1",
    +        "2",
    +        "Fizz",
    +        "4",
    +        "Buzz",
    +        "Fizz",
    +        "Baxx",
    +        "8",
    +        "Fizz",
    +        "Buzz",
    +        "11",
    +        "Fizz",
    +        "13",
    +        "Baxx",
    +        "FizzBuzz",
    +        "16",
    +        "17",
    +        "Fizz",
    +        "19",
    +        "Buzz",
    +        "
    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "In a functional style of JavaScript, with two nested ''reduce'' folds – one through the integer series,", + "and one through the series of rules.", + "", + "First as compacted by Google's Closure compiler:", + "function fizz(d, e) {", + " return function b(a) {", + " return a ? b(a - 1).concat(a) : [];", + " }(e).reduce(function (b, a) {", + " return b + (d.reduce(function (b, c) {", + " return b + (a % c[0] ? \"\" : c[1]);", + " }, \"\") || a.toString()) + \"\\n\";", + " }, \"\");", + "}", + "", + "and then in the original expanded form, for better legibility:", + "", + "function fizz(lstRules, lngMax) {", + "", + " return (", + " function rng(i) {", + " return i ? rng(i - 1).concat(i) : []", + " }", + " )(lngMax).reduce(", + " function (strSeries, n) {", + "", + " // The next member of the series of lines:", + " // a word string or a number string", + " return strSeries + (", + " lstRules.reduce(", + " function (str, tplNumWord) {", + " return str + (", + " n % tplNumWord[0] ? '' : tplNumWord[1]", + " )", + " }, ''", + " ) || n.toString()", + " ) + '\\n';", + " ", + " }, ''", + " );", + "}", + "", + "fizz([[3, 'Fizz'], [5, 'Buzz'], [7, 'Baxx']], 20);", + "", + "{{out}}", + "
    1",
    +        "2",
    +        "Fizz",
    +        "4",
    +        "Buzz",
    +        "Fizz",
    +        "Baxx",
    +        "8",
    +        "Fizz",
    +        "Buzz",
    +        "11",
    +        "Fizz",
    +        "13",
    +        "Baxx",
    +        "FizzBuzz",
    +        "16",
    +        "17",
    +        "Fizz",
    +        "19",
    +        "Buzz
    ", + "", + "", + "===ES6===", + "", + "(() => {", + "", + " // fizz :: [[Int, String]] -> Int -> String", + " const fizz = (lstRules, lngMax) => range(1, lngMax)", + " .reduce((strSeries, n) =>", + "", + " // The next member of the series of lines:", + " // a word string or a number string", + " strSeries + (", + " lstRules", + " .reduce((str, tplNumWord) =>", + " str + (", + " n % tplNumWord[0] ? '' : tplNumWord[1]", + " ),", + " ''", + " ) || n.toString()", + " ) + '\\n', ''", + " );", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + "", + " return fizz([", + " [3, 'Fizz'],", + " [5, 'Buzz'],", + " [7, 'Baxx']", + " ], 20);", + "", + "})();", + "", + "", + "{{Out}}", + "
    1",
    +        "2",
    +        "Fizz",
    +        "4",
    +        "Buzz",
    +        "Fizz",
    +        "Baxx",
    +        "8",
    +        "Fizz",
    +        "Buzz",
    +        "11",
    +        "Fizz",
    +        "13",
    +        "Baxx",
    +        "FizzBuzz",
    +        "16",
    +        "17",
    +        "Fizz",
    +        "19",
    +        "Buzz",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e78", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function fizz(d, e) {\n return function b(a) {\n return a ? b(a - 1).concat(a) : [];\n }(e).reduce(function (b, a) {\n return b + (d.reduce(function (b, c) {\n return b + (a % c[0] ? \"\" : c[1]);\n }, \"\") || a.toString()) + \"\\n\";\n }, \"\");\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Generate Chess960 starting position", + "type": "Waypoint", + "description": [ + "

    Chess960 is a variant of chess created by world champion Bobby Fischer. Unlike other variants of the game, Chess960 does not require a different material, but instead relies on a random initial position, with a few constraints:

    as in the standard chess game, all eight white pawns must be placed on the second rank.", + "White pieces must stand on the first rank as in the standard game, in random column order but with the two following constraints:", + "* the bishops must be placed on opposite color squares (i.e. they must be an odd number of spaces apart or there must be an even number of spaces between them)", + "* the King must be between two rooks (with any number of other pieces between them all)", + "Black pawns and pieces must be placed respectively on the seventh and eighth ranks, mirroring the white pawns and pieces, just as in the standard game. (That is, their positions are not independently randomized.)", + "

    With those constraints there are 960 possible starting positions, thus the name of the variant.

    ", + "Task:", + "

    The purpose of this task is to write a program that can randomly generate any one of the 960 Chess960 initial positions. You will show the result as the first rank displayed with Chess symbols in Unicode: ♔♕♖♗♘ or with the letters King Queen Rook Bishop kNight.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "This conforms to Altendörfer's single die method[https://en.wikipedia.org/wiki/Chess960_starting_position#Single_die_method], though the die will give no \"needless\" numbers.", + "function ch960startPos() {", + " var rank = new Array(8),", + " // randomizer (our die)", + " d = function(num) { return Math.floor(Math.random() * ++num) },", + " emptySquares = function() {", + " var arr = [];", + " for (var i = 0; i < 8; i++) if (rank[i] == undefined) arr.push(i);", + " return arr;", + " };", + " // place one bishop on any black square", + " rank[d(2) * 2] = \"♗\";", + " // place the other bishop on any white square", + " rank[d(2) * 2 + 1] = \"♗\";", + " // place the queen on any empty square", + " rank[emptySquares()[d(5)]] = \"♕\";", + " // place one knight on any empty square", + " rank[emptySquares()[d(4)]] = \"♘\";", + " // place the other knight on any empty square", + " rank[emptySquares()[d(3)]] = \"♘\";", + " // place the rooks and the king on the squares left, king in the middle", + " for (var x = 1; x <= 3; x++) rank[emptySquares()[0]] = x==2 ? \"♔\" : \"♖\";", + " return rank;", + "}", + "", + "// testing (10 times)", + "for (var x = 1; x <= 10; x++) console.log(ch960startPos().join(\" | \"));", + "{{out}}", + "

    The test-output (exemplary each):

    ", + "♖ | ♗ | ♗ | ♔ | ♘ | ♖ | ♘ | ♕
    ", + "♗ | ♗ | ♕ | ♖ | ♔ | ♘ | ♘ | ♖
    ", + "♖ | ♕ | ♘ | ♗ | ♗ | ♔ | ♘ | ♖
    ", + "♖ | ♗ | ♔ | ♘ | ♗ | ♕ | ♘ | ♖
    ", + "♗ | ♖ | ♕ | ♔ | ♘ | ♗ | ♘ | ♖
    ", + "♖ | ♗ | ♗ | ♕ | ♔ | ♘ | ♖ | ♘
    ", + "♗ | ♘ | ♖ | ♗ | ♔ | ♘ | ♕ | ♖
    ", + "♕ | ♘ | ♗ | ♖ | ♔ | ♗ | ♖ | ♘
    ", + "♗ | ♘ | ♖ | ♘ | ♕ | ♗ | ♔ | ♖
    ", + "♘ | ♗ | ♖ | ♔ | ♗ | ♘ | ♖ | ♕
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e79", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function ch960startPos() {\n var rank = new Array(8),\n // randomizer (our die)\n d = function(num) { return Math.floor(Math.random() * ++num) },\n emptySquares = function() {\n var arr = [];\n for (var i = 0; i < 8; i++) if (rank[i] == undefined) arr.push(i);\n return arr;\n };\n // place one bishop on any black square\n rank[d(2) * 2] = \"♗\";\n // place the other bishop on any white square\n rank[d(2) * 2 + 1] = \"♗\";\n // place the queen on any empty square\n rank[emptySquares()[d(5)]] = \"♕\";\n // place one knight on any empty square\n rank[emptySquares()[d(4)]] = \"♘\";\n // place the other knight on any empty square\n rank[emptySquares()[d(3)]] = \"♘\";\n // place the rooks and the king on the squares left, king in the middle\n for (var x = 1; x <= 3; x++) rank[emptySquares()[0]] = x==2 ? \"♔\" : \"♖\";\n return rank;\n}\n\n// testing (10 times)\nfor (var x = 1; x <= 10; x++) console.log(ch960startPos().join(\" | \"));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Generate lower case ASCII alphabet", + "type": "Waypoint", + "description": [ + "Task:", + "

    Generate an array, list, lazy sequence, or even an indexable string of all the lower case ASCII characters, from a to z. If the standard library contains such a sequence, show how to access it, but don't fail to show how to generate a similar sequence.

    For this basic task use a reliable style of coding, a style fit for a very large program, and use strong typing if available. It's bug prone to enumerate all the lowercase characters manually in the code. During code review it's not immediate obvious to spot the bug in a Tcl line like this contained in a page of code:

    ", + "

    set alpha {a b c d e f g h i j k m n o p q r s t u v w x y z}

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "In ES5, we can use '''String.fromCharCode()''', which suffices for Unicode characters which can be represented with one 16 bit number.", + "", + "For Unicode characters beyond this range, in ES5 we have to enter a pair of Unicode number escapes.", + "", + "(function (cFrom, cTo) {", + "", + " function cRange(cFrom, cTo) {", + " var iStart = cFrom.charCodeAt(0);", + "", + " return Array.apply(", + " null, Array(cTo.charCodeAt(0) - iStart + 1)", + " ).map(function (_, i) {", + "", + " return String.fromCharCode(iStart + i);", + "", + " });", + " }", + "", + " return cRange(cFrom, cTo);", + "", + "})('a', 'z');", + "", + "Returns:", + "[\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\", \"j\", \"k\", \"l\", \"m\", \"n\", \"o\", \"p\", \"q\", \"r\", \"s\", \"t\", \"u\", \"v\", \"w\", \"x\", \"y\", \"z\"]", + "", + "===ES6===", + "", + "In ES6, the new '''String.fromCodePoint()''' method can can return 4-byte characters (such as Emoji, for example) as well as the usual 2-byte characters.", + "", + "(function (lstRanges) {", + "", + " function cRange(cFrom, cTo) {", + " var iStart = cFrom.codePointAt(0);", + "", + " return Array.apply(", + " null, Array(cTo.codePointAt(0) - iStart + 1)", + " ).map(function (_, i) {", + "", + " return String.fromCodePoint(iStart + i);", + "", + " });", + " }", + "", + " return lstRanges.map(function (lst) {", + " return cRange(lst[0], lst[1]);", + " });", + "", + "})([", + " ['a', 'z'],", + " ['🐐', '🐟']", + "]); ", + "", + "Output:", + "", + "[[\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\", \"j\", \"k\", \"l\", \"m\", \"n\", \"o\", \"p\", \"q\", \"r\", \"s\", \"t\", \"u\", \"v\", \"w\", \"x\", \"y\", \"z\"],", + " [\"🐐\", \"🐑\", \"🐒\", \"🐓\", \"🐔\", \"🐕\", \"🐖\", \"🐗\", \"🐘\", \"🐙\", \"🐚\", \"🐛\", \"🐜\", \"🐝\", \"🐞\", \"🐟\"]] ", + "", + "{{works with|ECMAScript|6}}", + "var letters = []", + "for (var i = 97; i <= 122; i++) {", + " letters.push(String.fromCodePoint(i))", + "}", + "", + "Or, if we want to write a more general ES6 function:", + "", + "(() => {", + " // enumFromTo :: Enum a => a -> a -> [a]", + " const enumFromTo = (m, n) => {", + " const [intM, intN] = [m, n].map(fromEnum),", + " f = typeof m === 'string' ? (", + " (_, i) => chr(intM + i)", + " ) : (_, i) => intM + i;", + " return Array.from({", + " length: Math.floor(intN - intM) + 1", + " }, f);", + " };", + "", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // compose :: (b -> c) -> (a -> b) -> (a -> c)", + " const compose = (f, g) => x => f(g(x));", + "", + " // chr :: Int -> Char", + " const chr = x => String.fromCodePoint(x);", + "", + " // ord :: Char -> Int", + " const ord = c => c.codePointAt(0);", + "", + " // fromEnum :: Enum a => a -> Int", + " const fromEnum = x => {", + " const type = typeof x;", + " return type === 'boolean' ? (", + " x ? 1 : 0", + " ) : type === 'string' ? ord(x) : x;", + " };", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = (f, xs) => xs.map(f);", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x);", + "", + " // uncurry :: Function -> Function", + " const uncurry = f => args => f.apply(null, args);", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + " // unwords :: [String] -> String", + " const unwords = xs => xs.join(' ');", + "", + " // TEST -------------------------------------------------------------------", + " return unlines(map(compose(unwords, uncurry(enumFromTo)), [", + " ['a', 'z'],", + " ['α', 'ω'],", + " ['א', 'ת'],", + " ['🐐', '🐟']", + " ]));", + "})();", + "{{Out}}", + "
    a b c d e f g h i j k l m n o p q r s t u v w x y z",
    +        "α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ ς σ τ υ φ χ ψ ω",
    +        "א ב ג ד ה ו ז ח ט י ך כ ל ם מ ן נ ס ע ף פ ץ צ ק ר ש ת",
    +        "🐐 🐑 🐒 🐓 🐔 🐕 🐖 🐗 🐘 🐙 🐚 🐛 🐜 🐝 🐞 🐟
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e7a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function (cFrom, cTo) {\n\n function cRange(cFrom, cTo) {\n var iStart = cFrom.charCodeAt(0);\n\n return Array.apply(\n null, Array(cTo.charCodeAt(0) - iStart + 1)\n ).map(function (_, i) {\n\n return String.fromCharCode(iStart + i);\n\n });\n }\n\n return cRange(cFrom, cTo);\n\n})('a', 'z');\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Generator/Exponential", + "type": "Waypoint", + "description": [ + "

    A generator is an executable entity (like a function or procedure) that contains code that yields a sequence of values, one at a time, so that each time you call the generator, the next value in the sequence is provided.

    ", + "

    Generators are often built on top of coroutines or objects so that the internal state of the object is handled “naturally”.

    ", + "

    Generators are often used in situations where a sequence is potentially infinite, and where it is possible to construct the next value of the sequence with only minimal state.

    Task description

    Create a function that returns a generation of the m'th powers of the positive integers starting from zero, in order, and without obvious or simple upper limit. (Any upper limit to the generator should not be stated in the source but should be down to factors such as the languages natural integer size limit or computational time/size).", + "Use it to create a generator of:# Squares.", + "

    # Cubes.

    ", + "Create a new generator that filters all cubes from the generator of squares.", + "Drop the first 20 values from this last generator of filtered results then show the next 10 valuesNote that this task requires the use of generators in the calculation of the result.

    See also

    ", + "Generator" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|Firefox 3.6 using JavaScript 1.7|}} ", + "", + "", + "function PowersGenerator(m) {", + "\tvar n=0;", + "\twhile(1) {", + "\t\tyield Math.pow(n, m);", + "\t\tn += 1;\t", + "\t}", + "}", + "", + "function FilteredGenerator(g, f){", + "\tvar value = g.next();", + "\tvar filter = f.next();", + "\t", + "\twhile(1) {", + "\t\tif( value < filter ) {", + "\t\t\tyield value;", + "\t\t\tvalue = g.next();", + "\t\t} else if ( value > filter ) {", + "\t\t\tfilter = f.next();", + "\t\t} else {", + "\t\t\tvalue = g.next();", + "\t\t\tfilter = f.next();", + "\t\t}", + "\t}\t", + "}", + "", + "", + "", + "var squares = PowersGenerator(2);", + "var cubes = PowersGenerator(3);", + "", + "var filtered = FilteredGenerator(squares, cubes);", + "", + "", + "", + "for( var x = 0; x < 20; x++ ) filtered.next()", + "for( var x = 20; x < 30; x++ ) console.logfiltered.next());", + "", + "", + "", + "===ES6===", + "function* nPowerGen(n) {", + " let e = 0;", + " while (1) { e++ && (yield Math.pow(e, n)); }", + "}", + "", + "function* filterGen(gS, gC, skip=0) {", + " let s = 0; // The square value", + " let c = 0; // The cube value", + " let n = 0; // A skip counter", + "", + " while(1) {", + " s = gS.next().value;", + " s > c && (c = gC.next().value);", + " s == c ?", + " c = gC.next().value :", + " n++ && n > skip && (yield s);", + " }", + "}", + "", + "const filtered = filterGen(nPowerGen(2), nPowerGen(3), skip=20);", + "// Generate the first 10 values", + "for (let n = 0; n < 10; n++) {", + " console.log(filtered.next().value)", + "}", + "
    529",
    +        "576",
    +        "625",
    +        "676",
    +        "784",
    +        "841",
    +        "900",
    +        "961",
    +        "1024",
    +        "1089
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e7b", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nfunction PowersGenerator(m) {\n\tvar n=0;\n\twhile(1) {\n\t\tyield Math.pow(n, m);\n\t\tn += 1;\t\n\t}\n}\n\nfunction FilteredGenerator(g, f){\n\tvar value = g.next();\n\tvar filter = f.next();\n\t\n\twhile(1) {\n\t\tif( value < filter ) {\n\t\t\tyield value;\n\t\t\tvalue = g.next();\n\t\t} else if ( value > filter ) {\n\t\t\tfilter = f.next();\n\t\t} else {\n\t\t\tvalue = g.next();\n\t\t\tfilter = f.next();\n\t\t}\n\t}\t\n}\n\n\n\nvar squares = PowersGenerator(2);\nvar cubes = PowersGenerator(3);\n\nvar filtered = FilteredGenerator(squares, cubes);\n\n\n\nfor( var x = 0; x < 20; x++ ) filtered.next()\nfor( var x = 20; x < 30; x++ ) console.logfiltered.next());\n\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Gray code", + "type": "Waypoint", + "description": [ + "

    Gray code is a form of binary encoding where transitions between consecutive numbers differ by only one bit. This is a useful encoding for reducing hardware data hazards with values that change rapidly and/or connect to slower hardware as inputs. It is also useful for generating inputs for Karnaugh maps in order from left to right or top to bottom.

    Create functions to encode a number to and decode a number from Gray code.

    Display the normal binary representations, Gray code representations, and decoded Gray code values for all 5-bit binary numbers (0-31 inclusive, leading 0's not necessary).

    There are many possible Gray codes. The following encodes what is called \"binary reflected Gray code.\"

    Encoding (MSB is bit 0, b is binary, g is Gray code):

    if b[i-1] = 1",
    +        "   g[i] = not b[i]",
    +        "else",
    +        "   g[i] = b[i]

    Or:

    g = b xor (b logically right shifted 1 time)

    Decoding (MSB is bit 0, b is binary, g is Gray code):

    b[0] = g[0]for other bits:",
    +        "b[i] = g[i] xor b[i-1]
    Reference", + "Converting Between Gray and Binary Codes. It includes step-by-step animations." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e80", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Greatest common divisor", + "type": "Waypoint", + "description": [ + "Task:", + "

    Find the greatest common divisor of two integers.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Iterative implementation", + "function gcd(a,b) {", + " a = Math.abs(a);", + " b = Math.abs(b);", + "", + " if (b > a) {", + " var temp = a;", + " a = b;", + " b = temp; ", + " }", + "", + " while (true) {", + " a %= b;", + " if (a === 0) { return b; }", + " b %= a;", + " if (b === 0) { return a; }", + " }", + "}", + "", + "Recursive.", + "function gcd_rec(a, b) {", + " return b ? gcd_rec(b, a % b) : Math.abs(a);", + "}", + "", + "Implementation that works on an array of integers.", + "function GCD(arr) {", + " var i, y,", + " n = arr.length,", + " x = Math.abs(arr[0]);", + "", + " for (i = 1; i < n; i++) {", + " y = Math.abs(arr[i]);", + "", + " while (x && y) {", + " (x > y) ? x %= y : y %= x;", + " }", + " x += y;", + " }", + " return x;", + "}", + "", + "//For example:", + "GCD([57,0,-45,-18,90,447]); //=> 3", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e82", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function gcd(a,b) {\n a = Math.abs(a);\n b = Math.abs(b);\n\n if (b > a) {\n var temp = a;\n a = b;\n b = temp; \n }\n\n while (true) {\n a %= b;\n if (a === 0) { return b; }\n b %= a;\n if (b === 0) { return a; }\n }\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Greatest subsequential sum", + "type": "Waypoint", + "description": [ + "Task:", + "

    Given a sequence of integers, find a continuous subsequence which maximizes the sum of its elements, that is, the elements of no other single subsequence add up to a value larger than this one.

    ", + "

    An empty subsequence is considered to have the sum of 0; thus if all elements are negative, the result must be the empty sequence.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Simple brute force approach.", + "function MaximumSubsequence(population) {", + " var maxValue = 0;", + " var subsequence = [];", + "", + " for (var i = 0, len = population.length; i < len; i++) {", + " for (var j = i; j <= len; j++) {", + " var subsequence = population.slice(i, j);", + " var value = sumValues(subsequence);", + " if (value > maxValue) {", + " maxValue = value;", + " greatest = subsequence;", + " };", + " }", + " }", + "", + " return greatest;", + "}", + "", + "function sumValues(arr) {", + " var result = 0;", + " for (var i = 0, len = arr.length; i < len; i++) {", + " result += arr[i];", + " }", + " return result;", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e84", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function MaximumSubsequence(population) {\n var maxValue = 0;\n var subsequence = [];\n\n for (var i = 0, len = population.length; i < len; i++) {\n for (var j = i; j <= len; j++) {\n var subsequence = population.slice(i, j);\n var value = sumValues(subsequence);\n if (value > maxValue) {\n maxValue = value;\n greatest = subsequence;\n };\n }\n }\n\n return greatest;\n}\n\nfunction sumValues(arr) {\n var result = 0;\n for (var i = 0, len = arr.length; i < len; i++) {\n result += arr[i];\n }\n return result;\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Guess the number/With feedback (player)", + "type": "Waypoint", + "description": [ + "

    The task is to write a player for the game that follows the following rules:

    ", + "

    The scorer will choose a number between set limits. The computer player will print a guess of the target number. The computer asks for a score of whether its guess is higher than, lower than, or equal to the target. The computer guesses, and the scorer scores, in turn, until the computer correctly guesses the target number.

    The computer should guess intelligently based on the accumulated scores given. One way is to use a Binary search based algorithm.

    Cf. ", + "Guess the number/With Feedback", + "Bulls and cows/Player" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "=== Spidermonkey version ===", + "", + "A boring solution that does nothing clever or inscrutable.", + "", + "Well, it does use recursion for the guessing function, but that's OK because the depth is bounded by LOG2 of the range. That's not true if the user changes his number, but then he gets what he deserves.", + "", + "#!/usr/bin/env js", + "", + "var DONE = RIGHT = 0, HIGH = 1, LOW = -1;", + "", + "function main() {", + " showInstructions();", + " while (guess(1, 100) !== DONE);", + "}", + "", + "function guess(low, high) {", + " if (low > high) {", + " print(\"I can't guess it. Perhaps you changed your number.\");", + " return DONE;", + " }", + " ", + " var g = Math.floor((low + high) / 2);", + " var result = getResult(g);", + " switch (result) {", + " case RIGHT:", + " return DONE;", + " case LOW:", + " return guess(g + 1, high);", + " case HIGH:", + " return guess(low, g - 1);", + " }", + "}", + "", + "function getResult(g) {", + " while(true) {", + " putstr('Is it ' + g + '? ');", + " var ans = readline().toUpperCase().replace(/^\\s+/, '') + ' ';", + " switch (ans[0]) {", + " case 'R':", + " print('I got it! Thanks for the game.');", + " return RIGHT;", + " case 'L': ", + " return LOW;", + " case 'H':", + " return HIGH;", + " default:", + " print('Please tell me if I am \"high\", \"low\" or \"right\".');", + " }", + " }", + "}", + "", + "function showInstructions() {", + " print('Think of a number between 1 and 100 and I will try to guess it.');", + " print('After I guess, type \"low\", \"high\" or \"right\", and then press enter.');", + " putstr(\"When you've thought of a number press enter.\");", + " readline();", + "}", + "", + "main();", + "", + "", + "An example session:", + " Think of a number between 1 and 100 and I will try to guess it.", + " After I guess, type \"low\", \"high\" or \"right\", and then press enter.", + " When you've thought of a number press enter.", + " Is it 50? high", + " Is it 25? high", + " Is it 12? low", + " Is it 18? high", + " Is it 15? high", + " Is it 13? right", + " I got it! Thanks for the game.", + "", + "Another example session:", + " Think of a number between 1 and 100 and I will try to guess it.", + " After I guess, type \"low\", \"high\" or \"right\", and then press enter.", + " When you've thought of a number press enter.", + " Is it 50? n", + " Please tell me if I am \"high\", \"low\" or \"right\".", + " Is it 50? h", + " Is it 25? h", + " Is it 12? h", + " Is it 6? h", + " Is it 3? h", + " Is it 1? h", + " I can't guess it. Perhaps you changed your number.", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e87", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "#!/usr/bin/env js\n\nvar DONE = RIGHT = 0, HIGH = 1, LOW = -1;\n\nfunction main() {\n showInstructions();\n while (guess(1, 100) !== DONE);\n}\n\nfunction guess(low, high) {\n if (low > high) {\n print(\"I can't guess it. Perhaps you changed your number.\");\n return DONE;\n }\n \n var g = Math.floor((low + high) / 2);\n var result = getResult(g);\n switch (result) {\n case RIGHT:\n return DONE;\n case LOW:\n return guess(g + 1, high);\n case HIGH:\n return guess(low, g - 1);\n }\n}\n\nfunction getResult(g) {\n while(true) {\n putstr('Is it ' + g + '? ');\n var ans = readline().toUpperCase().replace(/^\\s+/, '') + ' ';\n switch (ans[0]) {\n case 'R':\n print('I got it! Thanks for the game.');\n return RIGHT;\n case 'L': \n return LOW;\n case 'H':\n return HIGH;\n default:\n print('Please tell me if I am \"high\", \"low\" or \"right\".');\n }\n }\n}\n\nfunction showInstructions() {\n print('Think of a number between 1 and 100 and I will try to guess it.');\n print('After I guess, type \"low\", \"high\" or \"right\", and then press enter.');\n putstr(\"When you've thought of a number press enter.\");\n readline();\n}\n\nmain();\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Hamming numbers", + "type": "Waypoint", + "description": [ + "

    Hamming numbers are numbers of the form

    ", + "

    H = 2i × 3j × 5k

    ", + "

    where

    ", + "

    i, j, k ≥ 0

    Hamming numbers are also known as ugly numbers and also 5-smooth numbers (numbers whose prime divisors are less or equal to 5).

    ", + "Task:", + "

    Generate the sequence of Hamming numbers, in increasing order. In particular:

    ", + "Show the first twenty Hamming numbers.", + "Show the 1691st Hamming number (the last one below 231).", + "Show the one millionth Hamming number (if the language – or a convenient library – supports arbitrary-precision integers).References:", + "Hamming numbers", + "Smooth number", + "Hamming problem from Dr. Dobb's CodeTalk (dead link as of Sep 2011; parts of the thread here and here)." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|JavaScript|1.7}} {{works with|Firefox|2}}", + "{{trans|Ruby}}", + "This does not calculate the 1,000,000th Hamming number.", + "", + "Note the use of '''for''' (x in obj) to iterate over the ''properties'' of an object, versus '''for each''' (y in obj) to iterate over the ''values'' of the properties of an object.", + "function hamming() {", + " var queues = {2: [], 3: [], 5: []};", + " var base;", + " var next_ham = 1;", + " while (true) {", + " yield next_ham;", + "", + " for (base in queues) {queues[base].push(next_ham * base)}", + "", + " next_ham = [ queue[0] for each (queue in queues) ].reduce(function(min, val) {", + " return Math.min(min,val)", + " });", + "", + " for (base in queues) {if (queues[base][0] == next_ham) queues[base].shift()}", + " }", + "}", + "", + "var ham = hamming();", + "var first20=[], i=1;", + "", + "for (; i <= 20; i++) ", + " first20.push(ham.next());", + "print(first20.join(', '));", + "print('...');", + "for (; i <= 1690; i++) ", + " ham.next();", + "print(i + \" => \" + ham.next());", + "{{out}}", + "
    1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36",
    +        "...",
    +        "1691 => 2125764000 
    ", + "", + "===Fast & complete version===", + "", + "{{trans|C#}}", + "", + "A translation of my fast C# version. I was curious to see how much slower JavaScript is. The result: it runs about 5x times slower than C#, though YMMV. You can try it yourself here: http://jsfiddle.net/N7AFN/", + "", + "--Mike Lorenz", + "", + "", + "", + "", + "
    ", + "", + "", + "", + "", + "
    ", + "", + "{{out}}", + "
    5-Smooth:",
    +        "",
    +        "1:\t\t1",
    +        "2:\t\t2",
    +        "3:\t\t3",
    +        "4:\t\t4",
    +        "5:\t\t5",
    +        "6:\t\t6",
    +        "7:\t\t8",
    +        "8:\t\t9",
    +        "9:\t\t10",
    +        "10:\t\t12",
    +        "11:\t\t15",
    +        "12:\t\t16",
    +        "13:\t\t18",
    +        "14:\t\t20",
    +        "15:\t\t24",
    +        "16:\t\t25",
    +        "17:\t\t27",
    +        "18:\t\t30",
    +        "19:\t\t32",
    +        "20:\t\t36",
    +        "1691:\t\t2125764000",
    +        "1000000:\t519312780448388736089589843750000000000000000000000000000000000000000000000000000000",
    +        "Elapsed time:\t1.73 seconds",
    +        "",
    +        "7-Smooth:",
    +        "",
    +        "1:\t\t1",
    +        "2:\t\t2",
    +        "3:\t\t3",
    +        "4:\t\t4",
    +        "5:\t\t5",
    +        "6:\t\t6",
    +        "7:\t\t7",
    +        "8:\t\t8",
    +        "9:\t\t9",
    +        "10:\t\t10",
    +        "11:\t\t12",
    +        "12:\t\t14",
    +        "13:\t\t15",
    +        "14:\t\t16",
    +        "15:\t\t18",
    +        "16:\t\t20",
    +        "17:\t\t21",
    +        "18:\t\t24",
    +        "19:\t\t25",
    +        "20:\t\t27",
    +        "1691:\t\t3317760",
    +        "1000000:\t4157409948433216829957008507500000000",
    +        "Elapsed time:\t1.989 seconds
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7e8d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function hamming() {\n var queues = {2: [], 3: [], 5: []};\n var base;\n var next_ham = 1;\n while (true) {\n yield next_ham;\n\n for (base in queues) {queues[base].push(next_ham * base)}\n\n next_ham = [ queue[0] for each (queue in queues) ].reduce(function(min, val) {\n return Math.min(min,val)\n });\n\n for (base in queues) {if (queues[base][0] == next_ham) queues[base].shift()}\n }\n}\n\nvar ham = hamming();\nvar first20=[], i=1;\n\nfor (; i <= 20; i++) \n first20.push(ham.next());\nprint(first20.join(', '));\nprint('...');\nfor (; i <= 1690; i++) \n ham.next();\nprint(i + \" => \" + ham.next());\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "IBAN", + "type": "Waypoint", + "description": [ + "

    The International Bank Account Number (IBAN) is an internationally agreed means of identifying bank accounts across national borders with a reduced risk of propagating transcription errors.

    The IBAN consists of up to 34 alphanumeric characters:

    ", + "

    :* first the two-letter ISO 3166-1 alpha-2 country code,

    ", + "

    :* then two check digits, and

    ", + "

    :* finally a country-specific Basic Bank Account Number (BBAN).

    ", + "

    The check digits enable a sanity check of the bank account number to confirm its integrity even before submitting a transaction.

    ", + "Task:", + "

    Validate the following fictitious IBAN: GB82 WEST 1234 5698 7654 32

    ", + "

    Details of the algorithm can be found on the Wikipedia page.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "var ibanLen = { ", + "\tNO:15, BE:16, DK:18, FI:18, FO:18, GL:18, NL:18, MK:19,", + "\tSI:19, AT:20, BA:20, EE:20, KZ:20, LT:20, LU:20, CR:21,", + "\tCH:21, HR:21, LI:21, LV:21, BG:22, BH:22, DE:22, GB:22,", + "\tGE:22, IE:22, ME:22, RS:22, AE:23, GI:23, IL:23, AD:24,", + "\tCZ:24, ES:24, MD:24, PK:24, RO:24, SA:24, SE:24, SK:24,", + "\tVG:24, TN:24, PT:25, IS:26, TR:26, FR:27, GR:27, IT:27,", + "\tMC:27, MR:27, SM:27, AL:28, AZ:28, CY:28, DO:28, GT:28,", + "\tHU:28, LB:28, PL:28, BR:29, PS:29, KW:30, MU:30, MT:31", + "}", + "", + "function isValid(iban) {", + "\tiban = iban.replace(/\\s/g, '')", + "\tif (!iban.match(/^[\\dA-Z]+$/)) return false", + "\tvar len = iban.length", + "\tif (len != ibanLen[iban.substr(0,2)]) return false", + "\tiban = iban.substr(4) + iban.substr(0,4)", + "\tfor (var s='', i=0; i') // true", + "document.write(isValid('GB82 WEST 1.34 5698 7654 32'), '
    ') // false", + "document.write(isValid('GB82 WEST 1234 5698 7654 325'), '
    ') // false", + "document.write(isValid('GB82 TEST 1234 5698 7654 32'), '
    ') // false", + "document.write(isValid('SA03 8000 0000 6080 1016 7519'), '
    ') // true", + "
    ", + "{{out}}", + " true", + " false", + " false", + " false", + " true", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7eaf", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var ibanLen = { \n\tNO:15, BE:16, DK:18, FI:18, FO:18, GL:18, NL:18, MK:19,\n\tSI:19, AT:20, BA:20, EE:20, KZ:20, LT:20, LU:20, CR:21,\n\tCH:21, HR:21, LI:21, LV:21, BG:22, BH:22, DE:22, GB:22,\n\tGE:22, IE:22, ME:22, RS:22, AE:23, GI:23, IL:23, AD:24,\n\tCZ:24, ES:24, MD:24, PK:24, RO:24, SA:24, SE:24, SK:24,\n\tVG:24, TN:24, PT:25, IS:26, TR:26, FR:27, GR:27, IT:27,\n\tMC:27, MR:27, SM:27, AL:28, AZ:28, CY:28, DO:28, GT:28,\n\tHU:28, LB:28, PL:28, BR:29, PS:29, KW:30, MU:30, MT:31\n}\n\nfunction isValid(iban) {\n\tiban = iban.replace(/\\s/g, '')\n\tif (!iban.match(/^[\\dA-Z]+$/)) return false\n\tvar len = iban.length\n\tif (len != ibanLen[iban.substr(0,2)]) return false\n\tiban = iban.substr(4) + iban.substr(0,4)\n\tfor (var s='', i=0; i') // true\ndocument.write(isValid('GB82 WEST 1.34 5698 7654 32'), '
    ') // false\ndocument.write(isValid('GB82 WEST 1234 5698 7654 325'), '
    ') // false\ndocument.write(isValid('GB82 TEST 1234 5698 7654 32'), '
    ') // false\ndocument.write(isValid('SA03 8000 0000 6080 1016 7519'), '
    ') // true\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "I before E except after C", + "type": "Waypoint", + "description": [ + "

    The phrase \"I before E, except after C\" is a

    ", + "

    widely known mnemonic which is supposed to help when spelling English words.

    ", + "Task:", + "

    Using the word list from http://www.puzzlers.org/pub/wordlists/unixdict.txt,

    ", + "check if the two sub-clauses of the phrase are plausible individually:", + "

    ::# \"I before E when not preceded by C\"

    ", + "

    ::# \"E before I when preceded by C\"

    ", + "

    If both sub-phrases are plausible then the original phrase can be said to be plausible.

    Something is plausible if the number of words having the feature is more than two times the number of words having the opposite feature (where feature is 'ie' or 'ei' preceded or not by 'c' as appropriate).

    ", + "Stretch goal:", + "

    As a stretch goal use the entries from the table of Word Frequencies in Written and Spoken English: based on the British National Corpus, (selecting those rows with three space or tab separated words only), to see if the phrase is plausible when word frequencies are taken into account.

    ", + "

    Show your output here as well as your program.

    ", + "cf.:", + "Schools to rethink 'i before e' - BBC news, 20 June 2009", + "I Before E Except After C - QI Series 8 Ep 14, (humorous)", + "Companion website for the book: \"Word Frequencies in Written and Spoken English: based on the British National Corpus\"." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7eb0", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Identity matrix", + "type": "Waypoint", + "description": [ + "Task:", + "

    Build an identity matrix of a size known at run-time.

    ", + "

    An identity matrix is a square matrix of size n × n,

    ", + "where the diagonal elements are all 1s (ones), ", + "and all the other elements are all 0s (zeroes).", + "

    $I_n = \\begin{bmatrix}

    ", + "

    1 & 0 & 0 & \\cdots & 0 \\\\

    ", + "

    0 & 1 & 0 & \\cdots & 0 \\\\

    ", + "

    0 & 0 & 1 & \\cdots & 0 \\\\

    ", + "

    \\vdots & \\vdots & \\vdots & \\ddots & \\vdots \\\\

    ", + "

    0 & 0 & 0 & \\cdots & 1 \\\\

    ", + "

    \\end{bmatrix}$

    ", + "Related tasks:", + " Spiral matrix", + " Zig-zag matrix ", + " Ulam_spiral_(for_primes)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "function idMatrix(n) {", + " return Array.apply(null, new Array(n))", + " .map(function (x, i, xs) {", + " return xs.map(function (_, k) {", + " return i === k ? 1 : 0;", + " })", + " });", + "}", + "", + "===ES6===", + "", + "(() => {", + "", + " // idMatrix :: Int -> [[0 | 1]]", + " const idMatrix = n => Array.from({", + " length: n", + " }, (_, i) => Array.from({", + " length: n", + " }, (_, j) => i !== j ? 0 : 1));", + "", + " // show :: a -> String", + " const show = JSON.stringify;", + "", + " // TEST", + " return idMatrix(5)", + " .map(show)", + " .join('\\n');", + "})();", + "", + "{{Out}}", + "
    [1,0,0,0,0]",
    +        "[0,1,0,0,0]",
    +        "[0,0,1,0,0]",
    +        "[0,0,0,1,0]",
    +        "[0,0,0,0,1]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7eb1", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function idMatrix(n) {\n return Array.apply(null, new Array(n))\n .map(function (x, i, xs) {\n return xs.map(function (_, k) {\n return i === k ? 1 : 0;\n })\n });\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Iterated digits squaring", + "type": "Waypoint", + "description": [ + "

    If you add the square of the digits of a Natural number (an integer bigger than zero), you always end with either 1 or 89:

    ", + "
    15 -> 26 -> 40 -> 16 -> 37 -> 58 -> 89",
    +        "7 -> 49 -> 97 -> 130 -> 10 -> 1
    ", + "

    An example in Python:

    >>> step = lambda x: sum(int(d) ** 2 for d in str(x))

    ", + "

    >>> iterate = lambda x: x if x in [1, 89] else iterate(step(x))

    ", + "

    >>> [iterate(x) for x in xrange(1, 20)]

    ", + "

    [1, 89, 89, 89, 89, 89, 1, 89, 89, 1, 89, 89, 1, 89, 89, 89, 89, 89, 1]

    Task:", + "

    Count how many number chains for integers 1 <= n < 100_000_000 end with a value 89.

    ", + "

    Or, for much less credit - (showing that your algorithm and/or language is slow):

    ", + "

    Count how many number chains for integers 1 <= n < 1_000_000 end with a value 89.

    This problem derives from the Project Euler problem 92.

    For a quick algorithm for this task see the talk page

    Cf:", + "Combinations with repetitions", + "Digital root", + "Digital root/Multiplicative digital root" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ec1", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Jaro distance", + "type": "Waypoint", + "description": [ + "

    The Jaro distance is a measure of similarity between two strings.

    The higher the Jaro distance for two strings is, the more similar the strings are.

    The score is normalized such that 0 equates to no similarity and 1 is an exact match.

    ", + ";Definition

    The Jaro distance $d_j$ of two given strings $s_1$ and $s_2$ is

    $d_j = \\left\\{

    \\begin{array}{l l}

    ", + "

    0 & \\text{if }m = 0\\\\

    ", + "

    \\frac{1}{3}\\left(\\frac{m}{|s_1|} + \\frac{m}{|s_2|} + \\frac{m-t}{m}\\right) & \\text{otherwise} \\end{array} \\right.$

    Where:

    $m$ is the number of matching characters;", + "$t$ is half the number of transpositions.

    Two characters from $s_1$ and $s_2$ respectively, are considered matching only if they are the same and not farther than $\\left\\lfloor\\frac{\\max(|s_1|,|s_2|)}{2}\\right\\rfloor-1$.

    Each character of $s_1$ is compared with all its matching

    ", + "

    characters in $s_2$.

    The number of matching (but different sequence order) characters

    ", + "

    divided by 2 defines the number of transpositions.

    ", + ";Example

    Given the strings $s_1$ DWAYNE and $s_2$ DUANE we find:

    $m = 4$", + "$|s_1| = 6$", + "$|s_2| = 5$", + "$t = 0$

    We find a Jaro score of:

    $d_j = \\frac{1}{3}\\left(\\frac{4}{6} + \\frac{4}{5} + \\frac{4-0}{4}\\right) = 0.822$

    ", + "Task

    Implement the Jaro-distance algorithm and show the distances for each of the following pairs:

    (\"MARTHA\", \"MARHTA\")", + "(\"DIXON\", \"DICKSONX\")", + "(\"JELLYFISH\", \"SMELLYFISH\") See also", + "Jaro–Winkler distance on Wikipedia." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ec2", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "JortSort", + "type": "Waypoint", + "description": [ + "

    jortSort is a sorting toolset that makes the user do the work and guarantees efficiency because you don't have to sort ever again. It was originally presented by Jenn \"Moneydollars\" Schiffer at the prestigious JSConf.

    jortSort is a function that takes a single array of comparable objects as its argument. It then sorts the array in ascending order and compares the sorted array to the originally provided array. If the arrays match (i.e. the original array was already sorted), the function returns true. If the arrays do not match (i.e. the original array was not sorted), the function returns false.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "The original JavaScript implementation courtesy of the author, [https://github.com/jennschiffer/jortsort Jenn \"Moneydollars\" Schiffer].", + "var jortSort = function( array ) {", + "", + " // sort the array", + " var originalArray = array.slice(0);", + " array.sort( function(a,b){return a - b} );", + "", + " // compare to see if it was originally sorted", + " for (var i = 0; i < originalArray.length; ++i) {", + " if (originalArray[i] !== array[i]) return false;", + " }", + "", + " return true;", + "};", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ec4", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var jortSort = function( array ) {\n\n // sort the array\n var originalArray = array.slice(0);\n array.sort( function(a,b){return a - b} );\n\n // compare to see if it was originally sorted\n for (var i = 0; i < originalArray.length; ++i) {\n if (originalArray[i] !== array[i]) return false;\n }\n\n return true;\n};\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Josephus problem", + "type": "Waypoint", + "description": [ + "

    Josephus problem is a math puzzle with a grim description: $n$ prisoners are standing on a circle, sequentially numbered from $0$ to $n-1$.

    An executioner walks along the circle, starting from prisoner $0$,

    ", + "

    removing every $k$-th prisoner and killing him.

    As the process goes on, the circle becomes smaller and smaller, until only one prisoner remains, who is then freed. >

    For example, if there are $n=5$ prisoners and $k=2$, the order the prisoners are killed in (let's call it the \"killing sequence\") will be 1, 3, 0, and 4, and the survivor will be #2.

    ", + "Task:", + "

    Given any $n, k > 0$, find out which prisoner will be the final survivor.

    In one such incident, there were 41 prisoners and every 3rd prisoner was being killed ($k=3$).

    Among them was a clever chap name Josephus who worked out the problem, stood at the surviving position, and lived on to tell the tale.

    Which number was he?

    ", + "Extra:", + "

    The captors may be especially kind and let $m$ survivors free,

    ", + "and Josephus might just have $m-1$ friends to save.

    Provide a way to calculate which prisoner is at any given position on the killing sequence.

    ", + "Notes:", + "You can always play the executioner and follow the procedure exactly as described, walking around the circle, counting (and cutting off) heads along the way. This would yield the complete killing sequence and answer the above questions, with a complexity of probably $O(kn)$. However, individually it takes no more than $O(m)$ to find out which prisoner is the $m$-th to die.", + "If it's more convenient, you can number prisoners from $1$ to $n$ instead. If you choose to do so, please state it clearly.", + "An alternative description has the people committing assisted suicide instead of being executed, and the last person simply walks away. These details are not relevant, at least not mathematically." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Labels are 1-based, executioner's solution:", + "var Josephus = {", + " init: function(n) {", + " this.head = {};", + " var current = this.head;", + " for (var i = 0; i < n-1; i++) {", + " current.label = i+1;", + " current.next = {prev: current};", + " current = current.next;", + " }", + " current.label = n;", + " current.next = this.head;", + " this.head.prev = current;", + " return this;", + " },", + " kill: function(spacing) {", + " var current = this.head;", + " while (current.next !== current) {", + " for (var i = 0; i < spacing-1; i++) {", + " current = current.next;", + " }", + " current.prev.next = current.next;", + " current.next.prev = current.prev;", + " current = current.next;", + " }", + " return current.label;", + " }", + "}", + "{{out}}", + "
    ",
    +        "> Josephus.init(30).kill(2)",
    +        "29",
    +        "
    ", + "", + "With Array methods:", + "function Josephus(n, k, s) {", + "\ts = s | 1", + "\tfor (var ps=[], i=n; i--; ) ps[i]=i", + "\tfor (var ks=[], i=--k; ps.length>s; i=(i+k)%ps.length) ks.push(ps.splice(i, 1))", + "\tdocument.write((arguments.callee+'').split(/\\s|\\(/)[1], '(', [].slice.call(arguments, 0), ') -> ', ps, ' / ', ks.length<45?ks:ks.slice(0,45)+',...' , '
    ')", + "\treturn [ps, ks]", + "}
    ", + "{{out}}", + "
    ",
    +        "Josephus(5,1) -> 2 / 1,3,0,4",
    +        "Josephus(41,2) -> 30 / 2,5,8,11,14,17,20,23,26,29,32,35,38,0,4,9,13,18,22,27,31,36,40,6,12,19,25,33,39,7,16,28,37,10,24,1,21,3,34,15",
    +        "Josephus(23482,3342,3) -> 1087,1335,13317 / 3342,6685,10028,13371,16714,20057,23400,3261,6605,9949,13293,16637,19981,23325,3187,6532,9877,13222,16567,19912,23257,3120,6466,9812,13158,16504,19850,23196,3060,6407,9754,13101,16448,19795,23142,3007,6355,9703,13051,16399,19747,23095,2961,6310,9659,...",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ec5", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var Josephus = {\n init: function(n) {\n this.head = {};\n var current = this.head;\n for (var i = 0; i < n-1; i++) {\n current.label = i+1;\n current.next = {prev: current};\n current = current.next;\n }\n current.label = n;\n current.next = this.head;\n this.head.prev = current;\n return this;\n },\n kill: function(spacing) {\n var current = this.head;\n while (current.next !== current) {\n for (var i = 0; i < spacing-1; i++) {\n current = current.next;\n }\n current.prev.next = current.next;\n current.next.prev = current.prev;\n current = current.next;\n }\n return current.label;\n }\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Kaprekar numbers", + "type": "Waypoint", + "description": [ + "

    A positive integer is a Kaprekar number if:

    ", + "It is 1", + "The decimal representation of its square may be split once into two parts consisting of positive integers which sum to the original number. Note that a split resulting in a part consisting purely of 0s is not valid, ", + "

    as 0 is not considered positive.

    Example Kaprekar numbers:", + "$2223$ is a Kaprekar number, as $2223 * 2223 = 4941729$, $4941729$ may be split to $494$ and $1729$, and $494 + 1729 = 2223$.", + "The series of Kaprekar numbers is known as A006886, and begins as $1, 9, 45, 55, ...$.", + "Example process:", + "

    10000 (1002) splitting from left to right:

    ", + "The first split is [1, 0000], and is invalid; the 0000 element consists entirely of 0s, and 0 is not considered positive.", + "Slight optimization opportunity: When splitting from left to right, once the right part consists entirely of 0s, no further testing is needed; all further splits would also be invalid.", + "Task description:", + "

    Generate and show all Kaprekar numbers less than 10,000.

    Extra credit:", + "

    Optionally, count (and report the count of) how many Kaprekar numbers are less than 1,000,000.

    Extra extra credit:", + "

    The concept of Kaprekar numbers is not limited to base 10 (i.e. decimal numbers);

    ", + "

    if you can, show that Kaprekar numbers exist in other bases too.

    For this purpose, do the following:

    ", + "Find all Kaprekar numbers for base 17 between 1 and 1,000,000 (one million);", + "Display each of them in base 10 representation;", + "Optionally, using base 17 representation (use letters 'a' to 'g' for digits 10(10) to 16(10)), display each of the numbers, its square, and where to split the square. ", + "For example, 225(10) is \"d4\" in base 17, its square \"a52g\", and a5(17) + 2g(17) = d4(17), so the display would be something like:
    225   d4  a52g  a5 + 2g
    Reference:", + "The Kaprekar Numbers by Douglas E. Iannucci (2000). PDF version" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "'''This string version'''", + "function isKaprekar( n, bs ) {", + "\tif ( n < 1 ) return false", + "\tif ( n == 1 ) return true", + "\tbs = bs || 10", + "\tvar s = (n * n).toString(bs)", + "\tfor (var i=1, e=s.length; i", + "'''or this numeric version'''", + "function isKaprekar( n, bs ) {", + "\tif ( n < 1 ) return false", + "\tif ( n == 1 ) return true", + "\tbs = bs || 10", + "\tfor (var a=n*n, b=0, s=1; a; s*=bs) {", + "\t\tb += a%bs*s", + "\t\ta = Math.floor(a/bs)", + "\t\tif (b && a + b == n) return true", + "\t}", + "\treturn false", + "}", + "'''with'''", + "function kaprekar( s, e, bs, pbs ) {", + "\tbs = bs || 10; pbs = pbs || 10", + "\tconst toString = n => n.toString(pbs).toUpperCase()", + "\tdocument.write('start:',toString(s), ' end:',toString(e), ' base:',bs, ' printBase:',pbs, '
    ' )", + "\tfor (var k=0, n=s; n<=e; n+=1) if (isKaprekar(n, bs)) k+=1, document.write(toString(n), ' ') ", + "\tdocument.write('
    found ', k, ' numbers

    ')", + "}", + "", + "kaprekar( 1, 99 )", + "kaprekar( 1, 255, 16)", + "kaprekar( 1, 255, 16, 16)", + "kaprekar( 1, 288, 17, 17)
    ", + "{{out}}", + "
    ",
    +        "start:1 end:99 base:10 printBase:10",
    +        "1 9 45 55 99",
    +        "found 5 numbers",
    +        "",
    +        "start:1 end:255 base:16 printBase:10",
    +        "1 6 10 15 51 85 91 120 136 171 205 255",
    +        "found 12 numbers",
    +        "",
    +        "start:1 end:FF base:16 printBase:16",
    +        "1 6 A F 33 55 5B 78 88 AB CD FF",
    +        "found 12 numbers",
    +        "",
    +        "start:1 end:GG base:17 printBase:17",
    +        "1 G 3D D4 GG",
    +        "found 5 numbers",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7eca", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function isKaprekar( n, bs ) {\n\tif ( n < 1 ) return false\n\tif ( n == 1 ) return true\n\tbs = bs || 10\n\tvar s = (n * n).toString(bs)\n\tfor (var i=1, e=s.length; ireplaceMe is a function.');" + ] + }, + { + "title": "K-d tree", + "type": "Waypoint", + "description": [ + "

    A k-d tree (short for k-dimensional tree) is a space-partitioning data structure for organizing points in a k-dimensional space. k-d trees are a useful data structure for several applications, such as searches involving a multidimensional search key (e.g. range searches and nearest neighbor searches).

    ", + "

    k-d trees are a special case of binary space partitioning trees.

    k-d trees are not suitable, however, for efficiently finding the nearest neighbor in high dimensional spaces. As a general rule, if the dimensionality is k, the number of points in the data, N, should be N ≫ 2k.

    ", + "

    Otherwise, when k-d trees are used with high-dimensional data, most of the points in the tree will be evaluated and the efficiency is no better than exhaustive search, and other methods such as approximate nearest-neighbor are used instead.

    Task: Construct a k-d tree and perform a nearest neighbor search for two example data sets:

    The Wikipedia example data of [(2,3), (5,4), (9,6), (4,7), (8,1), (7,2)].", + "1000 3-d points uniformly distributed in a 3-d cube.", + "

    For the Wikipedia example, find the nearest neighbor to point (9, 2)

    ", + "

    For the random data, pick a random location and find the nearest neighbor.

    In addition, instrument your code to count the number of nodes visited in the nearest neighbor search. Count a node as visited if any field of it is accessed.

    Output should show the point searched for, the point found,

    ", + "

    the distance to the point, and the number of nodes visited.

    There are variant algorithms for constructing the tree.

    ", + "

    You can use a simple median strategy or implement something more efficient.

    ", + "

    Variants of the nearest neighbor search include nearest N neighbors, approximate nearest neighbor, and range searches.

    ", + "

    You do not have to implement these.

    ", + "

    The requirement for this task is specifically the nearest single neighbor.

    ", + "

    Also there are algorithms for inserting, deleting, and balancing k-d trees.

    ", + "

    These are also not required for the task.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ecb", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Knapsack problem/0-1", + "type": "Waypoint", + "description": [ + "

    A tourist wants to make a good trip at the weekend with his friends.

    They will go to the mountains to see the wonders of nature, so he needs to pack well for the trip.

    He has a good knapsack for carrying things, but knows that he can carry a maximum of only 4kg in it, and it will have to last the whole day.

    He creates a list of what he wants to bring for the trip but the total weight of all items is too much.

    He then decides to add columns to his initial list detailing their weights and a numerical value representing how important the item is for the trip.

    ", + "

    Here is the list:

    ", + "

    {| style=\"text-align: left; width: 80%;\" border=\"4\" cellpadding=\"2\" cellspacing=\"2\"

    ", + "

    |+ Table of potential knapsack items

    ", + "

    |- style=\"background-color: rgb(255, 204, 255);\"

    ", + "

    ! item !! weight (dag) !! value

    ", + "

    |-

    ", + "

    | map || 9 || 150

    ", + "

    |-

    ", + "

    | compass || 13 || 35

    ", + "

    |-

    ", + "

    | water || 153 || 200

    ", + "

    |-

    ", + "

    | sandwich || 50 || 160

    ", + "

    |-

    ", + "

    | glucose || 15 || 60

    ", + "

    |-

    ", + "

    | tin || 68 || 45

    ", + "

    |-

    ", + "

    | banana || 27 || 60

    ", + "

    |-

    ", + "

    | apple || 39 || 40

    ", + "

    |-

    ", + "

    | cheese || 23 || 30

    ", + "

    |-

    ", + "

    | beer || 52 || 10

    ", + "

    |-

    ", + "

    | suntan cream || 11 || 70

    ", + "

    |-

    ", + "

    | camera || 32 || 30

    ", + "

    |-

    ", + "

    | T-shirt || 24 || 15

    ", + "

    |-

    ", + "

    | trousers || 48 || 10

    ", + "

    |-

    ", + "

    | umbrella || 73 || 40

    ", + "

    |-

    ", + "

    | waterproof trousers || 42 || 70

    ", + "

    |-

    ", + "

    | waterproof overclothes || 43 || 75

    ", + "

    |-

    ", + "

    | note-case || 22 || 80

    ", + "

    |-

    ", + "

    | sunglasses || 7 || 20

    ", + "

    |-

    ", + "

    | towel || 18 || 12

    ", + "

    |-

    ", + "

    | socks || 4 || 50

    ", + "

    |-

    ", + "

    | book || 30 || 10

    ", + "

    |- style=\"background-color: rgb(255, 204, 255);\"

    ", + "

    | knapsack || ≤400 dag || ?

    ", + "

    |}

    ", + "

    The tourist can choose to take any combination of items from the list,

    ", + "

    but only one of each item is available.

    He may not cut or diminish the items, so he can only take whole units of any item.

    ", + "Task:", + "

    Show which items the tourist can carry in his knapsack so that their total weight does not

    ", + "

    exceed 400 dag [4 kg], and their total value is maximized.

    [dag = decagram = 10 grams]

    ", + "Related tasks:", + " Knapsack problem/Bounded", + " Knapsack problem/Unbounded", + " Knapsack problem/Continuous" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Also available at [https://gist.github.com/truher/4715551|this gist].", + "/*global portviz:false, _:false */", + "/*", + " * 0-1 knapsack solution, recursive, memoized, approximate.", + " *", + " * credits:", + " *", + " * the Go implementation here:", + " * http://rosettacode.org/mw/index.php?title=Knapsack_problem/0-1", + " *", + " * approximation details here:", + " * http://math.mit.edu/~goemans/18434S06/knapsack-katherine.pdf", + " */", + "portviz.knapsack = {};", + "(function() {", + " this.combiner = function(items, weightfn, valuefn) {", + " // approximation guarantees result >= (1-e) * optimal", + " var _epsilon = 0.01;", + " var _p = _.max(_.map(items,valuefn));", + " var _k = _epsilon * _p / items.length;", + " ", + " var _memo = (function(){", + " var _mem = {};", + " var _key = function(i, w) {", + " return i + '::' + w;", + " };", + " return {", + " get: function(i, w) {", + " return _mem[_key(i,w)];", + " },", + " put: function(i, w, r) {", + " _mem[_key(i,w)]=r;", + " return r;", + " }", + " };", + " })();", + " ", + " var _m = function(i, w) {", + " ", + " i = Math.round(i);", + " w = Math.round(w);", + " ", + " ", + " if (i < 0 || w === 0) {", + " // empty base case", + " return {items: [], totalWeight: 0, totalValue: 0};", + " }", + " ", + " var mm = _memo.get(i,w);", + " if (!_.isUndefined(mm)) {", + " return mm;", + " }", + " ", + " var item = items[i];", + " if (weightfn(item) > w) {", + " //item does not fit, try the next item", + " return _memo.put(i, w, _m(i-1, w));", + " }", + " // this item could fit.", + " // are we better off excluding it?", + " var excluded = _m(i-1, w);", + " // or including it?", + " var included = _m(i-1, w - weightfn(item));", + " if (included.totalValue + Math.floor(valuefn(item)/_k) > excluded.totalValue) {", + " // better off including it", + " // make a copy of the list", + " var i1 = included.items.slice();", + " i1.push(item);", + " return _memo.put(i, w,", + " {items: i1,", + " totalWeight: included.totalWeight + weightfn(item),", + " totalValue: included.totalValue + Math.floor(valuefn(item)/_k)});", + " }", + " //better off excluding it", + " return _memo.put(i,w, excluded);", + " };", + " return {", + " /* one point */", + " one: function(maxweight) {", + " var scaled = _m(items.length - 1, maxweight);", + " return {", + " items: scaled.items,", + " totalWeight: scaled.totalWeight,", + " totalValue: scaled.totalValue * _k", + " };", + " },", + " /* the entire EF */", + " ef: function(maxweight, step) {", + " return _.map(_.range(0, maxweight+1, step), function(weight) {", + " var scaled = _m(items.length - 1, weight);", + " return {", + " items: scaled.items,", + " totalWeight: scaled.totalWeight,", + " totalValue: scaled.totalValue * _k", + " };", + " });", + " }", + " };", + " };", + "}).apply(portviz.knapsack);", + "", + "/*global portviz:false, _:false */", + "/*", + " * after rosettacode.org/mw/index.php?title=Knapsack_problem/0-1", + " */", + "var allwants = [", + " {name:\"map\", weight:9, value: 150},", + " {name:\"compass\", weight:13, value: 35},", + " {name:\"water\", weight:153, value: 200},", + " {name:\"sandwich\", weight: 50, value: 160},", + " {name:\"glucose\", weight:15, value: 60},", + " {name:\"tin\", weight:68, value: 45},", + " {name:\"banana\", weight:27, value: 60},", + " {name:\"apple\", weight:39, value: 40},", + " {name:\"cheese\", weight:23, value: 30},", + " {name:\"beer\", weight:52, value: 10},", + " {name:\"suntan cream\", weight:11, value: 70},", + " {name:\"camera\", weight:32, value: 30},", + " {name:\"T-shirt\", weight:24, value: 15},", + " {name:\"trousers\", weight:48, value: 10},", + " {name:\"umbrella\", weight:73, value: 40},", + " {name:\"waterproof trousers\", weight:42, value: 70},", + " {name:\"waterproof overclothes\", weight:43, value: 75},", + " {name:\"note-case\", weight:22, value: 80},", + " {name:\"sunglasses\", weight:7, value: 20},", + " {name:\"towel\", weight:18, value: 12},", + " {name:\"socks\", weight:4, value: 50},", + " {name:\"book\", weight:30, value: 10}", + "];", + " ", + "var near = function(actual, expected, tolerance) {", + " if (expected === 0 && actual === 0) return true;", + " if (expected === 0) {", + " return Math.abs(expected - actual) / actual < tolerance;", + " }", + " return Math.abs(expected - actual) / expected < tolerance;", + "};", + " ", + "test(\"one knapsack\", function() {", + " var combiner =", + " portviz.knapsack.combiner(allwants,", + " function(x){return x.weight;},", + " function(x){return x.value;});", + " var oneport = combiner.one(400);", + " ok(near(oneport.totalValue, 1030, 0.01), \"correct total value\");", + " ok(near(oneport.totalValue, 1030, 0.01), \"correct total value\");", + " equal(oneport.totalWeight, 396, \"correct total weight\");", + "});", + " ", + "test(\"frontier\", function() {", + " var combiner =", + " portviz.knapsack.combiner(allwants,", + " function(x){return x.weight;},", + " function(x){return x.value;});", + " var ef = combiner.ef(400, 1);", + " equal(ef.length, 401, \"401 because it includes the endpoints\");", + " ef = combiner.ef(400, 40);", + " equal(ef.length, 11, \"11 because it includes the endpoints\");", + " var expectedTotalValue = [", + " 0,", + " 330,", + " 445,", + " 590,", + " 685,", + " 755,", + " 810,", + " 860,", + " 902,", + " 960,", + " 1030", + " ] ;", + " _.each(ef, function(element, index) {", + " // 15% error! bleah!", + " ok(near(element.totalValue, expectedTotalValue[index], 0.15),", + " 'actual ' + element.totalValue + ' expected ' + expectedTotalValue[index]);", + " });", + " deepEqual(_.pluck(ef, 'totalWeight'), [", + " 0,", + " 39,", + " 74,", + " 118,", + " 158,", + " 200,", + " 236,", + " 266,", + " 316,", + " 354,", + " 396", + " ]);", + " deepEqual(_.map(ef, function(x){return x.items.length;}), [", + " 0,", + " 4,", + " 6,", + " 7,", + " 9,", + " 10,", + " 10,", + " 12,", + " 14,", + " 11,", + " 12", + " ]);", + "});", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ed1", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "/*global portviz:false, _:false */\n/*\n * 0-1 knapsack solution, recursive, memoized, approximate.\n *\n * credits:\n *\n * the Go implementation here:\n * http://rosettacode.org/mw/index.php?title=Knapsack_problem/0-1\n *\n * approximation details here:\n * http://math.mit.edu/~goemans/18434S06/knapsack-katherine.pdf\n */\nportviz.knapsack = {};\n(function() {\n this.combiner = function(items, weightfn, valuefn) {\n // approximation guarantees result >= (1-e) * optimal\n var _epsilon = 0.01;\n var _p = _.max(_.map(items,valuefn));\n var _k = _epsilon * _p / items.length;\n \n var _memo = (function(){\n var _mem = {};\n var _key = function(i, w) {\n return i + '::' + w;\n };\n return {\n get: function(i, w) {\n return _mem[_key(i,w)];\n },\n put: function(i, w, r) {\n _mem[_key(i,w)]=r;\n return r;\n }\n };\n })();\n \n var _m = function(i, w) {\n \n i = Math.round(i);\n w = Math.round(w);\n \n \n if (i < 0 || w === 0) {\n // empty base case\n return {items: [], totalWeight: 0, totalValue: 0};\n }\n \n var mm = _memo.get(i,w);\n if (!_.isUndefined(mm)) {\n return mm;\n }\n \n var item = items[i];\n if (weightfn(item) > w) {\n //item does not fit, try the next item\n return _memo.put(i, w, _m(i-1, w));\n }\n // this item could fit.\n // are we better off excluding it?\n var excluded = _m(i-1, w);\n // or including it?\n var included = _m(i-1, w - weightfn(item));\n if (included.totalValue + Math.floor(valuefn(item)/_k) > excluded.totalValue) {\n // better off including it\n // make a copy of the list\n var i1 = included.items.slice();\n i1.push(item);\n return _memo.put(i, w,\n {items: i1,\n totalWeight: included.totalWeight + weightfn(item),\n totalValue: included.totalValue + Math.floor(valuefn(item)/_k)});\n }\n //better off excluding it\n return _memo.put(i,w, excluded);\n };\n return {\n /* one point */\n one: function(maxweight) {\n var scaled = _m(items.length - 1, maxweight);\n return {\n items: scaled.items,\n totalWeight: scaled.totalWeight,\n totalValue: scaled.totalValue * _k\n };\n },\n /* the entire EF */\n ef: function(maxweight, step) {\n return _.map(_.range(0, maxweight+1, step), function(weight) {\n var scaled = _m(items.length - 1, weight);\n return {\n items: scaled.items,\n totalWeight: scaled.totalWeight,\n totalValue: scaled.totalValue * _k\n };\n });\n }\n };\n };\n}).apply(portviz.knapsack);\n\n/*global portviz:false, _:false */\n/*\n * after rosettacode.org/mw/index.php?title=Knapsack_problem/0-1\n */\nvar allwants = [\n {name:\"map\", weight:9, value: 150},\n {name:\"compass\", weight:13, value: 35},\n {name:\"water\", weight:153, value: 200},\n {name:\"sandwich\", weight: 50, value: 160},\n {name:\"glucose\", weight:15, value: 60},\n {name:\"tin\", weight:68, value: 45},\n {name:\"banana\", weight:27, value: 60},\n {name:\"apple\", weight:39, value: 40},\n {name:\"cheese\", weight:23, value: 30},\n {name:\"beer\", weight:52, value: 10},\n {name:\"suntan cream\", weight:11, value: 70},\n {name:\"camera\", weight:32, value: 30},\n {name:\"T-shirt\", weight:24, value: 15},\n {name:\"trousers\", weight:48, value: 10},\n {name:\"umbrella\", weight:73, value: 40},\n {name:\"waterproof trousers\", weight:42, value: 70},\n {name:\"waterproof overclothes\", weight:43, value: 75},\n {name:\"note-case\", weight:22, value: 80},\n {name:\"sunglasses\", weight:7, value: 20},\n {name:\"towel\", weight:18, value: 12},\n {name:\"socks\", weight:4, value: 50},\n {name:\"book\", weight:30, value: 10}\n];\n \nvar near = function(actual, expected, tolerance) {\n if (expected === 0 && actual === 0) return true;\n if (expected === 0) {\n return Math.abs(expected - actual) / actual < tolerance;\n }\n return Math.abs(expected - actual) / expected < tolerance;\n};\n \ntest(\"one knapsack\", function() {\n var combiner =\n portviz.knapsack.combiner(allwants,\n function(x){return x.weight;},\n function(x){return x.value;});\n var oneport = combiner.one(400);\n ok(near(oneport.totalValue, 1030, 0.01), \"correct total value\");\n ok(near(oneport.totalValue, 1030, 0.01), \"correct total value\");\n equal(oneport.totalWeight, 396, \"correct total weight\");\n});\n \ntest(\"frontier\", function() {\n var combiner =\n portviz.knapsack.combiner(allwants,\n function(x){return x.weight;},\n function(x){return x.value;});\n var ef = combiner.ef(400, 1);\n equal(ef.length, 401, \"401 because it includes the endpoints\");\n ef = combiner.ef(400, 40);\n equal(ef.length, 11, \"11 because it includes the endpoints\");\n var expectedTotalValue = [\n 0,\n 330,\n 445,\n 590,\n 685,\n 755,\n 810,\n 860,\n 902,\n 960,\n 1030\n ] ;\n _.each(ef, function(element, index) {\n // 15% error! bleah!\n ok(near(element.totalValue, expectedTotalValue[index], 0.15),\n 'actual ' + element.totalValue + ' expected ' + expectedTotalValue[index]);\n });\n deepEqual(_.pluck(ef, 'totalWeight'), [\n 0,\n 39,\n 74,\n 118,\n 158,\n 200,\n 236,\n 266,\n 316,\n 354,\n 396\n ]);\n deepEqual(_.map(ef, function(x){return x.items.length;}), [\n 0,\n 4,\n 6,\n 7,\n 9,\n 10,\n 10,\n 12,\n 14,\n 11,\n 12\n ]);\n});\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Knapsack problem/Bounded", + "type": "Waypoint", + "description": [ + "

    A tourist wants to make a good trip at the weekend with his friends.

    They will go to the mountains to see the wonders of nature. So he needs some items during the trip. Food, clothing, etc. He has a good knapsack for carrying the things, but he knows that he can carry only 4 kg weight in his knapsack, because they will make the trip from morning to evening.

    He creates a list of what he wants to bring for the trip, but the total weight of all items is too much. He adds a value to each item. The value represents how important the thing for the tourist.

    The list contains which items are the wanted things for the trip, what is the weight and value of an item, and how many units does he have from each items.

    ", + "

    This is the list:

    ", + "

    {| style=\"text-align: left; width: 80%;\" border=\"4\" cellpadding=\"2\" cellspacing=\"2\"

    ", + "

    |+ Table of potential knapsack items

    ", + "

    |- style=\"background-color: rgb(255, 204, 255);\"

    ", + "

    ! item !! weight (dag) (each) !! value (each) !! piece(s)

    ", + "

    |-

    ", + "

    | map || 9 || 150 || 1

    ", + "

    |-

    ", + "

    | compass || 13 || 35 || 1

    ", + "

    |-

    ", + "

    | water || 153 || 200 || 2

    ", + "

    |-

    ", + "

    | sandwich || 50 || 60 || 2

    ", + "

    |-

    ", + "

    | glucose || 15 || 60 || 2

    ", + "

    |-

    ", + "

    | tin || 68 || 45 || 3

    ", + "

    |-

    ", + "

    | banana || 27 || 60 || 3

    ", + "

    |-

    ", + "

    | apple || 39 || 40 || 3

    ", + "

    |-

    ", + "

    | cheese || 23 || 30 || 1

    ", + "

    |-

    ", + "

    | beer || 52 || 10 || 3

    ", + "

    |-

    ", + "

    | suntan cream || 11 || 70 || 1

    ", + "

    |-

    ", + "

    | camera || 32 || 30 || 1

    ", + "

    |-

    ", + "

    | T-shirt || 24 || 15 || 2

    ", + "

    |-

    ", + "

    | trousers || 48 || 10 || 2

    ", + "

    |-

    ", + "

    | umbrella || 73 || 40 || 1

    ", + "

    |-

    ", + "

    | waterproof trousers || 42 || 70 || 1

    ", + "

    |-

    ", + "

    | waterproof overclothes || 43 || 75 || 1

    ", + "

    |-

    ", + "

    | note-case || 22 || 80 || 1

    ", + "

    |-

    ", + "

    | sunglasses || 7 || 20 || 1

    ", + "

    |-

    ", + "

    | towel || 18 || 12 || 2

    ", + "

    |-

    ", + "

    | socks || 4 || 50 || 1

    ", + "

    |-

    ", + "

    | book || 30 || 10 || 2

    ", + "

    |- style=\"background-color: rgb(255, 204, 255);\"

    ", + "

    | knapsack || ≤400 dag || ? || ?

    ", + "

    |}

    ", + "

    The tourist can choose to take any combination of items from the list, and some number of each item is available (see the column piece(s) in the list above).

    He may not cut the items, so he can only take whole units of any item.

    ", + "Task:", + "

    Show which items does the tourist carry in his knapsack so that their total weight does not exceed 4 kg, and their total value is maximized.

    ", + "Related tasks:", + " Knapsack problem/Unbounded", + " Knapsack problem/Continuous", + " Knapsack problem/0-1" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Based on the (dynamic) J implementation. Expressed as an htm page:", + "", + "", + "", + "This will generate (translating html to mediawiki markup):", + "{|", + "|'''Count'''", + "|'''Item'''", + "!unit weight", + "!unit value", + "|-", + "|1", + "|map", + "|9", + "|150", + "|-", + "|1", + "|compass", + "|13", + "|35", + "|-", + "|1", + "|water", + "|153", + "|200", + "|-", + "|2", + "|glucose", + "|15", + "|60", + "|-", + "|3", + "|banana", + "|27", + "|60", + "|-", + "|1", + "|cheese", + "|23", + "|30", + "|-", + "|1", + "|suntan, cream", + "|11", + "|70", + "|-", + "|1", + "|waterproof, overclothes", + "|43", + "|75", + "|-", + "|1", + "|note-case", + "|22", + "|80", + "|-", + "|1", + "|sunglasses", + "|7", + "|20", + "|-", + "|1", + "|socks", + "|4", + "|50", + "|}", + "Total weight: 396
    ", + "Total value: 1010", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ed2", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Knapsack problem/Continuous", + "type": "Waypoint", + "description": [ + "

    A thief burgles a butcher's shop, where he can select from some items.

    The thief knows the weights and prices of each items. Because he has a knapsack with 15 kg maximal capacity, he wants to select the items such that he would have his profit maximized. He may cut the items; the item has a reduced price after cutting that is proportional to the original price by the ratio of masses. That means: half of an item has half the price of the original.

    ", + "

    This is the item list in the butcher's shop:

    {| style=\"text-align: left; width: 50%;\" border=\"4\" cellpadding=\"2\" cellspacing=\"2\"

    ", + "

    |+ Table of potential knapsack items

    ", + "

    |- style=\"background-color: rgb(255, 204, 255);\"

    ", + "

    ! Item !! Weight (kg) !! Price (Value)

    ", + "

    |-

    ", + "

    | beef || 3.8 || 36

    ", + "

    |-

    ", + "

    | pork || 5.4 || 43

    ", + "

    |-

    ", + "

    | ham || 3.6 || 90

    ", + "

    |-

    ", + "

    | greaves || 2.4 || 45

    ", + "

    |-

    ", + "

    | flitch || 4.0 || 30

    ", + "

    |-

    ", + "

    | brawn || 2.5 || 56

    ", + "

    |-

    ", + "

    | welt || 3.7 || 67

    ", + "

    |-

    ", + "

    | salami || 3.0 || 95

    ", + "

    |-

    ", + "

    | sausage || 5.9 || 98

    ", + "

    |- style=\"background-color: rgb(255, 204, 255);\"

    ", + "

    | Knapsack || <=15 kg || ?

    ", + "

    |}

    ", + "Task:", + "

    Show which items the thief carries in his knapsack so that their total weight does not exceed 15 kg, and their total value is maximized.

    ", + "Related tasks:", + " Knapsack problem/Bounded", + " Knapsack problem/Unbounded", + " Knapsack problem/0-1", + "See also:", + " Wikipedia article: continuous knapsack." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ed3", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Knapsack problem/Unbounded", + "type": "Waypoint", + "description": [ + "

    A traveler gets diverted and has to make an unscheduled stop in what turns out to be Shangri La. Opting to leave, he is allowed to take as much as he likes of the following items, so long as it will fit in his knapsack, and he can carry it.

    He knows that he can carry no more than 25 'weights' in total; and that the capacity of his knapsack is 0.25 'cubic lengths'.

    Looking just above the bar codes on the items he finds their weights and volumes. He digs out his recent copy of a financial paper and gets the value of each item.

    ", + "

    ", + "

    style=\"text-align: left; width: 80%;\" border=\"4\"

    ", + "

    cellpadding=\"2\" cellspacing=\"2\">", + "

    style=\"font-weight: bold;\" align=\"left\" nowrap=\"nowrap\"

    ", + "

    valign=\"middle\">Item", + "

    style=\"font-weight: bold;\" align=\"left\" nowrap=\"nowrap\"

    ", + "

    valign=\"middle\">Explanation", + "

    style=\"font-weight: bold;\" align=\"left\" nowrap=\"nowrap\"

    ", + "

    valign=\"middle\">Value (each)", + "

    style=\"font-weight: bold;\" align=\"left\" nowrap=\"nowrap\"

    ", + "

    valign=\"middle\">weight", + "

    style=\"font-weight: bold;\" align=\"left\" nowrap=\"nowrap\"

    ", + "

    valign=\"middle\">Volume (each)", + "

    align=\"left\" nowrap=\"nowrap\" valign=\"middle\">panacea

    ", + "

    (vials of)", + "

    valign=\"middle\">Incredible healing properties", + "

    align=\"left\" nowrap=\"nowrap\" valign=\"middle\">3000", + "

    align=\"left\" nowrap=\"nowrap\" valign=\"middle\">0.3", + "

    align=\"left\" nowrap=\"nowrap\" valign=\"middle\">0.025", + "

    align=\"left\" nowrap=\"nowrap\" valign=\"middle\">ichor

    ", + "

    (ampules of)", + "

    valign=\"middle\">Vampires blood", + "

    nowrap=\"nowrap\" valign=\"middle\">1800", + "

    align=\"left\" nowrap=\"nowrap\" valign=\"middle\">0.2", + "

    align=\"left\" nowrap=\"nowrap\" valign=\"middle\">0.015", + "

    align=\"left\" nowrap=\"nowrap\" valign=\"middle\">gold

    ", + "

    (bars)", + "

    valign=\"middle\">Shiney shiney", + "

    nowrap=\"nowrap\" valign=\"middle\">2500", + "

    align=\"left\" nowrap=\"nowrap\" valign=\"middle\">2.0", + "

    align=\"left\" nowrap=\"nowrap\" valign=\"middle\">0.002", + "

    style=\"background-color: rgb(255, 204, 255);\" align=\"left\"

    ", + "

    nowrap=\"nowrap\" valign=\"middle\">Knapsack", + "

    style=\"background-color: rgb(255, 204, 255);\" align=\"left\"

    ", + "

    nowrap=\"nowrap\" valign=\"middle\">For the carrying of", + "

    style=\"background-color: rgb(255, 204, 255);\" align=\"left\"

    ", + "

    nowrap=\"nowrap\" valign=\"middle\">-", + "

    style=\"background-color: rgb(255, 204, 255);\" align=\"left\"

    ", + "

    nowrap=\"nowrap\" valign=\"middle\"><=25", + "

    style=\"background-color: rgb(255, 204, 255);\" align=\"left\"

    ", + "

    nowrap=\"nowrap\" valign=\"middle\"><=0.25

    ", + "", + "

    He can only take whole units of any item, but there is much more of any item than he could ever carry

    ", + "Task:", + "

    Show how many of each item does he take to maximize the value of items he is carrying away with him.

    ", + "Note: ", + " There are four solutions that maximize the value taken. Only one need be given.

    Related tasks:", + " Knapsack problem/Bounded", + " Knapsack problem/Continuous", + " Knapsack problem/0-1" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Brute force.", + "var gold = { 'value': 2500, 'weight': 2.0, 'volume': 0.002 },", + " panacea = { 'value': 3000, 'weight': 0.3, 'volume': 0.025 },", + " ichor = { 'value': 1800, 'weight': 0.2, 'volume': 0.015 },", + " ", + " items = [gold, panacea, ichor],", + " knapsack = {'weight': 25, 'volume': 0.25},", + " max_val = 0,", + " solutions = [],", + " g, p, i, item, val;", + " ", + "for (i = 0; i < items.length; i += 1) {", + " item = items[i];", + " item.max = Math.min(", + " Math.floor(knapsack.weight / item.weight),", + " Math.floor(knapsack.volume / item.volume)", + " );", + "}", + " ", + "for (g = 0; g <= gold.max; g += 1) {", + " for (p = 0; p <= panacea.max; p += 1) {", + " for (i = 0; i <= ichor.max; i += 1) {", + " if (i * ichor.weight + g * gold.weight + p * panacea.weight > knapsack.weight) {", + " continue;", + " }", + " if (i * ichor.volume + g * gold.volume + p * panacea.volume > knapsack.volume) {", + " continue;", + " }", + " val = i * ichor.value + g * gold.value + p * panacea.value;", + " if (val > max_val) {", + " solutions = [];", + " max_val = val;", + " }", + " if (val === max_val) {", + " solutions.push([g, p, i]);", + " }", + " }", + " }", + "}", + " ", + "document.write(\"maximum value: \" + max_val + '
    ');", + "for (i = 0; i < solutions.length; i += 1) {", + " item = solutions[i];", + " document.write(\"(gold: \" + item[0] + \", panacea: \" + item[1] + \", ichor: \" + item[2] + \")
    \");", + "}", + "", + "output:", + "

    maximum value: 54500",
    +        "(gold: 11, panacea: 0, ichor: 15)",
    +        "(gold: 11, panacea: 3, ichor: 10)",
    +        "(gold: 11, panacea: 6, ichor: 5)",
    +        "(gold: 11, panacea: 9, ichor: 0)
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ed4", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var gold = { 'value': 2500, 'weight': 2.0, 'volume': 0.002 },\n panacea = { 'value': 3000, 'weight': 0.3, 'volume': 0.025 },\n ichor = { 'value': 1800, 'weight': 0.2, 'volume': 0.015 },\n \n items = [gold, panacea, ichor],\n knapsack = {'weight': 25, 'volume': 0.25},\n max_val = 0,\n solutions = [],\n g, p, i, item, val;\n \nfor (i = 0; i < items.length; i += 1) {\n item = items[i];\n item.max = Math.min(\n Math.floor(knapsack.weight / item.weight),\n Math.floor(knapsack.volume / item.volume)\n );\n}\n \nfor (g = 0; g <= gold.max; g += 1) {\n for (p = 0; p <= panacea.max; p += 1) {\n for (i = 0; i <= ichor.max; i += 1) {\n if (i * ichor.weight + g * gold.weight + p * panacea.weight > knapsack.weight) {\n continue;\n }\n if (i * ichor.volume + g * gold.volume + p * panacea.volume > knapsack.volume) {\n continue;\n }\n val = i * ichor.value + g * gold.value + p * panacea.value;\n if (val > max_val) {\n solutions = [];\n max_val = val;\n }\n if (val === max_val) {\n solutions.push([g, p, i]);\n }\n }\n }\n}\n \ndocument.write(\"maximum value: \" + max_val + '
    ');\nfor (i = 0; i < solutions.length; i += 1) {\n item = solutions[i];\n document.write(\"(gold: \" + item[0] + \", panacea: \" + item[1] + \", ichor: \" + item[2] + \")
    \");\n}\n\noutput:\n
    maximum value: 54500\n(gold: 11, panacea: 0, ichor: 15)\n(gold: 11, panacea: 3, ichor: 10)\n(gold: 11, panacea: 6, ichor: 5)\n(gold: 11, panacea: 9, ichor: 0)
    \n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Knight's tour", + "type": "Waypoint", + "description": [ + "Task", + "

    Problem: you have a standard 8x8 chessboard, empty but for a single knight on some square. Your task is to emit a series of legal knight moves that result in the knight visiting every square on the chessboard exactly once. Note that it is not a requirement that the tour be \"closed\"; that is, the knight need not end within a single move of its start position.

    Input and output may be textual or graphical, according to the conventions of the programming environment. If textual, squares should be indicated in algebraic notation. The output should indicate the order in which the knight visits the squares, starting with the initial position. The form of the output may be a diagram of the board with the squares numbered according to visitation sequence, or a textual list of algebraic coordinates in order, or even an actual animation of the knight moving around the chessboard.

    Input: starting square

    Output: move sequence

    ", + "Related tasks", + "A* search algorithm", + "N-queens problem", + "Solve a Hidato puzzle", + "Solve a Holy Knight's tour", + "Solve a Hopido puzzle", + "Solve a Numbrix puzzle", + "Solve the no connection puzzle" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ed5", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Knuth's algorithm S", + "type": "Waypoint", + "description": [ + "

    This is a method of randomly sampling n items from a set of M items, with equal probability; where M >= n and M, the number of items is unknown until the end.

    ", + "

    This means that the equal probability sampling should be maintained for all successive items > n as they become available (although the content of successive samples can change).

    The algorithm:", + "Select the first n items as the sample as they become available;", + "For the i-th item where i > n, have a random chance of n/i of keeping it. If failing this chance, the sample remains the same. If not, have it randomly (1/n) replace one of the previously selected n items of the sample.", + "Repeat #2 for any subsequent items.", + "The Task:", + "Create a function s_of_n_creator that given $n$ the maximum sample size, returns a function s_of_n that takes one parameter, item.", + "Function s_of_n when called with successive items returns an equi-weighted random sample of up to n of its items so far, each time it is called, calculated using Knuths Algorithm S.", + "Test your functions by printing and showing the frequency of occurrences of the selected digits from 100,000 repetitions of:# Use the s_of_n_creator with n == 3 to generate an s_of_n.", + "

    # call s_of_n with each of the digits 0 to 9 in order, keeping the returned three digits of its random sampling from its last call with argument item=9.

    Note: A class taking n and generating a callable instance/function might also be used.

    Reference:", + "The Art of Computer Programming, Vol 2, 3.4.2 p.142", + "Cf.", + "One of n lines in a file ", + "Accumulator factory" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ed6", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Knuth shuffle", + "type": "Waypoint", + "description": [ + "

    The Knuth shuffle (a.k.a. the Fisher-Yates shuffle) is an algorithm for randomly shuffling the elements of an array.

    ", + "

    Implement the Knuth shuffle for an integer array (or, if possible, an array of any type).

    ", + "

    Given an array items with indices ranging from 0 to last, the algorithm can be defined as follows (pseudo-code):

    for i from last downto 1 do:

    ", + "

    let j = random integer in range 0 $\\leq$ j $\\leq$ i

    ", + "

    swap items[i] with items[j]

    Notes:

    ", + "It modifies the input array in-place. If that is unreasonable in your programming language, you may amend the algorithm to return the shuffled items as a new array instead.", + "The algorithm can also be amended to iterate from left to right, if that is more convenient.", + "

    {|

    ", + "

    |-

    ", + "

    ! Input array

    ", + "

    ! Possible output arrays

    ", + "

    |-

    ", + "

    | []

    ", + "

    | []

    ", + "

    |-

    ", + "

    | [10]

    ", + "

    | [10]

    ", + "

    |-

    ", + "

    | [10, 20]

    ", + "

    | [10, 20][20, 10]

    ", + "

    |-

    ", + "

    | [10, 20, 30]

    ", + "

    | [10, 20, 30][10, 30, 20][20, 10, 30][20, 30, 10][30, 10, 20][30, 20, 10]

    ", + "

    |}

    (These are listed here just for your convenience; no need to demonstrate them on the page.)

    ", + "Sattolo cycle", + "


    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "function knuthShuffle(arr) {", + " var rand, temp, i;", + "", + " for (i = arr.length - 1; i > 0; i -= 1) {", + " rand = Math.floor((i + 1) * Math.random());//get random between zero and i (inclusive)", + " temp = arr[rand];//swap i and the zero-indexed number", + " arr[rand] = arr[i];", + " arr[i] = temp;", + " }", + " return arr;", + "}", + "", + "var res = {", + " '1,2,3': 0, '1,3,2': 0,", + " '2,1,3': 0, '2,3,1': 0,", + " '3,1,2': 0, '3,2,1': 0", + "};", + "", + "for (var i = 0; i < 100000; i++) {", + " res[knuthShuffle([1,2,3]).join(',')] += 1;", + "}", + "", + "for (var key in res) {", + " print(key + \"\\t\" + res[key]);", + "}", + "Results in:", + "
    1,2,3   16619",
    +        "1,3,2   16614",
    +        "2,1,3   16752",
    +        "2,3,1   16959",
    +        "3,1,2   16460",
    +        "3,2,1   16596
    ", + "", + "", + "===ES6===", + "", + "====Mutating in-place swap====", + "(lst => {", + " ", + " // knuthShuffle :: [a] -> [a]", + " let knuthShuffle = lst =>", + " range(0, lst.length - 1)", + " .reduceRight((a, i) => {", + " let iRand = i ? randomInteger(0, i) : 0,", + " tmp = a[iRand];", + "", + " return iRand !== i ? (", + " a[iRand] = a[i],", + " a[i] = tmp,", + " a", + " ) : a;", + " }, lst),", + " ", + " // randomInteger :: Int -> Int -> Int", + " randomInteger = (low, high) =>", + " low + Math.floor(", + " (Math.random() * ((high - low) + 1))", + " ),", + " ", + " // range :: Int -> Int -> Maybe Int -> [Int]", + " range = (m, n, step) => {", + " let d = (step || 1) * (n >= m ? 1 : -1);", + " ", + " return Array.from({", + " length: Math.floor((n - m) / d) + 1", + " }, (_, i) => m + (i * d));", + " };", + " ", + " ", + " return knuthShuffle(lst);", + " ", + "})(", + " 'alpha beta gamma delta epsilon zeta eta theta iota kappa lambda mu'", + " .split(' ')", + " );", + "", + "{{Out}}", + "e.g.", + "[\"iota\", \"epsilon\", \"kappa\", \"theta\", \"gamma\", \"delta\", ", + "\"lambda\", \"eta\", \"zeta\", \"beta\", \"mu\", \"alpha\"]", + "", + "====Non-mutating swap====", + "", + "(lst => {", + "", + " // knuthShuffle :: [a] -> [a]", + " function knuthShuffle(lst) {", + " let lng = lst.length;", + "", + " return lng ? range(0, lng - 1)", + " .reduceRight((a, i) => {", + " let iRand = i > 0 ? randomInteger(0, i) : 0;", + "", + " return i !== iRand ? swapped(a, i, iRand) : a;", + " }, lst) : [];", + " };", + "", + "", + " // A non-mutating variant of swapped():", + "", + " // swapped :: [a] -> Int -> Int -> [a] ", + " let swapped = (lst, iFrom, iTo) => {", + " let [iLow, iHigh] = iTo > iFrom ? (", + " [iFrom, iTo]", + " ) : [iTo, iFrom];", + "", + " return iLow !== iHigh ? (", + " [].concat(", + " (iLow > 0 ? lst.slice(0, iLow) : []), // pre", + " lst[iHigh], // DOWN", + " lst.slice(iLow + 1, iHigh), // mid", + " lst[iLow], // UP", + " lst.slice(iHigh + 1) // post", + " ) ", + " ) : lst.slice(0) // (unchanged copy)", + " },", + "", + " // randomInteger :: Int -> Int -> Int", + " randomInteger = (low, high) =>", + " low + Math.floor(", + " (Math.random() * ((high - low) + 1))", + " ),", + "", + " // range :: Int -> Int -> Maybe Int -> [Int]", + " range = (m, n, step) => {", + " let d = (step || 1) * (n >= m ? 1 : -1);", + "", + " return Array.from({", + " length: Math.floor((n - m) / d) + 1", + " }, (_, i) => m + (i * d));", + " };", + "", + "", + " return knuthShuffle(lst);", + "", + "})(", + " 'alpha beta gamma delta epsilon zeta eta theta iota kappa lambda mu'", + " .split(' ')", + ");", + "", + "{{Out}}", + "e.g.", + "[\"mu\", \"theta\", \"beta\", \"eta\", \"delta\", \"epsilon\", ", + "\"kappa\", \"alpha\", \"gamma\", \"lambda\", \"zeta\", \"iota\"]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ed7", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function knuthShuffle(arr) {\n var rand, temp, i;\n\n for (i = arr.length - 1; i > 0; i -= 1) {\n rand = Math.floor((i + 1) * Math.random());//get random between zero and i (inclusive)\n temp = arr[rand];//swap i and the zero-indexed number\n arr[rand] = arr[i];\n arr[i] = temp;\n }\n return arr;\n}\n\nvar res = {\n '1,2,3': 0, '1,3,2': 0,\n '2,1,3': 0, '2,3,1': 0,\n '3,1,2': 0, '3,2,1': 0\n};\n\nfor (var i = 0; i < 100000; i++) {\n res[knuthShuffle([1,2,3]).join(',')] += 1;\n}\n\nfor (var key in res) {\n print(key + \"\\t\" + res[key]);\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Kronecker product based fractals", + "type": "Waypoint", + "description": [ + "

    This task is based on Kronecker product of two matrices. If your

    ", + "

    language has no a built-in function for such product then you need to implement it first.

    ", + "

    The essence of fractals is self-replication (at least, self-similar replications).

    ", + "

    So, using n times self-product of the matrix (filled with 0/1) we will have a fractal of the n-th order.

    ", + "

    Actually, \"self-product\" is a Kronecker power of the matrix. In other words: for a matrix M and a power n create a function like matkronpow(M, n), which returns MxMxMx... (n times product).

    ", + "

    A formal recurrent algorithm of creating Kronecker power of a matrix is the following:

    ", + "

    Algorithm:

    ", + "

    Let M is an initial matrix, and Rn is a resultant block matrix of the Kronecker power, where n is the power (a.k.a. order).

    ", + "

    Self-product of M, i.e., M x M producing R2 (resultant matrix with order/power 2).

    ", + "

    To receive the next order/power matrix use this recurrent formula: Rn = R(n-1) x M.

    ", + "

    Plot this Rn matrix to produce the nth order fractal.

    ", + "

    Even just looking at the resultant matrix you can see what will be plotted.

    ", + "

    There are virtually infinitely many fractals of this type. You are limited only by your creativity and

    ", + "

    the power of your computer.

    ", + "Task:", + "

    Using Kronecker product implement and show two popular and well-known fractals, i.e.:

    ", + " Vicsek fractal;", + " Sierpinski carpet fractal.", + "The last one ( Sierpinski carpet) is already here on RC, but built using different approaches.", + "Test cases:", + "

    These 2 fractals (each order/power 4 at least) should be built using the following 2 simple matrices:

    ", + "
    ",
    +        "|0 1 0|\tand |1 1 1|",
    +        "|1 1 1|\t    |1 0 1|",
    +        "|0 1 0|\t    |1 1 1|",
    +        "
    ", + "Note:", + "Output could be a graphical or ASCII-art representation, but if an order is set > 4 then printing is not suitable.", + "The orientation and distortion of the fractal could be your language/tool specific.", + "It would be nice to see one additional fractal of your choice, e.g., based on using a single (double) letter(s) of an alphabet, any sign(s) or alredy made a resultant matrix of the Kronecker product.", + "See implementations and results below in JavaScript, PARI/GP and R languages. They have additional samples of \"H\", \"+\" and checkerboard fractals." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Using Version #1 of [[Kronecker_product| Kronecker product]] in JavaScript.", + "{{Works with|Chrome}}", + "[[File:VicsekFractaljs.png|200px|right|thumb|Output VicsekFractaljs.png]]", + "[[File:SierpCarpetFractaljs.png|200px|right|thumb|Output SierpCarpetFractaljs.png]]", + "[[File:CheckbrdFractaljs.png|200px|right|thumb|Output CheckbrdFractaljs.png]]", + "", + "// KPF.js 6/23/16 aev", + "// HFJS: Plot any matrix mat (filled with 0,1)", + "function pmat01(mat, color) {", + " // DCLs", + " var cvs = document.getElementById('canvId');", + " var ctx = cvs.getContext(\"2d\"); ", + " var w = cvs.width; var h = cvs.height;", + " var m = mat[0].length; var n = mat.length;", + " // Cleaning canvas and setting plotting color ", + " ctx.fillStyle=\"white\"; ctx.fillRect(0,0,w,h);", + " ctx.fillStyle=color;", + " // MAIN LOOP", + " for(var i=0; i'+title+'
    :
    ');",
    +        "  for(var i=0; i'); re='';",
    +        "  }//fend i",
    +        "  document.write('
    ');", + "}", + "// mkp function (exotic arrow function): Return the Kronecker product", + "// of the a and b matrices", + "mkp=(a,b)=>a.map(a=>b.map(b=>a.map(y=>b.map(x=>r.push(y*x)),t.push(r=[]))),t=[])&&t;", + " ", + "", + ";Required tests:", + "", + "", + "", + "", + " Vicsek fractal", + " ", + "", + "", + "

    Vicsek fractal

    ", + " Next: Sierpinski carpet fractal
    ", + " ", + "", + "
    ", + "", + "", + "", + "", + "", + " Sierpinski carpet fractal", + " ", + "", + "", + "

    Sierpinski carpet fractal

    ", + " Next: Checkerboard
    ", + " ", + "", + "", + "", + "", + "", + "", + " Checkerboard", + " ", + "", + "", + "

    Checkerboard

    ", + " Next: Vicsek fractal
    ", + " ", + "", + "
    ", + "", + "{{Output}} ", + "
    ",
    +        "Page VicsekFractal.html with VicsekFractaljs.png",
    +        "Page SierpCarpetFractal.html with SierpCarpetFractaljs.png",
    +        "Page Checkerboard.html with CheckbrdFractaljs.png",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ed8", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n// KPF.js 6/23/16 aev\n// HFJS: Plot any matrix mat (filled with 0,1)\nfunction pmat01(mat, color) {\n // DCLs\n var cvs = document.getElementById('canvId');\n var ctx = cvs.getContext(\"2d\"); \n var w = cvs.width; var h = cvs.height;\n var m = mat[0].length; var n = mat.length;\n // Cleaning canvas and setting plotting color \n ctx.fillStyle=\"white\"; ctx.fillRect(0,0,w,h);\n ctx.fillStyle=color;\n // MAIN LOOP\n for(var i=0; i'+title+':
    ');\n  for(var i=0; i'); re='';\n  }//fend i\n  document.write('
    ');\n}\n// mkp function (exotic arrow function): Return the Kronecker product\n// of the a and b matrices\nmkp=(a,b)=>a.map(a=>b.map(b=>a.map(y=>b.map(x=>r.push(y*x)),t.push(r=[]))),t=[])&&t;\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Kronecker product", + "type": "Waypoint", + "description": [ + "Task:", + "

    Implement the Kronecker product of two matrices (arbitrary sized) resulting in a block matrix.

    ", + "Test cases:", + "

    Show results for each of the following two samples:

    Sample 1 (from Wikipedia):

    ", + "
    ",
    +        "│1 2│  x  │0 5│\t= │ 0  5  0 10│",
    +        "│3 4│     │6 7│\t  │ 6  7 12 14│",
    +        "\t\t  │ 0 15  0 20│",
    +        "\t\t  │18 21 24 28│",
    +        "

    Sample 2:

    ", + "
    ",
    +        "│0 1 0│ x │1 1 1 1│ = │0 0 0 0 1 1 1 1 0 0 0 0│",
    +        "│1 1 1│   │1 0 0 1│   │0 0 0 0 1 0 0 1 0 0 0 0│",
    +        "│0 1 0│   │1 1 1 1│   │0 0 0 0 1 1 1 1 0 0 0 0│",
    +        "\t              │1 1 1 1 1 1 1 1 1 1 1 1│",
    +        "                      │1 0 0 1 1 0 0 1 1 0 0 1│",
    +        "                      │1 1 1 1 1 1 1 1 1 1 1 1│",
    +        "                      │0 0 0 0 1 1 1 1 0 0 0 0│",
    +        "                      │0 0 0 0 1 0 0 1 0 0 0 0│",
    +        "                      │0 0 0 0 1 1 1 1 0 0 0 0│",
    +        "
    ", + "

    See implementations and results below in JavaScript and PARI/GP languages.

    ", + "Related task:", + " Kronecker product based fractals. " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===Imperative===", + "====Version #1.====", + "{{Works with|Chrome}}", + "", + "// matkronprod.js", + "// Prime function:", + "// mkp arrow function: Return the Kronecker product of the a and b matrices.", + "// Note: both a and b must be matrices, i.e., 2D rectangular arrays.", + "mkp=(a,b)=>a.map(a=>b.map(b=>a.map(y=>b.map(x=>r.push(y*x)),t.push(r=[]))),t=[])&&t;", + "// Helper functions:", + "// Log title and matrix mat to console", + "function matl2cons(title,mat) {console.log(title); console.log(mat.join`\\n`)}", + "// Print title to document", + "function pttl2doc(title) {document.write(''+title+'
    ')}", + "// Print title and matrix mat to document", + "function matp2doc(title,mat) {", + " document.write(''+title+':
    ');", + " for (var i = 0; i < mat.length; i++) {", + " document.write('  '+mat[i].join(' ')+'
    ');", + " }", + "}", + "
    ", + "", + ";Required tests:", + "", + "", + "", + " Kronecker product: Sample 1 (from Wikipedia) and Sample 2", + " ", + " ", + "", + "", + " ", + "{{Output}} '''Console and page results'''", + "
    ",
    +        "Kronecker product of A and B matrices",
    +        "A",
    +        "1,2",
    +        "3,4",
    +        "B",
    +        "0,5",
    +        "6,7",
    +        "A x B",
    +        "0,5,0,10",
    +        "6,7,12,14",
    +        "0,15,0,20",
    +        "18,21,24,28",
    +        "Kronecker product of A and B matrices",
    +        "A",
    +        "0,1,0",
    +        "1,1,1",
    +        "0,1,0",
    +        "B",
    +        "1,1,1,1",
    +        "1,0,0,1",
    +        "1,1,1,1",
    +        "A x B",
    +        "0,0,0,0,1,1,1,1,0,0,0,0",
    +        "0,0,0,0,1,0,0,1,0,0,0,0",
    +        "0,0,0,0,1,1,1,1,0,0,0,0",
    +        "1,1,1,1,1,1,1,1,1,1,1,1",
    +        "1,0,0,1,1,0,0,1,1,0,0,1",
    +        "1,1,1,1,1,1,1,1,1,1,1,1",
    +        "0,0,0,0,1,1,1,1,0,0,0,0",
    +        "0,0,0,0,1,0,0,1,0,0,0,0",
    +        "0,0,0,0,1,1,1,1,0,0,0,0",
    +        "
    ", + "", + "====Version #2.====", + "This version is more understandable for sure.", + "{{trans|PARI/GP}}", + "{{Works with|Chrome}}", + "", + "// matkronprod2.js", + "// Prime function:", + "// mkp2(): Return the Kronecker product of the a and b matrices", + "// Note: both a and b must be matrices, i.e., 2D rectangular arrays.", + "function mkp2(a,b) {", + " var m=a.length, n=a[0].length, p=b.length, q=b[0].length;", + " var rtn=m*p, ctn=n*q; var r=new Array(rtn);", + " for (var i=0; i'+title+'
    ')}", + "// Print title and matrix mat to document", + "function matp2doc(title,mat) {", + " document.write(''+title+':
    ');", + " for (var i=0; i < mat.length; i++) {", + " document.write('  '+mat[i].join(' ')+'
    ');", + " }", + "}", + "
    ", + ";Required tests:", + "", + "", + "", + " Kronecker product v.2: Sample 1 (from Wikipedia) and Sample 2", + " ", + " ", + "", + "", + " ", + "", + "{{Output}} '''Console and page results'''", + "
    ",
    +        "Output is identical to Version #1 above.",
    +        "
    ", + "", + "===Functional===", + "====ES6====", + "{{Trans|Haskell}}", + "(As JavaScript is now widely embedded in non-browser contexts, a non-HTML string value is returned here, rather than invoking a DOM method, which will not always be available to a JavaScript interpreter)", + "(() => {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // concat :: [[a]] -> [a]", + " const concat = xs => [].concat.apply([], xs);", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " const concatMap = (f, xs) => [].concat.apply([], xs.map(f));", + "", + " // 2 or more arguments", + " // curry :: Function -> Function", + " const curry = (f, ...args) => {", + " const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :", + " function () {", + " return go(xs.concat([].slice.apply(arguments)));", + " };", + " return go([].slice.call(args, 1));", + " };", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = curry((f, xs) => xs.map(f));", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x); //, null, 2);", + "", + " // transpose :: [[a]] -> [[a]]", + " const transpose = xs =>", + " xs[0].map((_, col) => xs.map(row => row[col]));", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + "", + " // KRONECKER PRODUCT OF TWO MATRICES --------------------------------------", + "", + " // kprod :: [[Num]] -> [[Num]] -> [[Num]]", + " const kprod = (xs, ys) =>", + " concatMap(", + " m => map(concat, transpose(m)),", + " map(map(f(ys)), xs)", + " );", + "", + " // (* n) mapped over each element in a matrix", + " // f :: [[Num]] -> Num -> [[Num]]", + " const f = curry((mx, n) => map(map(x => x * n), mx));", + "", + " // TEST -------------------------------------------------------------------", + " return unlines(map(rows => unlines(map(show, rows)), [", + " kprod([", + " [1, 2],", + " [3, 4]", + " ], [", + " [0, 5],", + " [6, 7]", + " ]), [], // One empty output line", + " kprod([", + " [0, 1, 0],", + " [1, 1, 1],", + " [0, 1, 0]", + " ], [", + " [1, 1, 1, 1],", + " [1, 0, 0, 1],", + " [1, 1, 1, 1]", + " ])", + " ]));", + "})();", + "{{Out}}", + "
    [0,5,0,10]",
    +        "[6,7,12,14]",
    +        "[0,15,0,20]",
    +        "[18,21,24,28]",
    +        "",
    +        "[0,0,0,0,1,1,1,1,0,0,0,0]",
    +        "[0,0,0,0,1,0,0,1,0,0,0,0]",
    +        "[0,0,0,0,1,1,1,1,0,0,0,0]",
    +        "[1,1,1,1,1,1,1,1,1,1,1,1]",
    +        "[1,0,0,1,1,0,0,1,1,0,0,1]",
    +        "[1,1,1,1,1,1,1,1,1,1,1,1]",
    +        "[0,0,0,0,1,1,1,1,0,0,0,0]",
    +        "[0,0,0,0,1,0,0,1,0,0,0,0]",
    +        "[0,0,0,0,1,1,1,1,0,0,0,0]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ed9", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n// matkronprod.js\n// Prime function:\n// mkp arrow function: Return the Kronecker product of the a and b matrices.\n// Note: both a and b must be matrices, i.e., 2D rectangular arrays.\nmkp=(a,b)=>a.map(a=>b.map(b=>a.map(y=>b.map(x=>r.push(y*x)),t.push(r=[]))),t=[])&&t;\n// Helper functions:\n// Log title and matrix mat to console\nfunction matl2cons(title,mat) {console.log(title); console.log(mat.join`\\n`)}\n// Print title to document\nfunction pttl2doc(title) {document.write(''+title+'
    ')}\n// Print title and matrix mat to document\nfunction matp2doc(title,mat) {\n document.write(''+title+':
    ');\n for (var i = 0; i < mat.length; i++) {\n document.write('  '+mat[i].join(' ')+'
    ');\n }\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Langton's ant", + "type": "Waypoint", + "description": [ + "

    Langton's ant is a cellular automaton that models an ant sitting on a plane of cells, all of which are white initially, facing in one of four directions.

    ", + "

    Each cell can either be black or white.

    ", + "

    The ant moves according to the color of the cell it is currently sitting in, with the following rules:

    ", + "

    :# If the cell is black, it changes to white and the ant turns left;

    ", + "

    :# If the cell is white, it changes to black and the ant turns right;

    ", + "

    :# The ant then moves forward to the next cell, and repeat from step 1.

    This rather simple ruleset leads to an initially chaotic movement pattern, and after about 10000 steps, a cycle appears where the ant moves steadily away from the starting location in a diagonal corridor about 10 pixels wide. ", + "

    Conceptually the ant can then travel infinitely far away.

    ", + "Task:", + "

    Start the ant near the center of a 100 by 100 field of cells, which is about big enough to contain the initial chaotic part of the movement.

    Follow the movement rules for the ant, terminate when it moves out of the region, and show the cell colors it leaves behind.

    ", + "

    The problem has received some analysis; for more details, please take a look at the Wikipedia article (a link is below)..

    ", + "See also:", + " Wikipedia: Langton's ant.Related task:", + " Rosetta Code: Conway's Game of Life." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "Utilises the HTML5 canvas element to procedurally generate the image... I wanted to see the progress of the grid state as it was generated, so this implementation produces a incrementally changing image until an 'ant' hits a cell outside of the coordinate system. It can also accept multiple ants, this adds minimal complexity with only the addition of an 'ants' array which is iterated in each step, no additional conditions are necessary to simulate multiple ants, they coexist quite well... good ants ! 1st argument is an array of ant objects, 2nd argument is an object property list of options to change grid size, pixel size and interval (animation speed).", + "", + "", + "// create global canvas", + "var canvas = document.createElement('canvas');", + "canvas.id = 'globalCanvas';", + "document.body.appendChild(canvas);", + "", + "function langtonant(antx, optx) {", + "\t'use strict';", + "\tvar x, y, i;", + "", + "\t// extend default opts", + "\tvar opts = {", + "\t\tgridsize: 100,", + "\t\tpixlsize: 4,", + "\t\tinterval: 4", + "\t};", + "\tfor (i in optx) {", + "\t\topts[i] = optx[i];", + "\t}", + "", + "\t// extend default ants", + "\tvar ants = [{", + "\t\tx: 50,", + "\t\ty: 50,", + "\t\td: 0", + "\t}];", + "\tfor (i in antx) {", + "\t\tants[i] = antx[i];", + "\t}", + "", + "\t// initialise grid", + "\tvar grid = [];", + "\tfor (x = 0; x < opts.gridsize; x ++) {", + "\t\tgrid[x] = [];", + "\t\tfor (y = 0; y < opts.gridsize; y ++) {", + "\t\t\tgrid[x][y] = true;", + "\t\t}", + "\t}", + "", + "\t// initialise directions", + "\tvar dirs = [", + "\t\t{x: 1, y: 0},", + "\t\t{x: 0, y: -1},", + "\t\t{x: -1, y: 0},", + "\t\t{x: 0, y: 1}", + "\t];", + "", + "\t// initialise canvas", + "\tvar canv = document.getElementById('globalCanvas');", + "\tvar cont = canv.getContext('2d');", + "\tcanv.width = opts.gridsize * opts.pixlsize;", + "\tcanv.height = opts.gridsize * opts.pixlsize;", + "", + "\t// initialise pixels", + "\tvar pixlblac = cont.createImageData(opts.pixlsize, opts.pixlsize);", + "\tfor (i = 0; i < (opts.pixlsize * opts.pixlsize * 4); i += 4) {", + "\t\tpixlblac.data[i + 3] = 255;", + "\t}", + "\tvar pixlwhit = cont.createImageData(opts.pixlsize, opts.pixlsize);", + "\tfor (i = 0; i < (opts.pixlsize * opts.pixlsize * 4); i += 4) {", + "\t\tpixlwhit.data[i + 3] = 0;", + "\t}", + "", + "\t// run simulation", + "\tfunction simulate() {", + "\t\tvar sane = true;", + "", + "\t\t// iterate over ants", + "\t\tfor (i = 0; i < ants.length; i ++) {", + "\t\t\tvar n = ants[i];", + "", + "\t\t\t// invert, draw, turn", + "\t\t\tif (grid[n.x][n.y]) {", + "\t\t\t\tgrid[n.x][n.y] = false;", + "\t\t\t\tcont.putImageData(pixlblac, n.x * opts.pixlsize, n.y * opts.pixlsize);", + "\t\t\t\tn.d --;", + "\t\t\t} else {", + "\t\t\t\tgrid[n.x][n.y] = true;", + "\t\t\t\tcont.putImageData(pixlwhit, n.x * opts.pixlsize, n.y * opts.pixlsize);", + "\t\t\t\tn.d ++;", + "\t\t\t}", + "", + "\t\t\t// modulus wraparound", + "\t\t\tn.d += dirs.length;", + "\t\t\tn.d %= dirs.length;", + "", + "\t\t\t// position + direction", + "\t\t\tn.x += dirs[n.d].x;", + "\t\t\tn.y += dirs[n.d].y;", + "", + "\t\t\t// sanity check", + "\t\t\tsane = (n.x < 0 || n.x > opts.gridsize || n.y < 0 || n.y > opts.gridsize) ? false : sane;", + "\t\t}", + "", + "\t\t// loop with interval", + "\t\tif (sane) {", + "\t\t\tsetTimeout(simulate, opts.interval);", + "\t\t}", + "\t}", + "", + "\tsimulate();", + "}", + "", + "", + "Usage: default ants, custom opts", + "", + "", + "langtonant({}, {", + "\tgridsize: 100,", + "\tpixlsize: 4,", + "\tinterval: 4", + "});", + "", + "", + "{{out}}", + "", + "[http://jsbin.com/ocuwal/1/edit Live Version]", + "", + "[[Image:Langtons Ant - JavaScript 1.png]]", + "", + "Usage: custom ants, default opts", + "", + "", + "langtonant([", + "\t{", + "\t\tx: (100 / 2) + 7,", + "\t\ty: (100 / 2) + 7,", + "\t\td: 1", + "\t}, {", + "\t\tx: (100 / 2) + 7,", + "\t\ty: (100 / 2) - 7,", + "\t\td: 2", + "\t}, {", + "\t\tx: (100 / 2) - 7,", + "\t\ty: (100 / 2) - 7,", + "\t\td: 3", + "\t}, {", + "\t\tx: (100 / 2) - 7,", + "\t\ty: (100 / 2) + 7,", + "\t\td: 0", + "\t}", + "]);", + "", + "", + "{{out}}", + "", + "[http://jsbin.com/ahumuz/1/edit Live Version]", + "", + "[[Image:Langtons Ant - JavaScript 2.png]]", + "", + "'''More functional approach to Javascript.'''", + "", + "Requires lodash. Wants a canvas with id = \"c\"", + "", + "", + "///////////////////", + "// LODASH IMPORT //", + "///////////////////", + "", + "// import all lodash functions to the main namespace, but isNaN not to cause conflicts", + "_.each(_.keys(_), k => window[k === 'isNaN' ? '_isNaN' : k] = _[k]);", + "", + "const", + "WORLD_WIDTH = 100,", + "WORLD_HEIGHT = 100,", + "PIXEL_SIZE = 4,", + "DIRTY_COLOR = '#000',", + "VIRGIN_COLOR = '#fff',", + "RUNS = 10000,", + "SPEED = 50,", + "", + "// up right down left", + "DIRECTIONS = [0, 1, 2, 3],", + "", + "displayWorld = (world) => each(world, (row, rowidx) => {", + " each(row, (cell, cellidx) => {", + " canvas.fillStyle = cell === 1 ? DIRTY_COLOR : VIRGIN_COLOR;", + " canvas.fillRect(rowidx * PIXEL_SIZE, cellidx * PIXEL_SIZE, PIXEL_SIZE, PIXEL_SIZE);", + " });", + "}),", + "", + "moveAnt = (world, ant) => {", + " world[ant.x][ant.y] = world[ant.x][ant.y] === 1 ? 0 : 1;", + " ant.dir = DIRECTIONS[(4 + ant.dir + (world[ant.x][ant.y] === 0 ? 1 : -1)) % 4];", + " switch (ant.dir) {", + " case DIRECTIONS[0]:", + " ant.y -= 1;", + " break;", + " case DIRECTIONS[1]:", + " ant.x -= 1;", + " break;", + " case DIRECTIONS[2]:", + " ant.y += 1;", + " break;", + " case DIRECTIONS[3]:", + " ant.x += 1;", + " break;", + " }", + "", + " return [world, ant];", + "},", + "", + "updateWorld = (world, ant, runs) => {", + " [world, ant] = moveAnt(world, ant);", + " displayWorld(world);", + "", + " if (runs > 0) setTimeout(partial(updateWorld, world, ant, --runs), SPEED);", + "},", + "", + "canvas = document.getElementById('c').getContext('2d');", + "", + "let", + "world = map(range(WORLD_HEIGHT), i => map(range(WORLD_WIDTH), partial(identity, 0))),", + "ant = {", + " x: WORLD_WIDTH / 2,", + " y: WORLD_HEIGHT / 2,", + " dir: DIRECTIONS[0]", + "};", + "", + "canvas.canvas.width = WORLD_WIDTH * PIXEL_SIZE;", + "canvas.canvas.height = WORLD_HEIGHT * PIXEL_SIZE;", + "", + "updateWorld(world, ant, RUNS);", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7eda", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n// create global canvas\nvar canvas = document.createElement('canvas');\ncanvas.id = 'globalCanvas';\ndocument.body.appendChild(canvas);\n\nfunction langtonant(antx, optx) {\n\t'use strict';\n\tvar x, y, i;\n\n\t// extend default opts\n\tvar opts = {\n\t\tgridsize: 100,\n\t\tpixlsize: 4,\n\t\tinterval: 4\n\t};\n\tfor (i in optx) {\n\t\topts[i] = optx[i];\n\t}\n\n\t// extend default ants\n\tvar ants = [{\n\t\tx: 50,\n\t\ty: 50,\n\t\td: 0\n\t}];\n\tfor (i in antx) {\n\t\tants[i] = antx[i];\n\t}\n\n\t// initialise grid\n\tvar grid = [];\n\tfor (x = 0; x < opts.gridsize; x ++) {\n\t\tgrid[x] = [];\n\t\tfor (y = 0; y < opts.gridsize; y ++) {\n\t\t\tgrid[x][y] = true;\n\t\t}\n\t}\n\n\t// initialise directions\n\tvar dirs = [\n\t\t{x: 1, y: 0},\n\t\t{x: 0, y: -1},\n\t\t{x: -1, y: 0},\n\t\t{x: 0, y: 1}\n\t];\n\n\t// initialise canvas\n\tvar canv = document.getElementById('globalCanvas');\n\tvar cont = canv.getContext('2d');\n\tcanv.width = opts.gridsize * opts.pixlsize;\n\tcanv.height = opts.gridsize * opts.pixlsize;\n\n\t// initialise pixels\n\tvar pixlblac = cont.createImageData(opts.pixlsize, opts.pixlsize);\n\tfor (i = 0; i < (opts.pixlsize * opts.pixlsize * 4); i += 4) {\n\t\tpixlblac.data[i + 3] = 255;\n\t}\n\tvar pixlwhit = cont.createImageData(opts.pixlsize, opts.pixlsize);\n\tfor (i = 0; i < (opts.pixlsize * opts.pixlsize * 4); i += 4) {\n\t\tpixlwhit.data[i + 3] = 0;\n\t}\n\n\t// run simulation\n\tfunction simulate() {\n\t\tvar sane = true;\n\n\t\t// iterate over ants\n\t\tfor (i = 0; i < ants.length; i ++) {\n\t\t\tvar n = ants[i];\n\n\t\t\t// invert, draw, turn\n\t\t\tif (grid[n.x][n.y]) {\n\t\t\t\tgrid[n.x][n.y] = false;\n\t\t\t\tcont.putImageData(pixlblac, n.x * opts.pixlsize, n.y * opts.pixlsize);\n\t\t\t\tn.d --;\n\t\t\t} else {\n\t\t\t\tgrid[n.x][n.y] = true;\n\t\t\t\tcont.putImageData(pixlwhit, n.x * opts.pixlsize, n.y * opts.pixlsize);\n\t\t\t\tn.d ++;\n\t\t\t}\n\n\t\t\t// modulus wraparound\n\t\t\tn.d += dirs.length;\n\t\t\tn.d %= dirs.length;\n\n\t\t\t// position + direction\n\t\t\tn.x += dirs[n.d].x;\n\t\t\tn.y += dirs[n.d].y;\n\n\t\t\t// sanity check\n\t\t\tsane = (n.x < 0 || n.x > opts.gridsize || n.y < 0 || n.y > opts.gridsize) ? false : sane;\n\t\t}\n\n\t\t// loop with interval\n\t\tif (sane) {\n\t\t\tsetTimeout(simulate, opts.interval);\n\t\t}\n\t}\n\n\tsimulate();\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Largest int from concatenated ints", + "type": "Waypoint", + "description": [ + "Task: ", + "

    Given a set of positive integers, write a function to order the integers in such a way that the concatenation of the numbers forms the largest possible integer and return this integer.

    Use the following two sets of integers as tests and show your program output here.

    ::::* {1, 34, 3, 98, 9, 76, 45, 4}

    ", + "

    ::::* {54, 546, 548, 60}

    ", + "Possible algorithms:", + "A solution could be found by trying all combinations and return the best. ", + "Another way to solve this is to note that in the best arrangement, for any two adjacent original integers X and Y, the concatenation X followed by Y will be numerically greater than or equal to the concatenation Y followed by '''X.", + "Yet another way to solve this is to pad the integers to the same size by repeating the digits then sort using these repeated integers as a sort key.See also:", + " Algorithms: What is the most efficient way to arrange the given numbers to form the biggest number?", + " Constructing the largest number possible by rearranging a list" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + " (function () {", + " 'use strict';", + "", + " // maxCombine :: [Int] -> Int", + " function maxCombine(xs) {", + " return parseInt(", + " xs.sort(", + " function (x, y) {", + " var a = x.toString(),", + " b = y.toString(),", + " ab = parseInt(a + b),", + " ba = parseInt(b + a);", + "", + " return ab > ba ? -1 : (ab < ba ? 1 : 0);", + " }", + " )", + " .join(''), 10", + " );", + " }", + "", + " return [", + " [1, 34, 3, 98, 9, 76, 45, 4],", + " [54, 546, 548, 60]", + " ].map(maxCombine);", + "", + " })();", + "", + "", + "{{Out}}", + "", + "
    [998764543431, 6054854654]
    ", + "", + "", + "", + "===ES6===", + "var maxCombine = (a) => +(a.sort((x, y) => +(\"\" + y + x) - +(\"\" + x + y)).join(''));", + "", + "// test & output", + "console.log([", + " [1, 34, 3, 98, 9, 76, 45, 4],", + " [54, 546, 548, 60]", + "].map(maxCombine));", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7edb", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + " (function () {\n 'use strict';\n\n // maxCombine :: [Int] -> Int\n function maxCombine(xs) {\n return parseInt(\n xs.sort(\n function (x, y) {\n var a = x.toString(),\n b = y.toString(),\n ab = parseInt(a + b),\n ba = parseInt(b + a);\n\n return ab > ba ? -1 : (ab < ba ? 1 : 0);\n }\n )\n .join(''), 10\n );\n }\n\n return [\n [1, 34, 3, 98, 9, 76, 45, 4],\n [54, 546, 548, 60]\n ].map(maxCombine);\n\n })();\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Last Friday of each month", + "type": "Waypoint", + "description": [ + "Task:", + "

    Write a program or a script that returns the date of the last Fridays of each month of a given year.

    The year may be given through any simple input method in your language (command line, std in, etc).

    ", + "

    Example of an expected output:

    ", + "
    ./last_fridays 2012",
    +        "2012-01-27",
    +        "2012-02-24",
    +        "2012-03-30",
    +        "2012-04-27",
    +        "2012-05-25",
    +        "2012-06-29",
    +        "2012-07-27",
    +        "2012-08-31",
    +        "2012-09-28",
    +        "2012-10-26",
    +        "2012-11-30",
    +        "2012-12-28",
    +        "
    ", + "Related tasks", + "Five weekends", + "Day of the week", + "Find the last Sunday of each month" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7edc", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Last letter-first letter", + "type": "Waypoint", + "description": [ + "

    A certain children's game involves starting with a word in a particular category. Each participant in turn says a word, but that word must begin with the final letter of the previous word. Once a word has been given, it cannot be repeated. If an opponent cannot give a word in the category, they fall out of the game.

    ", + "

    For example, with \"animals\" as the category,

    ", + "
    ",
    +        "Child 1: dog ",
    +        "Child 2: goldfish",
    +        "Child 1: hippopotamus",
    +        "Child 2: snake",
    +        "...",
    +        "
    ", + "Task:", + "

    Take the following selection of 70 English Pokemon names (extracted from Wikipedia's list of Pokemon) and generate the/a sequence with the highest possible number of Pokemon names where the subsequent name starts with the final letter of the preceding name.

    No Pokemon name is to be repeated.

    ",
    +        "audino bagon baltoy banette bidoof braviary bronzor carracosta charmeleon",
    +        "cresselia croagunk darmanitan deino emboar emolga exeggcute gabite",
    +        "girafarig gulpin haxorus heatmor heatran ivysaur jellicent jumpluff kangaskhan",
    +        "kricketune landorus ledyba loudred lumineon lunatone machamp magnezone mamoswine",
    +        "nosepass petilil pidgeotto pikachu pinsir poliwrath poochyena porygon2",
    +        "porygonz registeel relicanth remoraid rufflet sableye scolipede scrafty seaking",
    +        "sealeo silcoon simisear snivy snorlax spoink starly tirtouga trapinch treecko",
    +        "tyrogue vigoroth vulpix wailord wartortle whismur wingull yamask",
    +        "
    ", + "

    Extra brownie points for dealing with the full list of 646 names.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7edd", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Leap year", + "type": "Waypoint", + "description": [ + "

    Determine whether a given year is a leap year in the Gregorian calendar.

    See Also

    ", + "Leap year (wiki)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "var isLeapYear = function (year) { return (year % 100 === 0) ? (year % 400 === 0) : (year % 4 === 0); };", + "Or, by setting the day to the 29th and checking if the day remains", + "// Month values start at 0, so 1 is for February", + "var isLeapYear = function (year) { return new Date(year, 1, 29).getDate() === 29; };", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ede", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var isLeapYear = function (year) { return (year % 100 === 0) ? (year % 400 === 0) : (year % 4 === 0); };\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Least common multiple", + "type": "Waypoint", + "description": [ + "Task:", + "

    Compute the least common multiple of two integers.

    Given m and n, the least common multiple is the smallest positive integer that has both m and n as factors.

    ", + "Example:", + "

    The least common multiple of 12 and 18 is 36, because 12 is a factor (12 × 3 = 36), and 18 is a factor (18 × 2 = 36), and there is no positive integer less than 36 that has both factors. As a special case, if either m or n is zero, then the least common multiple is zero.

    One way to calculate the least common multiple is to iterate all the multiples of m, until you find one that is also a multiple of n.

    If you already have gcd for greatest common divisor, then this formula calculates lcm.

    ", + "

    ::: $\\operatorname{lcm}(m, n) = \\frac{|m \\times n|}{\\operatorname{gcd}(m, n)}$

    ", + "

    One can also find lcm by merging the prime decompositions of both m and n.

    ", + "References:", + " MathWorld.", + " Wikipedia." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "Computing the least common multiple of an integer array, using the associative law:", + "", + "\\operatorname{lcm}(a,b,c)=\\operatorname{lcm}(\\operatorname{lcm}(a,b),c),", + "", + "\\operatorname{lcm}(a_1,a_2,\\ldots,a_n) = \\operatorname{lcm}(\\operatorname{lcm}(a_1,a_2,\\ldots,a_{n-1}),a_n).", + "", + "function LCM(A) // A is an integer array (e.g. [-50,25,-45,-18,90,447])", + "{ ", + " var n = A.length, a = Math.abs(A[0]);", + " for (var i = 1; i < n; i++)", + " { var b = Math.abs(A[i]), c = a;", + " while (a && b){ a > b ? a %= b : b %= a; } ", + " a = Math.abs(c*A[i])/(a+b);", + " }", + " return a;", + "}", + "", + "/* For example:", + " LCM([-50,25,-45,-18,90,447]) -> 67050", + "*/", + "", + "", + "===ES6===", + "{{Trans|Haskell}}", + "(() => {", + " 'use strict';", + "", + " // gcd :: Integral a => a -> a -> a", + " let gcd = (x, y) => {", + " let _gcd = (a, b) => (b === 0 ? a : _gcd(b, a % b)),", + " abs = Math.abs;", + " return _gcd(abs(x), abs(y));", + " }", + "", + " // lcm :: Integral a => a -> a -> a", + " let lcm = (x, y) =>", + " x === 0 || y === 0 ? 0 : Math.abs(Math.floor(x / gcd(x, y)) * y);", + "", + " // TEST", + " return lcm(12, 18);", + "", + "})();", + "", + "{{Out}}", + "
    36
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7edf", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function LCM(A) // A is an integer array (e.g. [-50,25,-45,-18,90,447])\n{ \n var n = A.length, a = Math.abs(A[0]);\n for (var i = 1; i < n; i++)\n { var b = Math.abs(A[i]), c = a;\n while (a && b){ a > b ? a %= b : b %= a; } \n a = Math.abs(c*A[i])/(a+b);\n }\n return a;\n}\n\n/* For example:\n LCM([-50,25,-45,-18,90,447]) -> 67050\n*/\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Left factorials", + "type": "Waypoint", + "description": [ + "

    Left factorials, !n, may refer to either subfactorials or to factorial sums;

    ", + "the same notation can be confusingly seen used for the two different definitions.

    Sometimes, subfactorials (also known as derangements) may use any of the notations:

    ", + "

    ::::::* !n`

    ", + "

    ::::::* !n

    ", + "

    ::::::*

    (It may not be visually obvious, but the last example uses an upside-down exclamation mark.)

    ", + "This Rosetta Code task will be using this formula for left factorial:", + "

    ", + "

    :: $ !n = \\sum_{k=0}^{n-1} k! $

    ", + "
    ", + "

    where

    ", + "

    ", + "

    :: $!0 = 0$

    ", + "
    ", + "Task", + "

    Display the left factorials for:

    ", + "zero through ten (inclusive)", + "20 through 110 (inclusive) by tens", + "

    Display the length (in decimal digits) of the left factorials for:

    ", + "1,000, 2,000 through 10,000 (inclusive), by thousands.Also see", + " The OEIS entry: A003422 left factorials", + " The MathWorld entry: left factorial", + " The MathWorld entry: factorial sums", + " The MathWorld entry: subfactorialRelated task:", + " permutations/derangements (subfactorials)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ee0", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Letter frequency", + "type": "Waypoint", + "description": [ + "Task:", + "

    Open a text file and count the occurrences of each letter.

    Some of these programs count all characters (including punctuation),

    ", + "

    but some only count letters A to Z.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "JavaScript is no longer used only in environments which are carefully isolated from file systems, but JavaScript standards still do not specify standard file-system functions. ", + "Leaving aside the particular and variable details of how files will be opened and read in environments like Node.js and OS X JavaScript for Automation etc., ", + "we can still use core JavasScript (ES5 in the example below), to count the characters in a text once it has been read from a file system.", + "", + "(function(txt) {", + "", + " var cs = txt.split(''),", + " i = cs.length,", + " dct = {},", + " c = '',", + " keys;", + " ", + " while (i--) {", + " c = cs[i];", + " dct[c] = (dct[c] || 0) + 1;", + " }", + " ", + " keys = Object.keys(dct);", + " keys.sort();", + " return keys.map(function (c) { return [c, dct[c]]; });", + "", + "})(\"Not all that Mrs. Bennet, however, with the assistance of her five\\", + "daughters, could ask on the subject, was sufficient to draw from her\\", + "husband any satisfactory description of Mr. Bingley. They attacked him\\", + "in various ways--with barefaced questions, ingenious suppositions, and\\", + "distant surmises; but he eluded the skill of them all, and they were at\\", + "last obliged to accept the second-hand intelligence of their neighbour,\\", + "Lady Lucas. Her report was highly favourable. Sir William had been\\", + "delighted with him. He was quite young, wonderfully handsome, extremely\\", + "agreeable, and, to crown the whole, he meant to be at the next assembly\\", + "with a large party. Nothing could be more delightful! To be fond of\\", + "dancing was a certain step towards falling in love; and very lively\\", + "hopes of Mr. Bingley's heart were entertained.\"); ", + "", + "{{Out}}", + "", + "[[\" \", 121], [\"!\", 1], [\"'\", 1], [\",\", 13], [\"-\", 3], [\".\", 9], [\";\", 2], ", + "[\"B\", 3], [\"H\", 2], [\"L\", 2], [\"M\", 3], [\"N\", 2], [\"S\", 1], [\"T\", 2], [\"W\", 1], ", + "[\"a\", 53], [\"b\", 13], [\"c\", 17], [\"d\", 29], [\"e\", 82], [\"f\", 17], [\"g\", 16], [\"h\", 36],", + "[\"i\", 44], [\"j\", 1], [\"k\", 3], [\"l\", 34], [\"m\", 11], [\"n\", 41], [\"o\", 40], [\"p\", 8], ", + "[\"q\", 2], [\"r\", 35], [\"s\", 39], [\"t\", 55], [\"u\", 20], [\"v\", 7], [\"w\", 17], [\"x\", 2], [\"y\", 16]]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ee1", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function(txt) {\n\n var cs = txt.split(''),\n i = cs.length,\n dct = {},\n c = '',\n keys;\n \n while (i--) {\n c = cs[i];\n dct[c] = (dct[c] || 0) + 1;\n }\n \n keys = Object.keys(dct);\n keys.sort();\n return keys.map(function (c) { return [c, dct[c]]; });\n\n})(\"Not all that Mrs. Bennet, however, with the assistance of her five\\\ndaughters, could ask on the subject, was sufficient to draw from her\\\nhusband any satisfactory description of Mr. Bingley. They attacked him\\\nin various ways--with barefaced questions, ingenious suppositions, and\\\ndistant surmises; but he eluded the skill of them all, and they were at\\\nlast obliged to accept the second-hand intelligence of their neighbour,\\\nLady Lucas. Her report was highly favourable. Sir William had been\\\ndelighted with him. He was quite young, wonderfully handsome, extremely\\\nagreeable, and, to crown the whole, he meant to be at the next assembly\\\nwith a large party. Nothing could be more delightful! To be fond of\\\ndancing was a certain step towards falling in love; and very lively\\\nhopes of Mr. Bingley's heart were entertained.\"); \n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Levenshtein distance", + "type": "Waypoint", + "description": [ + "

    In information theory and computer science, the Levenshtein distance is a metric for measuring the amount of difference between two sequences (i.e. an edit distance). The Levenshtein distance between two strings is defined as the minimum number of edits needed to transform one string into the other, with the allowable edit operations being insertion, deletion, or substitution of a single character.

    ", + "Example:", + "

    The Levenshtein distance between \"kitten\" and \"sitting\" is 3, since the following three edits change one into the other, and there isn't a way to do it with fewer than three edits:

    ", + "

    :# kitten sitten (substitution of 'k' with 's')

    ", + "

    :# sitten sittin (substitution of 'e' with 'i')

    ", + "

    :# sittin sitting (insert 'g' at the end).

    ", + "

    ''The Levenshtein distance between \"rosettacode\", \"raisethysword\" is 8.

    The distance between two strings is same as that when both strings are reversed.

    ", + "Task;", + "

    Implements a Levenshtein distance function, or uses a library function, to show the Levenshtein distance between \"kitten\" and \"sitting\".

    ", + "Related task:", + " Longest common subsequence" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "Iterative:", + "function levenshtein(a, b) {", + " var t = [], u, i, j, m = a.length, n = b.length;", + " if (!m) { return n; }", + " if (!n) { return m; }", + " for (j = 0; j <= n; j++) { t[j] = j; }", + " for (i = 1; i <= m; i++) {", + " for (u = [i], j = 1; j <= n; j++) {", + " u[j] = a[i - 1] === b[j - 1] ? t[j - 1] : Math.min(t[j - 1], t[j], u[j - 1]) + 1;", + " } t = u;", + " } return u[n];", + "}", + "", + "// tests", + "[ ['', '', 0],", + " ['yo', '', 2],", + " ['', 'yo', 2],", + " ['yo', 'yo', 0],", + " ['tier', 'tor', 2],", + " ['saturday', 'sunday', 3],", + " ['mist', 'dist', 1],", + " ['tier', 'tor', 2],", + " ['kitten', 'sitting', 3],", + " ['stop', 'tops', 2],", + " ['rosettacode', 'raisethysword', 8],", + " ['mississippi', 'swiss miss', 8]", + "].forEach(function(v) {", + " var a = v[0], b = v[1], t = v[2], d = levenshtein(a, b);", + " if (d !== t) {", + " console.log('levenstein(\"' + a + '\",\"' + b + '\") was ' + d + ' should be ' + t);", + " }", + "});", + "", + "===ES6===", + "{{Trans|Haskell}}", + "", + "By composition of generic functions:", + "(() => {", + " 'use strict';", + "", + " // levenshtein :: String -> String -> Int", + " const levenshtein = (sa, sb) => {", + " const [s1, s2] = [sa.split(''), sb.split('')];", + "", + " return last(s2.reduce((ns, c) => {", + " const [n, ns1] = uncons(ns);", + "", + " return scanl(", + " (z, [c1, x, y]) =>", + " minimum(", + " [y + 1, z + 1, x + fromEnum(c1 != c)]", + " ),", + " n + 1,", + " zip3(s1, ns, ns1)", + " );", + " }, range(0, s1.length)));", + " };", + "", + "", + " /*********************************************************************/", + " // GENERIC FUNCTIONS", + "", + " // minimum :: [a] -> a", + " const minimum = xs =>", + " xs.reduce((a, x) => (x < a || a === undefined ? x : a), undefined);", + "", + " // fromEnum :: Enum a => a -> Int", + " const fromEnum = x => {", + " const type = typeof x;", + " return type === 'boolean' ? (", + " x ? 1 : 0", + " ) : (type === 'string' ? x.charCodeAt(0) : undefined);", + " };", + "", + " // uncons :: [a] -> Maybe (a, [a])", + " const uncons = xs => xs.length ? [xs[0], xs.slice(1)] : undefined;", + "", + " // scanl :: (b -> a -> b) -> b -> [a] -> [b]", + " const scanl = (f, a, xs) => {", + " for (var lst = [a], lng = xs.length, i = 0; i < lng; i++) {", + " a = f(a, xs[i], i, xs), lst.push(a);", + " }", + " return lst;", + " };", + "", + " // zip3 :: [a] -> [b] -> [c] -> [(a,b,c)]", + " const zip3 = (xs, ys, zs) =>", + " xs.slice(0, Math.min(xs.length, ys.length, zs.length))", + " .map((x, i) => [x, ys[i], zs[i]]);", + "", + " // last :: [a] -> a", + " const last = xs => xs.length ? xs.slice(-1) : undefined;", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " /*********************************************************************/", + " // TEST", + " return [", + " [\"kitten\", \"sitting\"],", + " [\"sitting\", \"kitten\"],", + " [\"rosettacode\", \"raisethysword\"],", + " [\"raisethysword\", \"rosettacode\"]", + " ].map(pair => levenshtein.apply(null, pair));", + "", + " // -> [3, 3, 8, 8]", + "})();", + "", + "{{Out}}", + "[3, 3, 8, 8]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ee2", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function levenshtein(a, b) {\n var t = [], u, i, j, m = a.length, n = b.length;\n if (!m) { return n; }\n if (!n) { return m; }\n for (j = 0; j <= n; j++) { t[j] = j; }\n for (i = 1; i <= m; i++) {\n for (u = [i], j = 1; j <= n; j++) {\n u[j] = a[i - 1] === b[j - 1] ? t[j - 1] : Math.min(t[j - 1], t[j], u[j - 1]) + 1;\n } t = u;\n } return u[n];\n}\n\n// tests\n[ ['', '', 0],\n ['yo', '', 2],\n ['', 'yo', 2],\n ['yo', 'yo', 0],\n ['tier', 'tor', 2],\n ['saturday', 'sunday', 3],\n ['mist', 'dist', 1],\n ['tier', 'tor', 2],\n ['kitten', 'sitting', 3],\n ['stop', 'tops', 2],\n ['rosettacode', 'raisethysword', 8],\n ['mississippi', 'swiss miss', 8]\n].forEach(function(v) {\n var a = v[0], b = v[1], t = v[2], d = levenshtein(a, b);\n if (d !== t) {\n console.log('levenstein(\"' + a + '\",\"' + b + '\") was ' + d + ' should be ' + t);\n }\n});\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Linear congruential generator", + "type": "Waypoint", + "description": [ + "

    The linear congruential generator is a very simple example of a random number generator. All linear congruential generators use this formula:

    $r_{n + 1} = a \\times r_n + c \\pmod m$", + "

    Where:

    $r_0$ is a seed.", + "$r_1$, $r_2$, $r_3$, ..., are the random numbers.", + "$a$, $c$, $m$ are constants.", + "

    If one chooses the values of $a$, $c$ and $m$ with care, then the generator produces a uniform distribution of integers from $0$ to $m - 1$.

    LCG numbers have poor quality. $r_n$ and $r_{n + 1}$ are not independent, as true random numbers would be. Anyone who knows $r_n$ can predict $r_{n + 1}$, therefore LCG is not cryptographically secure. The LCG is still good enough for simple tasks like Miller-Rabin primality test, or FreeCell deals. Among the benefits of the LCG, one can easily reproduce a sequence of numbers, from the same $r_0$. One can also reproduce such sequence with a different programming language, because the formula is so simple.

    The task is to replicate two historic random number generators. One is the rand() function from BSD libc, and the other is the rand() function from the Microsoft C Runtime (MSCVRT.DLL). Each replica must yield the same sequence of integers as the original generator, when starting from the same seed.

    In these formulas, the seed becomes $state_0$. The random sequence is $rand_1$, $rand_2$ and so on.

    BSD formula:

    $state_{n + 1} = 1103515245 \\times state_n + 12345 \\pmod{2^{31}}$", + "$rand_n = state_n$", + "$rand_n$ is in range 0 to 2147483647.", + "

    Microsoft formula:

    $state_{n + 1} = 214013 \\times state_n + 2531011 \\pmod{2^{31}}$", + "$rand_n = state_n \\div 2^{16}$", + "$rand_n$ is in range 0 to 32767.", + "

    The BSD formula was so awful that FreeBSD switched to a different formula. More info is at Random number generator (included)#C.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ee3", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "List comprehensions", + "type": "Waypoint", + "description": [ + "

    A list comprehension is a special syntax in some programming languages to describe lists. It is similar to the way mathematicians describe sets, with a set comprehension, hence the name.

    Some attributes of a list comprehension are:

    ", + "They should be distinct from (nested) for loops and the use of map and filter functions within the syntax of the language.", + "They should return either a list or an iterator (something that returns successive members of a collection, in order).", + "The syntax has parts corresponding to that of set-builder notation. Task:", + "

    Write a list comprehension that builds the list of all Pythagorean triples with elements between 1 and n.

    If the language has multiple ways for expressing such a construct (for example, direct list comprehensions and generators), write one example for each.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "ES5 does not provide built-in notation for list comprehensions. The list monad pattern which underlies list comprehension notation can, however, be used in any language which supports the use of higher order functions. The following shows how we can achieve the same result by directly using a list monad in ES5, without the abbreviating convenience of any specific syntactic sugar. ", + "", + "// USING A LIST MONAD DIRECTLY, WITHOUT SPECIAL SYNTAX FOR LIST COMPREHENSIONS", + "", + "(function (n) {", + "", + " return mb(r(1, n), function (x) { // x <- [1..n]", + " return mb(r(1 + x, n), function (y) { // y <- [1+x..n]", + " return mb(r(1 + y, n), function (z) { // z <- [1+y..n]", + " ", + " return x * x + y * y === z * z ? [[x, y, z]] : [];", + " ", + " })})});", + "", + "", + " // LIBRARY FUNCTIONS", + " ", + " // Monadic bind for lists", + " function mb(xs, f) {", + " return [].concat.apply([], xs.map(f));", + " }", + " ", + " // Monadic return for lists is simply lambda x -> [x]", + " // as in [[x, y, z]] : [] above", + "", + " // Integer range [m..n]", + " function r(m, n) {", + " return Array.apply(null, Array(n - m + 1))", + " .map(function (n, x) {", + " return m + x;", + " });", + " }", + "", + "})(100);", + "", + "Output:", + "", + "
    [[3, 4, 5], [5, 12, 13], [6, 8, 10], [7, 24, 25], [8, 15, 17], [9, 12, 15], [9, 40, 41], [10, 24, 26], [11, 60, 61], [12, 16, 20], [12, 35, 37], [13, 84, 85], [14, 48, 50], [15, 20, 25], [15, 36, 39], [16, 30, 34], [16, 63, 65], [18, 24, 30], [18, 80, 82], [20, 21, 29], [20, 48, 52], [21, 28, 35], [21, 72, 75], [24, 32, 40], [24, 45, 51], [24, 70, 74], [25, 60, 65], [27, 36, 45], [28, 45, 53], [28, 96, 100], [30, 40, 50], [30, 72, 78], [32, 60, 68], [33, 44, 55], [33, 56, 65], [35, 84, 91], [36, 48, 60], [36, 77, 85], [39, 52, 65], [39, 80, 89], [40, 42, 58], [40, 75, 85], [42, 56, 70], [45, 60, 75], [48, 55, 73], [48, 64, 80], [51, 68, 85], [54, 72, 90], [57, 76, 95], [60, 63, 87], [60, 80, 100], [65, 72, 97]]
    ", + "", + "===ES6===", + "{{trans|Python}}", + "", + "{{works with|JavaScript|1.7+ (Firefox 2+)}} {{works with|SpiderMonkey|1.7}}", + "", + "See [https://developer.mozilla.org/en/New_in_JavaScript_1.7#Array_comprehensions here] for more details", + "", + "function range(begin, end) {", + " for (let i = begin; i < end; ++i)", + " yield i;", + "}", + "", + "function triples(n) {", + " return [", + " [x, y, z]", + " for each(x in range(1, n + 1))", + " for each(y in range(x, n + 1))", + " for each(z in range(y, n + 1))", + " if (x * x + y * y == z * z)", + " ]", + "}", + "", + "for each(var triple in triples(20))", + "print(triple);", + "", + "outputs:", + "
    3,4,5",
    +        "5,12,13",
    +        "6,8,10",
    +        "8,15,17",
    +        "9,12,15",
    +        "12,16,20
    ", + "", + "", + "List comprehension notation was not, in the end, included in the final ES6 standard, and the code above will not run in fully ES6-compliant browsers or interpreters, but we can still go straight to the underlying monadic logic of list comprehensions and obtain: ", + "", + "[ (x, y, z)", + "| x <- [1 .. n], y <- [x .. n], z <- [y .. n], x ^ 2 + y ^ 2 == z ^ 2 ]", + "", + "by using concatMap (the monadic bind function for lists), and x => [x] (monadic pure/return for lists):", + "", + "(n => {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " const concatMap = (f, xs) => [].concat.apply([], xs.map(f));", + "", + " // enumFromTo :: Int -> Int -> [Int]", + " const enumFromTo = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + "", + " // EXAMPLE ----------------------------------------------------------------", + "", + " // [(x, y, z) | x <- [1..n], y <- [x..n], z <- [y..n], x ^ 2 + y ^ 2 == z ^ 2]", + "", + " return concatMap(x =>", + " concatMap(y =>", + " concatMap(z =>", + "", + " x * x + y * y === z * z ? [", + " [x, y, z]", + " ] : [],", + "", + " enumFromTo(y, n)),", + " enumFromTo(x, n)),", + " enumFromTo(1, n));", + "})(20);", + "{{Out}}", + "[[3, 4, 5], [5, 12, 13], [6, 8, 10], [8, 15, 17], [9, 12, 15], [12, 16, 20]]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ee4", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// USING A LIST MONAD DIRECTLY, WITHOUT SPECIAL SYNTAX FOR LIST COMPREHENSIONS\n\n(function (n) {\n\n return mb(r(1, n), function (x) { // x <- [1..n]\n return mb(r(1 + x, n), function (y) { // y <- [1+x..n]\n return mb(r(1 + y, n), function (z) { // z <- [1+y..n]\n \n return x * x + y * y === z * z ? [[x, y, z]] : [];\n \n })})});\n\n\n // LIBRARY FUNCTIONS\n \n // Monadic bind for lists\n function mb(xs, f) {\n return [].concat.apply([], xs.map(f));\n }\n \n // Monadic return for lists is simply lambda x -> [x]\n // as in [[x, y, z]] : [] above\n\n // Integer range [m..n]\n function r(m, n) {\n return Array.apply(null, Array(n - m + 1))\n .map(function (n, x) {\n return m + x;\n });\n }\n\n})(100);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Longest common subsequence", + "type": "Waypoint", + "description": [ + "

    The longest common subsequence (or LCS) of groups A and B is the longest group of elements from A and B that are common between the two groups and in the same order in each group. For example, the sequences \"1234\" and \"1224533324\" have an LCS of \"1234\":

    ", + "

    1234

    ", + "

    1224533324

    ", + "

    For a string example, consider the sequences \"thisisatest\" and \"testing123testing\". An LCS would be \"tsitest\":

    ", + "

    thisisatest

    ", + "

    testing123testing

    In this puzzle, your code only needs to deal with strings. Write a function which returns an LCS of two strings (case-sensitive). You don't need to show multiple LCS's.

    For more information on this problem please see Wikipedia.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===Recursion===", + "{{trans|Java}}", + "This is more or less a translation of the recursive Java version above.", + "function lcs(a, b) {", + " var aSub = a.substr(0, a.length - 1);", + " var bSub = b.substr(0, b.length - 1);", + " ", + " if (a.length === 0 || b.length === 0) {", + " return '';", + " } else if (a.charAt(a.length - 1) === b.charAt(b.length - 1)) {", + " return lcs(aSub, bSub) + a.charAt(a.length - 1);", + " } else {", + " var x = lcs(a, bSub);", + " var y = lcs(aSub, b);", + " return (x.length > y.length) ? x : y;", + " }", + "}", + "", + "ES6 recursive implementation", + "", + "", + "var longest = (xs, ys) => (xs.length > ys.length) ? xs : ys;", + "", + "var lcs = (xx, yy) => {", + " if (!xx.length || !yy.length) { return ''; }", + "", + " var x = xx[0],", + " y = yy[0];", + " xs = xx.slice(1);", + " ys = yy.slice(1);", + "", + " return (x === y) ? lcs(xs, ys) :", + " longest(lcs(xx, ys), lcs(xs, yy));", + "};", + "", + "===Dynamic Programming===", + "This version runs in O(mn) time and consumes O(mn) space.", + "Factoring out loop edge cases could get a small constant time improvement, and it's fairly trivial to edit the final loop to produce a full diff in addition to the lcs.", + "function lcs(x,y){", + "\tvar s,i,j,m,n,", + "\t\tlcs=[],row=[],c=[],", + "\t\tleft,diag,latch;", + "\t//make sure shorter string is the column string", + "\tif(mrow[j]){row[j] = left;}", + "\t\t\t}", + "\t\t}", + "\t}", + "\ti--,j--;", + "\t//row[j] now contains the length of the lcs", + "\t//recover the lcs from the table", + "\twhile(i>-1&&j>-1){", + "\t\tswitch(c[i][j]){", + "\t\t\tdefault: j--;", + "\t\t\t\tlcs.unshift(x[i]);", + "\t\t\tcase (i&&c[i-1][j]): i--;", + "\t\t\t\tcontinue;", + "\t\t\tcase (j&&c[i][j-1]): j--;", + "\t\t}", + "\t}", + "\treturn lcs.join('');", + "}", + "", + "'''BUG note: In line 6, m and n are not yet initialized, and so x and y are never swapped.'''", + "'''Swapping is useless here, and becomes wrong when extending the algorithm to produce a diff.'''", + "", + "The final loop can be modified to concatenate maximal common substrings rather than individual characters:", + "\tvar t=i;", + "\twhile(i>-1&&j>-1){", + "\t\tswitch(c[i][j]){", + "\t\t\tdefault:i--,j--;", + "\t\t\t\tcontinue;", + "\t\t\tcase (i&&c[i-1][j]):", + "\t\t\t\tif(t!==i){lcs.unshift(x.substring(i+1,t+1));}", + "\t\t\t\tt=--i;", + "\t\t\t\tcontinue;", + "\t\t\tcase (j&&c[i][j-1]): j--;", + "\t\t\t\tif(t!==i){lcs.unshift(x.substring(i+1,t+1));}", + "\t\t\t\tt=i;", + "\t\t}", + "\t}", + "\tif(t!==i){lcs.unshift(x.substring(i+1,t+1));}", + "", + "===Greedy Algorithm===", + "This is an heuristic algorithm that won't always return the correct answer, but is significantly faster and less memory intensive than the dynamic programming version, in exchange for giving up the ability to re-use the table to find alternate solutions and greater complexity in generating diffs. Note that this implementation uses a binary buffer for additional efficiency gains, but it's simple to transform to use string or array concatenation;", + "function lcs_greedy(x,y){", + " var p1, i, idx,", + " symbols = {},", + " r = 0,", + " p = 0,", + " l = 0,", + " m = x.length,", + " n = y.length,", + " s = new Buffer((m < n) ? n : m);", + "", + " p1 = popsym(0);", + "", + " for (i = 0; i < m; i++) {", + " p = (r === p) ? p1 : popsym(i);", + " p1 = popsym(i + 1);", + " if (p > p1) {", + " i += 1;", + " idx = p1;", + " } else {", + " idx = p;", + " }", + "", + " if (idx === n) {", + " p = popsym(i);", + " } else {", + " r = idx;", + " s[l] = x.charCodeAt(i);", + " l += 1;", + " }", + " }", + " return s.toString('utf8', 0, l);", + "\t", + " function popsym(index) {", + " var s = x[index],", + " pos = symbols[s] + 1;", + "", + " pos = y.indexOf(s, ((pos > r) ? pos : r));", + " if (pos === -1) { pos = n; }", + " symbols[s] = pos;", + " return pos;", + " }", + "}", + "", + "Note that it won't return the correct answer for all inputs. For example: lcs_greedy('bcaaaade', 'deaaaabc'); // 'bc' instead of 'aaaa'", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ee9", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function lcs(a, b) {\n var aSub = a.substr(0, a.length - 1);\n var bSub = b.substr(0, b.length - 1);\n \n if (a.length === 0 || b.length === 0) {\n return '';\n } else if (a.charAt(a.length - 1) === b.charAt(b.length - 1)) {\n return lcs(aSub, bSub) + a.charAt(a.length - 1);\n } else {\n var x = lcs(a, bSub);\n var y = lcs(aSub, b);\n return (x.length > y.length) ? x : y;\n }\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Longest increasing subsequence", + "type": "Waypoint", + "description": [ + "

    Calculate and show here a longest increasing subsequence of the list:

    ", + "

    $\\{3, 2, 6, 4, 5, 1\\}$

    ", + "

    And of the list:

    ", + "

    $\\{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15\\}$

    Note that a list may have more than one subsequence that is of the maximum length.

    Ref:", + "Dynamic Programming #1: Longest Increasing Subsequence on Youtube", + "An efficient solution can be based on Patience sorting." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{libheader|Lo-Dash underscore library}}", + "", + "", + "", + "var _ = require('underscore');", + "function findIndex(input){", + "\tvar len = input.length;", + "\tvar maxSeqEndingHere = _.range(len).map(function(){return 1;});", + "\tfor(var i=0; i=0;j--)", + "\t\t\tif(input[i] > input[j] && maxSeqEndingHere[j] >= maxSeqEndingHere[i])", + "\t\t\t\tmaxSeqEndingHere[i] = maxSeqEndingHere[j]+1;", + "\treturn maxSeqEndingHere;", + "}", + "", + "function findSequence(input, result){", + "\tvar maxValue = Math.max.apply(null, result);", + "\tvar maxIndex = result.indexOf(Math.max.apply(Math, result));", + "\tvar output = [];", + "\toutput.push(input[maxIndex]);", + "\tfor(var i = maxIndex ; i >= 0; i--){", + "\t\tif(maxValue==0)break;", + "\t\tif(input[maxIndex] > input[i] && result[i] == maxValue-1){", + "\t\t\toutput.push(input[i]);", + "\t\t\tmaxValue--;", + "\t\t}", + "\t}", + "\toutput.reverse();", + "\treturn output;", + "}", + "", + "", + "var x = [0, 7, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15];", + "var y = [3, 2, 6, 4, 5, 1];", + "", + "var result = findIndex(x);", + "var final = findSequence(x, result);", + "console.log(final);", + "", + "var result1 = findIndex(y);", + "var final1 = findSequence(y, result1);", + "console.log(final1);", + "", + "", + "{{out}}", + "
    ",
    +        "[ 0, 2, 6, 9, 11, 15 ]",
    +        "[ 2, 4, 5 ]",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7eea", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n\nvar _ = require('underscore');\nfunction findIndex(input){\n\tvar len = input.length;\n\tvar maxSeqEndingHere = _.range(len).map(function(){return 1;});\n\tfor(var i=0; i=0;j--)\n\t\t\tif(input[i] > input[j] && maxSeqEndingHere[j] >= maxSeqEndingHere[i])\n\t\t\t\tmaxSeqEndingHere[i] = maxSeqEndingHere[j]+1;\n\treturn maxSeqEndingHere;\n}\n\nfunction findSequence(input, result){\n\tvar maxValue = Math.max.apply(null, result);\n\tvar maxIndex = result.indexOf(Math.max.apply(Math, result));\n\tvar output = [];\n\toutput.push(input[maxIndex]);\n\tfor(var i = maxIndex ; i >= 0; i--){\n\t\tif(maxValue==0)break;\n\t\tif(input[maxIndex] > input[i] && result[i] == maxValue-1){\n\t\t\toutput.push(input[i]);\n\t\t\tmaxValue--;\n\t\t}\n\t}\n\toutput.reverse();\n\treturn output;\n}\n\n\nvar x = [0, 7, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15];\nvar y = [3, 2, 6, 4, 5, 1];\n\nvar result = findIndex(x);\nvar final = findSequence(x, result);\nconsole.log(final);\n\nvar result1 = findIndex(y);\nvar final1 = findSequence(y, result1);\nconsole.log(final1);\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Longest string challenge", + "type": "Waypoint", + "description": [ + "Background:", + "

    This \"longest string challenge\" is inspired by a problem that used to be given to students learning Icon. Students were expected to try to solve the problem in Icon and another language with which the student was already familiar. The basic problem is quite simple; the challenge and fun part came through the introduction of restrictions. Experience has shown that the original restrictions required some adjustment to bring out the intent of the challenge and make it suitable for Rosetta Code.

    The original programming challenge and some solutions can be found at Unicon Programming TWiki / Longest Strings Puzzle. (See notes on the talk page if you have trouble with the site).

    ", + "Basic problem statement", + "

    Write a program that reads lines from standard input and, upon end of file, writes the longest line to standard output.

    ", + "

    If there are ties for the longest line, the program writes out all the lines that tie.

    ", + "

    If there is no input, the program should produce no output.

    ", + "Task ", + "

    Implement a solution to the basic problem that adheres to the spirit of the restrictions (see below).

    Describe how you circumvented or got around these 'restrictions' and met the 'spirit' of the challenge. Your supporting description may need to describe any challenges to interpreting the restrictions and how you made this interpretation. You should state any assumptions, warnings, or other relevant points. The central idea here is to make the task a bit more interesting by thinking outside of the box and perhaps by showing off the capabilities of your language in a creative way. Because there is potential for considerable variation between solutions, the description is key to helping others see what you've done.

    This task is likely to encourage a variety of different types of solutions. They should be substantially different approaches.

    Given the input:

    ", + "
    ",
    +        "a",
    +        "bb",
    +        "ccc",
    +        "ddd",
    +        "ee",
    +        "f",
    +        "ggg",
    +        "

    the output should be (possibly rearranged):

    ", + "
    ",
    +        "ccc",
    +        "ddd",
    +        "ggg",
    +        "
    ", + "Original list of restrictionsNo comparison operators may be used.", + "No arithmetic operations, such as addition and subtraction, may be used.", + "The only datatypes you may use are integer and string. In particular, you may not use lists.", + "Do not re-read the input file. Avoid using files as a replacement for lists (this restriction became apparent in the discussion).Intent of restrictions:", + "

    Because of the variety of languages on Rosetta Code and the wide variety of concepts used in them, there needs to be a bit of clarification and guidance here to get to the spirit of the challenge and the intent of the restrictions.

    The basic problem can be solved very conventionally, but that's boring and pedestrian. The original intent here wasn't to unduly frustrate people with interpreting the restrictions, it was to get people to think outside of their particular box and have a bit of fun doing it.

    The guiding principle here should be to be creative in demonstrating some of the capabilities of the programming language being used. If you need to bend the restrictions a bit, explain why and try to follow the intent. If you think you've implemented a 'cheat', call out the fragment yourself and ask readers if they can spot why. If you absolutely can't get around one of the restrictions, explain why in your description.

    Now having said that, the restrictions require some elaboration.

    In general, the restrictions are meant to avoid the explicit use of these features.", + "\"No comparison operators may be used\" - At some level there must be some test that allows the solution to get at the length and determine if one string is longer. Comparison operators, in particular any less/greater comparison should be avoided. Representing the length of any string as a number should also be avoided. Various approaches allow for detecting the end of a string. Some of these involve implicitly using equal/not-equal; however, explicitly using equal/not-equal should be acceptable.", + "\"No arithmetic operations\" - Again, at some level something may have to advance through the string. Often there are ways a language can do this implicitly advance a cursor or pointer without explicitly using a +, - , ++, --, add, subtract, etc.", + "The datatype restrictions are amongst the most difficult to reinterpret. In the language of the original challenge strings are atomic datatypes and structured datatypes like lists are quite distinct and have many different operations that apply to them. This becomes a bit fuzzier with languages with a different programming paradigm. The intent would be to avoid using an easy structure to accumulate the longest strings and spit them out. There will be some natural reinterpretation here.

    To make this a bit more concrete, here are a couple of specific examples:

    ", + "

    In C, a string is an array of chars, so using a couple of arrays as strings is in the spirit while using a second array in a non-string like fashion would violate the intent.

    ", + "

    In APL or J, arrays are the core of the language so ruling them out is unfair. Meeting the spirit will come down to how they are used.

    Please keep in mind these are just examples and you may hit new territory finding a solution. There will be other cases like these. Explain your reasoning. You may want to open a discussion on the talk page as well.

    ", + "The added \"No rereading\" restriction is for practical reasons, re-reading stdin should be broken. I haven't outright banned the use of other files but I've discouraged them as it is basically another form of a list. Somewhere there may be a language that just sings when doing file manipulation and where that makes sense; however, for most there should be a way to accomplish without resorting to an externality.

    At the end of the day for the implementer this should be a bit of fun. As an implementer you represent the expertise in your language, the reader may have no knowledge of your language. For the reader it should give them insight into how people think outside the box in other languages. Comments, especially for non-obvious (to the reader) bits will be extremely helpful. While the implementations may be a bit artificial in the context of this task, the general techniques may be useful elsewhere.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7eeb", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Long multiplication", + "type": "Waypoint", + "description": [ + "Task:", + "

    Explicitly implement long multiplication.

    This is one possible approach to arbitrary-precision integer algebra.

    ", + "

    For output, display the result of 264 * 264.

    ", + "

    The decimal representation of 264 is:

    ", + "

    18,446,744,073,709,551,616

    The output of 264 * 264 is 2128, and is:

    ", + "

    340,282,366,920,938,463,463,374,607,431,768,211,456

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Iterative===", + "", + "With integer expression inputs at this scale, JavaScript still gives a slightly lossy result, despite the subsequent digit by digit string concatenation approach.", + "", + "The problem is that the JavaScript Math.pow expressions become lossy at around 2^54, and Math.pow(2, 64) evaluates to a rounded:", + "", + "18446744073709552000 rather than the full 18446744073709551616", + "", + "This means that to handle larger inputs, the multiplication function needs to have string parameters:", + "", + "function mult(strNum1,strNum2){", + "", + " var a1 = strNum1.split(\"\").reverse();", + " var a2 = strNum2.toString().split(\"\").reverse();", + " var aResult = new Array;", + " ", + " for ( var iterNum1 = 0; iterNum1 < a1.length; iterNum1++ ) {", + " for ( var iterNum2 = 0; iterNum2 < a2.length; iterNum2++ ) {", + " var idxIter = iterNum1 + iterNum2; // Get the current array position.", + " aResult[idxIter] = a1[iterNum1] * a2[iterNum2] + ( idxIter >= aResult.length ? 0 : aResult[idxIter] );", + " ", + " if ( aResult[idxIter] > 9 ) { // Carrying", + " aResult[idxIter + 1] = Math.floor( aResult[idxIter] / 10 ) + ( idxIter + 1 >= aResult.length ? 0 : aResult[idxIter + 1] );", + " aResult[idxIter] -= Math.floor( aResult[idxIter] / 10 ) * 10;", + " }", + " }", + " }", + " return aResult.reverse().join(\"\");", + "}", + "", + "", + "mult('18446744073709551616', '18446744073709551616')", + "", + "{{Out}}", + "
    340282366920938463463374607431768211456
    ", + "", + "", + "===Functional (ES 5)===", + "", + "The function below accepts integer string or native integer arguments, but as JavaScript (unlike Haskell and Python, for example), lacks an arbitrary precision integer type, larger inputs to this function (beyond the scale of c. 2^54) need to take the form of integer strings, to avoid rounding. ", + "", + "For the same reason, the output always takes the form of an arbitrary precision integer string, rather than a native integer data type. (See the '''largeIntegerString()''' helper function below)", + "", + "(function () {", + " 'use strict';", + "", + " // Javascript lacks an unbounded integer type", + " // so this multiplication function takes and returns", + " // long integer strings rather than any kind of native integer", + "", + " // longMult :: (String | Integer) -> (String | Integer) -> String", + " function longMult(num1, num2) {", + " return largeIntegerString(", + " digitProducts(digits(num1), digits(num2))", + " );", + " }", + "", + " // digitProducts :: [Int] -> [Int] -> [Int]", + " function digitProducts(xs, ys) {", + " return multTable(xs, ys)", + " .map(function (zs, i) {", + " return Array.apply(null, Array(i))", + " .map(function () {", + " return 0;", + " })", + " .concat(zs);", + " })", + " .reduce(function (a, x) {", + " if (a) {", + " var lng = a.length;", + "", + " return x.map(function (y, i) {", + " return y + (i < lng ? a[i] : 0);", + " })", + "", + " } else return x;", + " })", + " }", + "", + " // largeIntegerString :: [Int] -> String", + " function largeIntegerString(lstColumnValues) {", + " var dctProduct = lstColumnValues", + " .reduceRight(function (a, x) {", + " var intSum = x + a.carried,", + " intDigit = intSum % 10;", + "", + " return {", + " digits: intDigit", + " .toString() + a.digits,", + " carried: (intSum - intDigit) / 10", + " };", + " }, {", + " digits: '',", + " carried: 0", + " });", + "", + " return (dctProduct.carried > 0 ? (", + " dctProduct.carried.toString()", + " ) : '') + dctProduct.digits;", + " }", + "", + " // multTables :: [Int] -> [Int] -> [[Int]]", + " function multTable(xs, ys) {", + " return ys.map(function (y) {", + " return xs.map(function (x) {", + " return x * y;", + " })", + " });", + " }", + "", + " // digits :: (Integer | String) -> [Integer]", + " function digits(n) {", + " return (typeof n === 'string' ? n : n.toString())", + " .split('')", + " .map(function (x) {", + " return parseInt(x, 10);", + " });", + " }", + "", + " // TEST showing that larged bounded integer inputs give only rounded results", + " // whereas integer string inputs allow for full precision on this scale (2^128)", + "", + " return {", + " fromIntegerStrings: longMult(", + " '18446744073709551616',", + " '18446744073709551616'", + " ),", + " fromBoundedIntegers: longMult(", + " 18446744073709551616,", + " 18446744073709551616", + " )", + " };", + "})();", + "{{Out}}", + "
    {\"fromIntegerStrings\":\"340282366920938463463374607431768211456\", ",
    +        "\"fromBoundedIntegers\":\"340282366920938477630474056040704000000\"}
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7eec", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function mult(strNum1,strNum2){\n\n var a1 = strNum1.split(\"\").reverse();\n var a2 = strNum2.toString().split(\"\").reverse();\n var aResult = new Array;\n \n for ( var iterNum1 = 0; iterNum1 < a1.length; iterNum1++ ) {\n for ( var iterNum2 = 0; iterNum2 < a2.length; iterNum2++ ) {\n var idxIter = iterNum1 + iterNum2; // Get the current array position.\n aResult[idxIter] = a1[iterNum1] * a2[iterNum2] + ( idxIter >= aResult.length ? 0 : aResult[idxIter] );\n \n if ( aResult[idxIter] > 9 ) { // Carrying\n aResult[idxIter + 1] = Math.floor( aResult[idxIter] / 10 ) + ( idxIter + 1 >= aResult.length ? 0 : aResult[idxIter + 1] );\n aResult[idxIter] -= Math.floor( aResult[idxIter] / 10 ) * 10;\n }\n }\n }\n return aResult.reverse().join(\"\");\n}\n\n\nmult('18446744073709551616', '18446744073709551616')\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Look-and-say sequence", + "type": "Waypoint", + "description": [ + "

    The Look and say sequence is a recursively defined sequence of numbers studied most notably by John Conway.

    ", + "

    Sequence Definition

    ", + "Take a decimal number", + "Look at the number, visually grouping consecutive runs of the same digit.", + "Say the number, from left to right, group by group; as how many of that digit there are - followed by the digit grouped. This becomes the next number of the sequence.", + "

    An example:

    ", + "Starting with the number 1, you have one 1 which produces 11", + "Starting with 11, you have two 1's. I.E.: 21", + "Starting with 21, you have one 2, then one 1. I.E.: (12)(11) which becomes 1211", + "Starting with 1211, you have one 1, one 2, then two 1's. I.E.: (11)(12)(21) which becomes 111221Task:", + "

    Write a program to generate successive members of the look-and-say sequence.

    ", + "See also:", + " Look-and-Say Numbers (feat John Conway), A Numberphile Video.", + " This task is related to, and an application of, the Run-length encoding task.", + " Sequence A005150 on The On-Line Encyclopedia of Integer Sequences." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{trans|Perl}}", + "function lookandsay(str) {", + " return str.replace(/(.)\\1*/g, function(seq, p1){return seq.length.toString() + p1})", + "}", + "", + "var num = \"1\";", + "for (var i = 10; i > 0; i--) {", + " alert(num);", + " num = lookandsay(num);", + "}", + "", + "Without RegExp", + "", + "function lookSay(digits) {", + " var result = '',", + " chars = (digits + ' ').split(''),", + " lastChar = chars[0],", + " times = 0;", + " ", + " chars.forEach(function(nextChar) {", + " if (nextChar === lastChar) {", + " times++;", + " }", + " else {", + " result += (times + '') + lastChar;", + " lastChar = nextChar;", + " times = 1;", + " }", + " });", + " ", + " return result;", + "}", + "", + "(function output(seed, iterations) {", + " for (var i = 0; i < iterations; i++) {", + " console.log(seed);", + " seed = lookSay(seed);", + " }", + "})(\"1\", 10);", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7eed", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function lookandsay(str) {\n return str.replace(/(.)\\1*/g, function(seq, p1){return seq.length.toString() + p1})\n}\n\nvar num = \"1\";\nfor (var i = 10; i > 0; i--) {\n alert(num);\n num = lookandsay(num);\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Loop over multiple arrays simultaneously", + "type": "Waypoint", + "description": [ + "Task:", + "

    Loop over multiple arrays (or lists or tuples or whatever they're called in

    ", + "

    your language) and display the i th element of each.

    Use your language's \"for each\" loop if it has one, otherwise iterate

    ", + "

    through the collection in order with some other loop.

    ", + "

    For this example, loop over the arrays:

    ", + "

    (a,b,c)

    ", + "

    (A,B,C)

    ", + "

    (1,2,3)

    ", + "

    to produce the output:

    ", + "

    aA1

    ", + "

    bB2

    ", + "

    cC3

    ", + "

    If possible, also describe what happens when the arrays are of different lengths.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Imperative===", + "This loops over the indices of the first array, ", + "and uses that to index into the others.", + "var a = [\"a\",\"b\",\"c\"],", + " b = [\"A\",\"B\",\"C\"],", + " c = [1,2,3],", + " output = \"\",", + " i;", + "for (i = 0; i < a.length; i += 1) {", + " output += a[i] + b[i] + c[i] + \"\\n\";", + "}", + "If the b or c arrays are too \"short\", ", + "you will see the string \"undefined\" appear in the output.", + "", + "Alternatively, we can nest a couple of calls to '''.forEach()''': one for the array of three arrays, and one for each of the three index positions:", + "", + "var lstOut = ['', '', ''];", + "", + "[[\"a\", \"b\", \"c\"], [\"A\", \"B\", \"C\"], [\"1\", \"2\", \"3\"]].forEach(", + " function (a) {", + " [0, 1, 2].forEach(", + " function (i) {", + " // side-effect on an array outside the function", + " lstOut[i] += a[i];", + " }", + " );", + " }", + ");", + "", + "// lstOut --> [\"aA1\", \"bB2\", \"cC3\"]", + "", + "===Functional (ES5)===", + "", + "Functional options include folding across an array of arrays with the built-in '''Array.reduce()''',", + "using a zipWith() function of suitable arity, or mapping over the output of a generic (any arity) zip() function.", + "", + "(The generic zip function is the most tolerant – it simply ignores further elements in any arrays which are longer than the shortest array).", + "", + "Reduce / fold:", + "", + "(function (lstArrays) {", + "", + " return lstArrays.reduce(", + " function (a, e) {", + " return [", + " a[0] + e[0],", + " a[1] + e[1],", + " a[2] + e[2]", + " ];", + " }, ['', '', ''] // initial copy of the accumulator", + " ).join('\\n');", + "", + "})([", + " [\"a\", \"b\", \"c\"],", + " [\"A\", \"B\", \"C\"],", + " [\"1\", \"2\", \"3\"]", + "]);", + "", + "A fixed arity ZipWith:", + "", + "(function (x, y, z) {", + "", + " // function of arity 3 mapped over nth items of each of 3 lists", + " // (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]", + " function zipWith3(f, xs, ys, zs) {", + " return zs.length ? [f(xs[0], ys[0], zs[0])].concat(", + " zipWith3(f, xs.slice(1), ys.slice(1), zs.slice(1))) : [];", + " }", + "", + " function concat(x, y, z) {", + " return ''.concat(x, y, z);", + " }", + "", + " return zipWith3(concat, x, y, z).join('\\n')", + "", + "})([\"a\", \"b\", \"c\"], [\"A\", \"B\", \"C\"], [1, 2, 3]);", + "", + "", + "Or we can write a generic '''zipListsWith''' which applies some supplied function overs lists derived from the nth members of an arbitrary list of (equal-length) lists.", + "", + "(function () {", + " 'use strict';", + "", + " // zipListsWith :: ([a] -> b) -> [[a]] -> [[b]]", + " function zipListsWith(f, xss) {", + " return (xss.length ? xss[0] : [])", + " .map(function (_, i) {", + " return f(xss.map(function (xs) {", + " return xs[i];", + " }));", + " });", + " }", + "", + "", + "", + "", + " // Sample function over a list", + "", + " // concat :: [a] -> s", + " function concat(lst) {", + " return ''.concat.apply('', lst);", + " }", + "", + "", + " // TEST", + " ", + " return zipListsWith(", + " concat, ", + " [[\"a\", \"b\", \"c\"], [\"A\", \"B\", \"C\"], [1, 2, 3]]", + " )", + " .join('\\n');", + "", + "})();", + "", + "{{Out}}", + "", + "aA1", + "bB2", + "cC3", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7eee", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var a = [\"a\",\"b\",\"c\"],\n b = [\"A\",\"B\",\"C\"],\n c = [1,2,3],\n output = \"\",\n i;\nfor (i = 0; i < a.length; i += 1) {\n output += a[i] + b[i] + c[i] + \"\\n\";\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Loops/Do-while", + "type": "Waypoint", + "description": [ + "

    Start with a value at 0. Loop while value mod 6 is not equal to 0.

    ", + "

    Each time through the loop, add 1 to the value then print it.

    ", + "

    The loop must execute at least once.

    Reference:", + "Do while loop Wikipedia." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Javascript: Imperative===", + "var val = 0;", + "do {", + " print(++val);", + "} while (val % 6);", + "", + "===Javascript: Functional===", + "====ES5====", + "In a functional idiom of JavaScript we cannot use a Do While '''statement''', as it returns no value and is not a composable expression. We can, however achieve the same effect with a composable doWhile '''function''', which takes three arguments, and returns the output series as a value.", + "", + ":#An initial value,", + ":#a Do function which transforms that value repetitively, corresponding to the body of the loop,", + ":#and a conditional While function.", + "", + "function doWhile(varValue, fnBody, fnTest) {", + " 'use strict';", + " var d = fnBody(varValue); // a transformed value", + "", + " return fnTest(d) ? [d].concat(", + " doWhile(d, fnBody, fnTest)", + " ) : [d];", + "}", + "", + "console.log(", + " doWhile(0, // initial value", + " function (x) { // Do body, returning transformed value", + " return x + 1;", + " },", + " function (x) { // While condition", + " return x % 6;", + " }", + " ).join('\\n')", + "); ", + "", + "Output:", + "1", + "2", + "3", + "4", + "5", + "6 ", + "", + "Alternatively, if we assume instead that the unstated problem was not to produce repetitive computation, but to derive the '''membership of a set''' we could interpret the task as a request for a JavaScript implementation of the '''takeWhile''' function – a familiar staple of functional list processing.", + "", + "So, for example, something like:", + "", + "function range(m, n) {", + " 'use strict';", + " return Array.apply(null, Array(n - m + 1)).map(", + " function (x, i) {", + " return m + i;", + " }", + " );", + "}", + " ", + "function takeWhile(lst, fnTest) {", + " 'use strict';", + " var varHead = lst.length ? lst[0] : null;", + " ", + " return varHead ? (", + " fnTest(varHead) ? [varHead].concat(", + " takeWhile(lst.slice(1), fnTest)", + " ) : []", + " ) : []", + "}", + " ", + "console.log(", + " takeWhile(", + " range(1, 100),", + " function (x) {", + " return x % 6;", + " }", + " ).join('\\n')", + "); ", + "", + "Output:", + "1", + "2", + "3", + "4", + "5", + "", + "====ES6====", + "", + "A process or value of this kind might be better expressed (in functionally composed JavaScript) with an '''unfold''' or '''until''' function, returning a list.", + "", + "(() => {", + " 'use strict';", + "", + " // unfoldr :: (b -> Maybe (a, b)) -> b -> [a]", + " function unfoldr(mf, v) {", + " for (var lst = [], a = v, m;", + " (m = mf(a)) && m.valid;) {", + " lst.push(m.value), a = m.new;", + " }", + " return lst;", + " }", + "", + " // until :: (a -> Bool) -> (a -> a) -> a -> a", + " function until(p, f, x) {", + " let v = x;", + " while(!p(v)) v = f(v);", + " return v;", + " }", + "", + " let result1 = unfoldr(", + " x => {", + " return {", + " value: x,", + " valid: (x % 6) !== 0,", + " new: x + 1", + " }", + " },", + " 1", + " );", + "", + " let result2 = until(", + " m => (m.n % 6) === 0,", + " m => {", + " return {", + " n : m.n + 1,", + " xs : m.xs.concat(m.n)", + " };", + " },", + " {", + " n: 1,", + " xs: []", + " }", + " ).xs;", + " ", + " return [result1, result2];", + "})();", + "", + "", + "", + "[[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ef1", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var val = 0;\ndo {\n print(++val);\n} while (val % 6);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Loops/Nested", + "type": "Waypoint", + "description": [ + "

    Show a nested loop which searches a two-dimensional array filled with random numbers uniformly distributed over $[1,\\ldots,20]$.

    The loops iterate rows and columns of the array printing the elements until the value $20$ is met.

    Specifically, this task also shows how to break out of nested loops.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Demonstrates use of break with a label.", + "Uses print() function from [[Rhino]].", + "// a \"random\" 2-D array ", + "var a = [[2, 12, 10, 4], [18, 11, 9, 3], [14, 15, 7, 17], [6, 19, 8, 13], [1, 20, 16, 5]];", + "", + "outer_loop:", + "for (var i in a) {", + " print(\"row \" + i);", + " for (var j in a[i]) {", + " print(\" \" + a[i][j]);", + " if (a[i][j] == 20) ", + " break outer_loop;", + " }", + "}", + "print(\"done\");", + "", + "In a functional idiom of JavaScript, however, we can not use a loop statement, as statements return no value and can not be composed within other functional expressions. Functional JavaScript often replaces a loop with a map or fold. In this case, we can achieve the same task by defining the standard list-processing function '''takeWhile''', which terminates when a condition returns true.", + "", + "We can then search the groups in the nested array by nesting takeWhile inside itself, and finally terminate when the 20 is found by one further application of takeWhile.", + "", + "Using the same data as above, and returning the trail of numbers up to twenty from a nested and composable expression:", + "", + "var lst = [[2, 12, 10, 4], [18, 11, 9, 3], [14, 15, 7, 17], [6, 19, 8, 13], [1,", + " 20, 16, 5]];", + "", + "var takeWhile = function (lst, fnTest) {", + " 'use strict';", + " var varHead = lst.length ? lst[0] : null;", + "", + " return varHead ? (", + " fnTest(varHead) ? [varHead].concat(", + " takeWhile(lst.slice(1), fnTest)", + " ) : []", + " ) : []", + " },", + "", + " // The takeWhile function terminates when notTwenty(n) returns false", + " notTwenty = function (n) {", + " return n !== 20;", + " },", + "", + " // Leftward groups containing no 20", + " // takeWhile nested within takeWhile", + " lstChecked = takeWhile(lst, function (group) {", + " return takeWhile(", + " group,", + " notTwenty", + " ).length === 4;", + " });", + "", + "", + "// Return the trail of numbers preceding 20 from a composable expression", + "", + "console.log(", + " // Numbers before 20 in a group in which it was found", + " lstChecked.concat(", + " takeWhile(", + " lst[lstChecked.length], notTwenty", + " )", + " )", + " // flattened", + " .reduce(function (a, x) {", + " return a.concat(x);", + " }).join('\\n')", + "); ", + "", + "Output:", + "2", + "12", + "10", + "4", + "18", + "11", + "9", + "3", + "14", + "15", + "7", + "17", + "6", + "19", + "8", + "13", + "6", + "19", + "8", + "13", + "1", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ef7", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// a \"random\" 2-D array \nvar a = [[2, 12, 10, 4], [18, 11, 9, 3], [14, 15, 7, 17], [6, 19, 8, 13], [1, 20, 16, 5]];\n\nouter_loop:\nfor (var i in a) {\n print(\"row \" + i);\n for (var j in a[i]) {\n print(\" \" + a[i][j]);\n if (a[i][j] == 20) \n break outer_loop;\n }\n}\nprint(\"done\");\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Lucas-Lehmer test", + "type": "Waypoint", + "description": [ + "

    Lucas-Lehmer Test: for $p$ an odd prime, the Mersenne number $2^p-1$ is prime if and only if $2^p-1$ divides $S(p-1)$ where $S(n+1)=(S(n))^2-2$, and $S(1)=4$.

    ", + "Task:", + "

    Calculate all Mersenne primes up to the implementation's

    ", + "

    maximum precision, or the 47th Mersenne prime (whichever comes first).

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7efa", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "LU decomposition", + "type": "Waypoint", + "description": [ + "

    Every square matrix $A$ can be decomposed into a product of a lower triangular matrix $L$ and a upper triangular matrix $U$,

    ", + "

    as described in LU decomposition.

    $A = LU$

    It is a modified form of Gaussian elimination.

    ", + "

    While the Cholesky decomposition only works for symmetric,

    ", + "

    positive definite matrices, the more general LU decomposition

    ", + "

    works for any square matrix.

    There are several algorithms for calculating L and U.

    ", + "

    To derive Crout's algorithm for a 3x3 example,

    ", + "

    we have to solve the following system:

    $

    ", + "

    A =

    ", + "

    \\begin{pmatrix}

    ", + "

    a_{11} & a_{12} & a_{13}\\\\

    ", + "

    a_{21} & a_{22} & a_{23}\\\\

    ", + "

    a_{31} & a_{32} & a_{33}\\\\

    ", + "

    \\end{pmatrix}

    ", + "

    =

    ", + "

    \\begin{pmatrix}

    ", + "

    l_{11} & 0 & 0 \\\\

    ", + "

    l_{21} & l_{22} & 0 \\\\

    ", + "

    l_{31} & l_{32} & l_{33}\\\\

    ", + "

    \\end{pmatrix}

    ", + "

    \\begin{pmatrix}

    ", + "

    u_{11} & u_{12} & u_{13} \\\\

    ", + "

    0 & u_{22} & u_{23} \\\\

    ", + "

    0 & 0 & u_{33}

    ", + "

    \\end{pmatrix}

    ", + "

    = LU

    ", + "

    $

    We now would have to solve 9 equations with 12 unknowns. To make the system uniquely solvable, usually the diagonal elements of $L$ are set to 1

    $l_{11}=1$

    ", + "

    $l_{22}=1$

    ", + "

    $l_{33}=1$

    so we get a solvable system of 9 unknowns and 9 equations.

    $

    ", + "

    A =

    ", + "

    \\begin{pmatrix}

    ", + "

    a_{11} & a_{12} & a_{13}\\\\

    ", + "

    a_{21} & a_{22} & a_{23}\\\\

    ", + "

    a_{31} & a_{32} & a_{33}\\\\

    ", + "

    \\end{pmatrix}

    ", + "

    =

    ", + "

    \\begin{pmatrix}

    ", + "

    1 & 0 & 0 \\\\

    ", + "

    l_{21} & 1 & 0 \\\\

    ", + "

    l_{31} & l_{32} & 1\\\\

    ", + "

    \\end{pmatrix}

    ", + "

    \\begin{pmatrix}

    ", + "

    u_{11} & u_{12} & u_{13} \\\\

    ", + "

    0 & u_{22} & u_{23} \\\\

    ", + "

    0 & 0 & u_{33}

    ", + "

    \\end{pmatrix}

    ", + "

    =

    ", + "

    \\begin{pmatrix}

    ", + "

    u_{11} & u_{12} & u_{13} \\\\

    ", + "

    u_{11}l_{21} & u_{12}l_{21}+u_{22} & u_{13}l_{21}+u_{23} \\\\

    ", + "

    u_{11}l_{31} & u_{12}l_{31}+u_{22}l_{32} & u_{13}l_{31} + u_{23}l_{32}+u_{33}

    ", + "

    \\end{pmatrix}

    ", + "

    = LU

    ", + "

    $

    Solving for the other $l$ and $u$, we get the following equations:

    $u_{11}=a_{11}$

    ", + "

    $u_{12}=a_{12}$

    ", + "

    $u_{13}=a_{13}$

    $u_{22}=a_{22} - u_{12}l_{21}$

    ", + "

    $u_{23}=a_{23} - u_{13}l_{21}$

    $u_{33}=a_{33} - (u_{13}l_{31} + u_{23}l_{32})$

    and for $l$:

    $l_{21}=\\frac{1}{u_{11}} a_{21}$

    ", + "

    $l_{31}=\\frac{1}{u_{11}} a_{31}$

    $l_{32}=\\frac{1}{u_{22}} (a_{32} - u_{12}l_{31})$

    We see that there is a calculation pattern, which can be expressed as the following formulas, first for $U$

    $u_{ij} = a_{ij} - \\sum_{k=1}^{i-1} u_{kj}l_{ik}$

    and then for $L$

    $l_{ij} = \\frac{1}{u_{jj}} (a_{ij} - \\sum_{k=1}^{j-1} u_{kj}l_{ik})$

    We see in the second formula that to get the $l_{ij}$ below the diagonal, we have to divide by the diagonal element (pivot) $u_{jj}$, so we get problems when $u_{jj}$ is either 0 or very small, which leads to numerical instability.

    The solution to this problem is pivoting $A$, which means rearranging the rows of $A$, prior to the $LU$ decomposition, in a way that the largest element of each column gets onto the diagonal of $A$. Rearranging the rows means to multiply $A$ by a permutation matrix $P$:

    $PA \\Rightarrow A'$

    Example:

    $

    ", + "

    \\begin{pmatrix}

    ", + "

    0 & 1 \\\\

    ", + "

    1 & 0

    ", + "

    \\end{pmatrix}

    ", + "

    \\begin{pmatrix}

    ", + "

    1 & 4 \\\\

    ", + "

    2 & 3

    ", + "

    \\end{pmatrix}

    ", + "

    \\Rightarrow

    ", + "

    \\begin{pmatrix}

    ", + "

    2 & 3 \\\\

    ", + "

    1 & 4

    ", + "

    \\end{pmatrix}

    ", + "

    $

    The decomposition algorithm is then applied on the rearranged matrix so that

    $PA = LU$

    ", + "

    Task description

    The task is to implement a routine which will take a square nxn matrix $A$ and return a lower triangular matrix $L$, a upper triangular matrix $U$ and a permutation matrix $P$,

    ", + "

    so that the above equation is fullfilled.

    ", + "

    You should then test it on the following two examples and include your output.

    Example 1:

    ", + "
    ",
    +        "A1   3   5",
    +        "2   4   7",
    +        "1   1   0L1.00000   0.00000   0.00000",
    +        "0.50000   1.00000   0.00000",
    +        "0.50000  -1.00000   1.00000U2.00000   4.00000   7.00000",
    +        "0.00000   1.00000   1.50000",
    +        "0.00000   0.00000  -2.00000P0   1   0",
    +        "1   0   0",
    +        "0   0   1",
    +        "

    Example 2:

    ", + "
    ",
    +        "A11    9   24    2",
    +        " 1    5    2    6",
    +        " 3   17   18    1",
    +        " 2    5    7    1L1.00000   0.00000   0.00000   0.00000",
    +        "0.27273   1.00000   0.00000   0.00000",
    +        "0.09091   0.28750   1.00000   0.00000",
    +        "0.18182   0.23125   0.00360   1.00000U11.00000    9.00000   24.00000    2.00000",
    +        " 0.00000   14.54545   11.45455    0.45455",
    +        " 0.00000    0.00000   -3.47500    5.68750",
    +        " 0.00000    0.00000    0.00000    0.51079P1   0   0   0",
    +        "0   0   1   0",
    +        "0   1   0   0",
    +        "0   0   0   1",
    +        "
    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7efb", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Ludic numbers", + "type": "Waypoint", + "description": [ + "

    Ludic numbers are related to prime numbers as they are generated by a sieve quite like the Sieve of Eratosthenes is used to generate prime numbers.

    The first ludic number is 1.

    To generate succeeding ludic numbers create an array of increasing integers starting from 2.

    ", + "

    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ...

    ", + "

    (Loop)

    ", + "Take the first member of the resultant array as the next ludic number 2.", + "Remove every 2nd indexed item from the array (including the first).:2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ...", + "(Unrolling a few loops...)", + "Take the first member of the resultant array as the next ludic number 3.", + "Remove every 3rd indexed item from the array (including the first).:3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 ...", + "Take the first member of the resultant array as the next ludic number 5.", + "Remove every 5th indexed item from the array (including the first).:5 7 11 13 17 19 23 25 29 31 35 37 41 43 47 49 53 55 59 61 65 67 71 73 77 ...", + "Take the first member of the resultant array as the next ludic number 7.", + "Remove every 7th indexed item from the array (including the first).:7 11 13 17 23 25 29 31 37 41 43 47 53 55 59 61 67 71 73 77 83 85 89 91 97 ...", + " ... ", + "Take the first member of the current array as the next ludic number L.", + "Remove every Lth indexed item from the array (including the first).", + " ... ", + "Task:", + "Generate and show here the first 25 ludic numbers.", + "How many ludic numbers are there less than or equal to 1000?", + "Show the 2000..2005th ludic numbers.", + "Stretch goal:", + "

    Show all triplets of ludic numbers < 250.

    ", + "A triplet is any three numbers $x,$ $x+2,$ $x+6$ where all three numbers are also ludic numbers. " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES6===", + "/**", + " * Boilerplate to simply get an array filled between 2 numbers", + " * @param {!number} s Start here (inclusive)", + " * @param {!number} e End here (inclusive)", + " */", + "const makeArr = (s, e) => new Array(e + 1 - s).fill(s).map((e, i) => e + i);", + "", + "/**", + " * Remove every n-th element from the given array", + " * @param {!Array} arr", + " * @param {!number} n", + " * @return {!Array}", + " */", + "const filterAtInc = (arr, n) => arr.filter((e, i) => (i + 1) % n);", + "", + "/**", + " * Generate ludic numbers", + " * @param {!Array} arr", + " * @param {!Array} result", + " * @return {!Array}", + " */", + "const makeLudic = (arr, result) => {", + " const iter = arr.shift();", + " result.push(iter);", + " return arr.length ? makeLudic(filterAtInc(arr, iter), result) : result;", + "};", + "", + "/**", + " * Our Ludic numbers. This is a bit of a cheat, as we already know beforehand", + " * up to where our seed array needs to go in order to exactly get to the", + " * 2005th Ludic number.", + " * @type {!Array}", + " */", + "const ludicResult = makeLudic(makeArr(2, 21512), [1]);", + "", + "", + "// Below is just logging out the results.", + "/**", + " * Given a number, return a function that takes an array, and return the", + " * count of all elements smaller than the given", + " * @param {!number} n", + " * @return {!Function}", + " */", + "const smallerThanN = n => arr => {", + " return arr.reduce((p,c) => {", + " return c <= n ? p + 1 : p", + " }, 0)", + "};", + "const smallerThan1K = smallerThanN(1000);", + "", + "console.log('\\nFirst 25 Ludic Numbers:');", + "console.log(ludicResult.filter((e, i) => i < 25).join(', '));", + "", + "console.log('\\nTotal Ludic numbers smaller than 1000:');", + "console.log(smallerThan1K(ludicResult));", + "", + "console.log('\\nThe 2000th to 2005th ludic numbers:');", + "console.log(ludicResult.filter((e, i) => i > 1998).join(', '));", + "", + "console.log('\\nTriplets smaller than 250:');", + "ludicResult.forEach(e => {", + " if (e + 6 < 250 && ludicResult.indexOf(e + 2) > 0 && ludicResult.indexOf(e + 6) > 0) {", + " console.log([e, e + 2, e + 6].join(', '));", + " }", + "});", + "", + "
    ",
    +        "First 25 Ludic Numbers:",
    +        "1, 2, 3, 5, 7, 11, 13, 17, 23, 25, 29, 37, 41, 43, 47, 53, 61, 67, 71, 77, 83, 89, 91, 97, 107",
    +        "",
    +        "Total Ludic numbers smaller than 1000:",
    +        "142",
    +        "",
    +        "The 2000th to 2005th ludic numbers:",
    +        "21475, 21481, 21487, 21493, 21503, 21511",
    +        "",
    +        "Triplets smaller than 250:",
    +        "1, 3, 7",
    +        "5, 7, 11",
    +        "11, 13, 17",
    +        "23, 25, 29",
    +        "41, 43, 47",
    +        "173, 175, 179",
    +        "221, 223, 227",
    +        "233, 235, 239",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7efc", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "/**\n * Boilerplate to simply get an array filled between 2 numbers\n * @param {!number} s Start here (inclusive)\n * @param {!number} e End here (inclusive)\n */\nconst makeArr = (s, e) => new Array(e + 1 - s).fill(s).map((e, i) => e + i);\n\n/**\n * Remove every n-th element from the given array\n * @param {!Array} arr\n * @param {!number} n\n * @return {!Array}\n */\nconst filterAtInc = (arr, n) => arr.filter((e, i) => (i + 1) % n);\n\n/**\n * Generate ludic numbers\n * @param {!Array} arr\n * @param {!Array} result\n * @return {!Array}\n */\nconst makeLudic = (arr, result) => {\n const iter = arr.shift();\n result.push(iter);\n return arr.length ? makeLudic(filterAtInc(arr, iter), result) : result;\n};\n\n/**\n * Our Ludic numbers. This is a bit of a cheat, as we already know beforehand\n * up to where our seed array needs to go in order to exactly get to the\n * 2005th Ludic number.\n * @type {!Array}\n */\nconst ludicResult = makeLudic(makeArr(2, 21512), [1]);\n\n\n// Below is just logging out the results.\n/**\n * Given a number, return a function that takes an array, and return the\n * count of all elements smaller than the given\n * @param {!number} n\n * @return {!Function}\n */\nconst smallerThanN = n => arr => {\n return arr.reduce((p,c) => {\n return c <= n ? p + 1 : p\n }, 0)\n};\nconst smallerThan1K = smallerThanN(1000);\n\nconsole.log('\\nFirst 25 Ludic Numbers:');\nconsole.log(ludicResult.filter((e, i) => i < 25).join(', '));\n\nconsole.log('\\nTotal Ludic numbers smaller than 1000:');\nconsole.log(smallerThan1K(ludicResult));\n\nconsole.log('\\nThe 2000th to 2005th ludic numbers:');\nconsole.log(ludicResult.filter((e, i) => i > 1998).join(', '));\n\nconsole.log('\\nTriplets smaller than 250:');\nludicResult.forEach(e => {\n if (e + 6 < 250 && ludicResult.indexOf(e + 2) > 0 && ludicResult.indexOf(e + 6) > 0) {\n console.log([e, e + 2, e + 6].join(', '));\n }\n});\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Luhn test of credit card numbers", + "type": "Waypoint", + "description": [ + "

    The Luhn test is used by some credit card companies to distinguish valid credit card numbers from what could be a random selection of digits.

    Those companies using credit card numbers that can be validated by the Luhn test have numbers that pass the following test:

    ", + " Reverse the order of the digits in the number.", + " Take the first, third, ... and every other odd digit in the reversed digits and sum them to form the partial sum s1", + " Taking the second, fourth ... and every other even digit in the reversed digits:# Multiply each digit by two and sum the digits if the answer is greater than nine to form partial sums for the even digits", + "

    # Sum the partial sums of the even digits to form s2

    ", + "If s1 + s2 ends in zero then the original number is in the form of a valid credit card number as verified by the Luhn test.", + "

    For example, if the trial number is 49927398716:

    ", + "
    Reverse the digits:",
    +        "  61789372994",
    +        "Sum the odd digits:",
    +        "  6 + 7 + 9 + 7 + 9 + 4 = 42 = s1",
    +        "The even digits:",
    +        "    1,  8,  3,  2,  9",
    +        "  Two times each even digit:",
    +        "    2, 16,  6,  4, 18",
    +        "  Sum the digits of each multiplication:",
    +        "    2,  7,  6,  4,  9",
    +        "  Sum the last:",
    +        "    2 + 7 + 6 + 4 + 9 = 28 = s2s1 + s2 = 70 which ends in zero which means that 49927398716 passes the Luhn test
    ", + "Task:", + "

    Write a function/method/procedure/subroutine that will validate a number with the Luhn test, and

    ", + "use it to validate the following numbers:", + "

    49927398716

    ", + "

    49927398717

    ", + "

    1234567812345678

    ", + "

    1234567812345670

    ", + "Related tasks:", + " SEDOL", + " ISIN" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Using prototype.", + "mod10check = function(cc) {", + " return $A(cc).reverse().map(Number).inject(0, function(s, d, i) {", + " return s + (i % 2 == 1 ? (d == 9 ? 9 : (d * 2) % 9) : d);", + " }) % 10 == 0;", + "};", + "['49927398716','49927398717','1234567812345678','1234567812345670'].each(function(i){alert(mod10check(i))});", + "", + "Without any library.", + "var LuhnCheck = (function()", + "{", + "\tvar luhnArr = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9];", + "\treturn function(str)", + "\t{", + "\t\tvar counter = 0;", + "\t\tvar incNum;", + "\t\tvar odd = false;", + "\t\tvar temp = String(str).replace(/[^\\d]/g, \"\");", + "\t\tif ( temp.length == 0)", + "\t\t\treturn false;", + "\t\tfor (var i = temp.length-1; i >= 0; --i)", + "\t\t{", + "\t\t\tincNum = parseInt(temp.charAt(i), 10);", + "\t\t\tcounter += (odd = !odd)? incNum : luhnArr[incNum];", + "\t\t}", + "\t\treturn (counter%10 == 0);", + "\t}", + "})();", + "ES5.1 version (uses 'reduce' and 'reduceRight' Array methods).", + "function luhn(str){", + "\treturn str.split('').reduceRight(function(prev, curr, idx){", + "\t\tprev = parseInt(prev, 10);", + "\t\tif ((idx + 1) % 2 !== 0) {", + "\t\t\tcurr = (curr * 2).toString().split('').reduce(function(p, c){ return parseInt(p, 10) + parseInt(c, 10)});", + "\t\t}", + "\t\treturn prev + parseInt(curr, 10);", + "\t}) % 10 === 0;", + "}", + "", + "Highly compressed version.", + "var luhn10 = function(a,b,c,d,e) {", + " for(d = +a[b = a.length-1], e=0; b--;)", + " c = +a[b], d += ++e % 2 ? 2 * c % 10 + (c > 4) : c;", + " return !(d%10)", + "};", + "", + "// returns true", + "luhn10('4111111111111111') ", + "", + "// returns false", + "luhn10('4111111111111112') ", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7efd", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "mod10check = function(cc) {\n return $A(cc).reverse().map(Number).inject(0, function(s, d, i) {\n return s + (i % 2 == 1 ? (d == 9 ? 9 : (d * 2) % 9) : d);\n }) % 10 == 0;\n};\n['49927398716','49927398717','1234567812345678','1234567812345670'].each(function(i){alert(mod10check(i))});\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Lychrel numbers", + "type": "Waypoint", + "description": [ + "Take an integer n, greater than zero.", + "Form the next n of its series by reversing the digits of the current n and adding the result to the current n.", + "Stop when n becomes palindromic - i.e. the digits of n in reverse order == n.", + "

    The above recurrence relation when applied to most starting numbers n = 1, 2, ... terminates in a palindrome quite quickly, for example if n0 = 12 we get

    ", + "
    12",
    +        "12 + 21 = 33, a palindrome!

    And if n0 = 55 we get

    ", + "
    55",
    +        "55 + 55 = 110",
    +        "110 + 011 = 121, a palindrome!

    Notice that the check for a palindrome happens after an addition.

    ", + "

    Some starting numbers seem to go on forever; the recurrence relation for 196 has been calculated for millions of repetitions forming numbers with millions of digits, without forming a palindrome. These numbers that do not end in a palindrome are called Lychrel numbers.

    For the purposes of this task a Lychrel number is any starting number that does not form a palindrome within 500 (or more) iterations.

    ", + "Seed and related Lychrel numbers:", + "

    Any integer produced in the sequence of a Lychrel number is also a Lychrel number.

    In general, any sequence from one Lychrel number might converge to join the sequence from a prior Lychrel number candidate; for example the sequences for the numbers 196 and then 689 begin:

    ", + "
    196",
    +        "196 + 691 = 887",
    +        "887 + 788 = 1675",
    +        "1675 + 5761 = 7436",
    +        "7436 + 6347 = 13783",
    +        "13783 + 38731 = 52514",
    +        "52514 + 41525 = 94039",
    +        "...",
    +        "689",
    +        "689 + 986 = 1675",
    +        "1675 + 5761 = 7436",
    +        "...
    ", + "

    So we see that the sequence starting with 689 converges to, and continues with the same numbers as that for 196. Because of this we can further split the Lychrel numbers into true Seed Lychrel number candidates, and Related numbers that produce no palindromes but have integers in their sequence seen as part of the sequence generated from a lower Lychrel number.

    ", + "Task:", + " Find the number of seed Lychrel number candidates and related numbers for n in the range 1..10000 inclusive. (With that iteration limit of 500).", + " Print the number of seed Lychrels found; the actual seed Lychrels; and just the number of relateds found.", + " Print any seed Lychrel or related number that is itself a palindrome.", + "

    Show all output here.

    ", + "References:", + "What's special about 196? Numberphile video.", + "A023108 Positive integers which apparently never result in a palindrome under repeated applications of the function f(x) = x + (x with digits reversed).", + "Status of the 196 conjecture? Mathoverflow." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7efe", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "LZW compression", + "type": "Waypoint", + "description": [ + "

    The Lempel-Ziv-Welch (LZW) algorithm provides loss-less data compression.

    You can read a complete description of it in the Wikipedia article on the subject. It was patented, but it entered the public domain in 2004.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "//LZW Compression/Decompression for Strings", + "var LZW = {", + " compress: function (uncompressed) {", + " \"use strict\";", + " // Build the dictionary.", + " var i,", + " dictionary = {},", + " c,", + " wc,", + " w = \"\",", + " result = [],", + " dictSize = 256;", + " for (i = 0; i < 256; i += 1) {", + " dictionary[String.fromCharCode(i)] = i;", + " }", + "", + " for (i = 0; i < uncompressed.length; i += 1) {", + " c = uncompressed.charAt(i);", + " wc = w + c;", + " //Do not use dictionary[wc] because javascript arrays ", + " //will return values for array['pop'], array['push'] etc", + " // if (dictionary[wc]) {", + " if (dictionary.hasOwnProperty(wc)) {", + " w = wc;", + " } else {", + " result.push(dictionary[w]);", + " // Add wc to the dictionary.", + " dictionary[wc] = dictSize++;", + " w = String(c);", + " }", + " }", + "", + " // Output the code for w.", + " if (w !== \"\") {", + " result.push(dictionary[w]);", + " }", + " return result;", + " },", + "", + "", + " decompress: function (compressed) {", + " \"use strict\";", + " // Build the dictionary.", + " var i,", + " dictionary = [],", + " w,", + " result,", + " k,", + " entry = \"\",", + " dictSize = 256;", + " for (i = 0; i < 256; i += 1) {", + " dictionary[i] = String.fromCharCode(i);", + " }", + "", + " w = String.fromCharCode(compressed[0]);", + " result = w;", + " for (i = 1; i < compressed.length; i += 1) {", + " k = compressed[i];", + " if (dictionary[k]) {", + " entry = dictionary[k];", + " } else {", + " if (k === dictSize) {", + " entry = w + w.charAt(0);", + " } else {", + " return null;", + " }", + " }", + "", + " result += entry;", + "", + " // Add w+entry[0] to the dictionary.", + " dictionary[dictSize++] = w + entry.charAt(0);", + "", + " w = entry;", + " }", + " return result;", + " }", + "}, // For Test Purposes", + " comp = LZW.compress(\"TOBEORNOTTOBEORTOBEORNOT\"),", + " decomp = LZW.decompress(comp);", + "document.write(comp + '
    ' + decomp);
    ", + "", + "{{out}}", + "
    84,79,66,69,79,82,78,79,84,256,258,260,265,259,261,263",
    +        "TOBEORNOTTOBEORTOBEORNOT
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7eff", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "//LZW Compression/Decompression for Strings\nvar LZW = {\n compress: function (uncompressed) {\n \"use strict\";\n // Build the dictionary.\n var i,\n dictionary = {},\n c,\n wc,\n w = \"\",\n result = [],\n dictSize = 256;\n for (i = 0; i < 256; i += 1) {\n dictionary[String.fromCharCode(i)] = i;\n }\n\n for (i = 0; i < uncompressed.length; i += 1) {\n c = uncompressed.charAt(i);\n wc = w + c;\n //Do not use dictionary[wc] because javascript arrays \n //will return values for array['pop'], array['push'] etc\n // if (dictionary[wc]) {\n if (dictionary.hasOwnProperty(wc)) {\n w = wc;\n } else {\n result.push(dictionary[w]);\n // Add wc to the dictionary.\n dictionary[wc] = dictSize++;\n w = String(c);\n }\n }\n\n // Output the code for w.\n if (w !== \"\") {\n result.push(dictionary[w]);\n }\n return result;\n },\n\n\n decompress: function (compressed) {\n \"use strict\";\n // Build the dictionary.\n var i,\n dictionary = [],\n w,\n result,\n k,\n entry = \"\",\n dictSize = 256;\n for (i = 0; i < 256; i += 1) {\n dictionary[i] = String.fromCharCode(i);\n }\n\n w = String.fromCharCode(compressed[0]);\n result = w;\n for (i = 1; i < compressed.length; i += 1) {\n k = compressed[i];\n if (dictionary[k]) {\n entry = dictionary[k];\n } else {\n if (k === dictSize) {\n entry = w + w.charAt(0);\n } else {\n return null;\n }\n }\n\n result += entry;\n\n // Add w+entry[0] to the dictionary.\n dictionary[dictSize++] = w + entry.charAt(0);\n\n w = entry;\n }\n return result;\n }\n}, // For Test Purposes\n comp = LZW.compress(\"TOBEORNOTTOBEORTOBEORNOT\"),\n decomp = LZW.decompress(comp);\ndocument.write(comp + '
    ' + decomp);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Magic squares of doubly even order", + "type": "Waypoint", + "description": [ + "

    A magic square is an NxN square matrix whose numbers consist of consecutive numbers arranged so that the sum of each row and column, and both diagonals are equal to the same sum (which is called the magic number or magic constant).

    A magic square of doubly even order has a size that is a multiple of four (e.g. 4, 8, 12). This means that the subsquares also have an even size, which plays a role in the construction.

    ", + "

    {| style=\"float:right;border: 2px solid black; background:lightblue; color:black; margin-left:auto;margin-right:auto;text-align:center;width:22em;height:15em;table-layout:fixed;font-size:100%\"

    ", + "

    |-

    ", + "

    |1||2||62||61||60||59||7||8

    ", + "

    |-

    ", + "

    |9||10||54||53||52||51||15||16

    ", + "

    |-

    ", + "

    |48||47||19||20||21||22||42||41

    ", + "

    |-

    ", + "

    |40||39||27||28||29||30||34||33

    ", + "

    |-

    ", + "

    |32||31||35||36||37||38||26||25

    ", + "

    |-

    ", + "

    |24||23||43||44||45||46||18||17

    ", + "

    |-

    ", + "

    |49||50||14||13||12||11||55||56

    ", + "

    |-

    ", + "

    |57||58||6||5||4||3||63||64

    ", + "

    |}

    ", + "Task", + "

    Create a magic square of 8 x 8.

    ", + " Related tasks", + "Magic squares of odd order", + "Magic squares of singly even order", + " See also:", + "Doubly Even Magic Squares (1728.org)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES6===", + "{{Trans|Haskell}}", + "(() => {", + " 'use strict';", + "", + " // doubleEvenMagicSquare :: Int -> [[Int]]", + " const doubleEvenMagicSquare = n => {", + " if (n % 4 > 0) return undefined;", + "", + " // truthSeries :: Int -> [Int]", + " const truthSeries = n => {", + " if (n <= 0) return [true];", + " const xs = truthSeries(n - 1);", + " return xs.concat(xs.map(x => !x));", + " };", + "", + " const sqr = n * n,", + " scale = curry(replicate)(n / 4),", + " power = Math.log2(sqr),", + " sequence = isInt(power) ? truthSeries(power) : (", + " flatten(", + " scale(", + " splitEvery(4, truthSeries(4))", + " .map(scale)", + " )", + " )", + " );", + "", + " return splitEvery(n, sequence", + " .map((x, i) => x ? i + 1 : sqr - i));", + " };", + "", + "", + " // GENERIC FUNCTIONS ----------------------------------------------------", + "", + " // flatten :: Tree a -> [a]", + " const flatten = t => (t instanceof Array ? concatMap(flatten, t) : [t]);", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " const concatMap = (f, xs) => [].concat.apply([], xs.map(f));", + "", + " // splitEvery :: Int -> [a] -> [][a]]", + " const splitEvery = (n, xs) => {", + " if (xs.length <= n) return [xs];", + " const [h, t] = [xs.slice(0, n), xs.slice(n)];", + " return [h].concat(splitEvery(n, t));", + " }", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " const curry = f => a => b => f(a, b);", + "", + " // replicate :: Int -> a -> [a]", + " const replicate = (n, a) => {", + " let v = [a],", + " o = [];", + " if (n < 1) return o;", + " while (n > 1) {", + " if (n & 1) o = o.concat(v);", + " n >>= 1;", + " v = v.concat(v);", + " }", + " return o.concat(v);", + " };", + "", + " // isInt :: Int -> Bool", + " const isInt = x => x === Math.floor(x);", + "", + "", + " // TEST AND DISPLAY FUNCTIONS -------------------------------------------", + "", + " // transpose :: [[a]] -> [[a]]", + " const transpose = xs =>", + " xs[0].map((_, iCol) => xs.map((row) => row[iCol]));", + "", + " // diagonals :: [[a]] -> ([a], [a])", + " const diagonals = xs => {", + " const nRows = xs.length,", + " nCols = (nRows > 0 ? xs[0].length : 0);", + " const cell = (x, y) => xs[y][x];", + "", + " if (nRows === nCols) {", + " const ns = range(0, nCols - 1);", + " return [zipWith(cell, ns, ns), zipWith(cell, ns, reverse(ns))];", + " } else return [", + " [],", + " []", + " ];", + " };", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " const zipWith = (f, xs, ys) => {", + " const ny = ys.length;", + " return (xs.length <= ny ? xs : xs.slice(0, ny))", + " .map((x, i) => f(x, ys[i]));", + " }", + "", + " // reverse :: [a] -> [a]", + " const reverse = (xs) => xs.slice(0)", + " .reverse()", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // all :: (a -> Bool) -> [a] -> Bool", + " const all = (f, xs) => xs.every(f);", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x);", + "", + " // justifyRight :: Int -> Char -> Text -> Text", + " const justifyRight = (n, cFiller, strText) =>", + " n > strText.length ? (", + " (cFiller.repeat(n) + strText)", + " .slice(-n)", + " ) : strText;", + "", + " // TEST -----------------------------------------------------------------", + "", + " //return doubleEvenMagicSquare(8)", + "", + " return [4, 8, 12]", + " .map(n => {", + " const lines = doubleEvenMagicSquare(n);", + " const sums = lines.concat(", + " transpose(lines)", + " .concat(diagonals(lines))", + " )", + " .map(xs => xs.reduce((a, b) => a + b, 0));", + " const sum = sums[0];", + " return [", + " \"Order: \" + n.toString(),", + " \"Summing to: \" + sum.toString(),", + " \"Row, column and diagonal sums checked: \" +", + " all(x => x === sum, sums)", + " .toString() + '\\n',", + " lines.map(", + " xs => xs.map(", + " x => justifyRight(3, ' ', x.toString())", + " )", + " .join(' '))", + " .join('\\n')", + " ].join('\\n')", + " })", + " .join('\\n\\n');", + "})();", + "", + "{{Out}}", + "
    Order: 4",
    +        "Summing to: 34",
    +        "Row, column and diagonal sums checked: true",
    +        "",
    +        "  1   15   14    4",
    +        " 12    6    7    9",
    +        "  8   10   11    5",
    +        " 13    3    2   16",
    +        "",
    +        "Order: 8",
    +        "Summing to: 260",
    +        "Row, column and diagonal sums checked: true",
    +        "",
    +        "  1   63   62    4   60    6    7   57",
    +        " 56   10   11   53   13   51   50   16",
    +        " 48   18   19   45   21   43   42   24",
    +        " 25   39   38   28   36   30   31   33",
    +        " 32   34   35   29   37   27   26   40",
    +        " 41   23   22   44   20   46   47   17",
    +        " 49   15   14   52   12   54   55    9",
    +        "  8   58   59    5   61    3    2   64",
    +        "",
    +        "Order: 12",
    +        "Summing to: 870",
    +        "Row, column and diagonal sums checked: true",
    +        "",
    +        "  1  143  142    4    5  139  138    8    9  135  134   12",
    +        "132   14   15  129  128   18   19  125  124   22   23  121",
    +        "120   26   27  117  116   30   31  113  112   34   35  109",
    +        " 37  107  106   40   41  103  102   44   45   99   98   48",
    +        " 49   95   94   52   53   91   90   56   57   87   86   60",
    +        " 84   62   63   81   80   66   67   77   76   70   71   73",
    +        " 72   74   75   69   68   78   79   65   64   82   83   61",
    +        " 85   59   58   88   89   55   54   92   93   51   50   96",
    +        " 97   47   46  100  101   43   42  104  105   39   38  108",
    +        " 36  110  111   33   32  114  115   29   28  118  119   25",
    +        " 24  122  123   21   20  126  127   17   16  130  131   13",
    +        "133   11   10  136  137    7    6  140  141    3    2  144
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f03", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n 'use strict';\n\n // doubleEvenMagicSquare :: Int -> [[Int]]\n const doubleEvenMagicSquare = n => {\n if (n % 4 > 0) return undefined;\n\n // truthSeries :: Int -> [Int]\n const truthSeries = n => {\n if (n <= 0) return [true];\n const xs = truthSeries(n - 1);\n return xs.concat(xs.map(x => !x));\n };\n\n const sqr = n * n,\n scale = curry(replicate)(n / 4),\n power = Math.log2(sqr),\n sequence = isInt(power) ? truthSeries(power) : (\n flatten(\n scale(\n splitEvery(4, truthSeries(4))\n .map(scale)\n )\n )\n );\n\n return splitEvery(n, sequence\n .map((x, i) => x ? i + 1 : sqr - i));\n };\n\n\n // GENERIC FUNCTIONS ----------------------------------------------------\n\n // flatten :: Tree a -> [a]\n const flatten = t => (t instanceof Array ? concatMap(flatten, t) : [t]);\n\n // concatMap :: (a -> [b]) -> [a] -> [b]\n const concatMap = (f, xs) => [].concat.apply([], xs.map(f));\n\n // splitEvery :: Int -> [a] -> [][a]]\n const splitEvery = (n, xs) => {\n if (xs.length <= n) return [xs];\n const [h, t] = [xs.slice(0, n), xs.slice(n)];\n return [h].concat(splitEvery(n, t));\n }\n\n // curry :: ((a, b) -> c) -> a -> b -> c\n const curry = f => a => b => f(a, b);\n\n // replicate :: Int -> a -> [a]\n const replicate = (n, a) => {\n let v = [a],\n o = [];\n if (n < 1) return o;\n while (n > 1) {\n if (n & 1) o = o.concat(v);\n n >>= 1;\n v = v.concat(v);\n }\n return o.concat(v);\n };\n\n // isInt :: Int -> Bool\n const isInt = x => x === Math.floor(x);\n\n\n // TEST AND DISPLAY FUNCTIONS -------------------------------------------\n\n // transpose :: [[a]] -> [[a]]\n const transpose = xs =>\n xs[0].map((_, iCol) => xs.map((row) => row[iCol]));\n\n // diagonals :: [[a]] -> ([a], [a])\n const diagonals = xs => {\n const nRows = xs.length,\n nCols = (nRows > 0 ? xs[0].length : 0);\n const cell = (x, y) => xs[y][x];\n\n if (nRows === nCols) {\n const ns = range(0, nCols - 1);\n return [zipWith(cell, ns, ns), zipWith(cell, ns, reverse(ns))];\n } else return [\n [],\n []\n ];\n };\n\n // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]\n const zipWith = (f, xs, ys) => {\n const ny = ys.length;\n return (xs.length <= ny ? xs : xs.slice(0, ny))\n .map((x, i) => f(x, ys[i]));\n }\n\n // reverse :: [a] -> [a]\n const reverse = (xs) => xs.slice(0)\n .reverse()\n\n // range :: Int -> Int -> [Int]\n const range = (m, n) =>\n Array.from({\n length: Math.floor(n - m) + 1\n }, (_, i) => m + i);\n\n // all :: (a -> Bool) -> [a] -> Bool\n const all = (f, xs) => xs.every(f);\n\n // show :: a -> String\n const show = x => JSON.stringify(x);\n\n // justifyRight :: Int -> Char -> Text -> Text\n const justifyRight = (n, cFiller, strText) =>\n n > strText.length ? (\n (cFiller.repeat(n) + strText)\n .slice(-n)\n ) : strText;\n\n // TEST -----------------------------------------------------------------\n\n //return doubleEvenMagicSquare(8)\n\n return [4, 8, 12]\n .map(n => {\n const lines = doubleEvenMagicSquare(n);\n const sums = lines.concat(\n transpose(lines)\n .concat(diagonals(lines))\n )\n .map(xs => xs.reduce((a, b) => a + b, 0));\n const sum = sums[0];\n return [\n \"Order: \" + n.toString(),\n \"Summing to: \" + sum.toString(),\n \"Row, column and diagonal sums checked: \" +\n all(x => x === sum, sums)\n .toString() + '\\n',\n lines.map(\n xs => xs.map(\n x => justifyRight(3, ' ', x.toString())\n )\n .join(' '))\n .join('\\n')\n ].join('\\n')\n })\n .join('\\n\\n');\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Magic squares of odd order", + "type": "Waypoint", + "description": [ + "

    A magic square is an NxN square matrix whose numbers (usually integers) consist of consecutive numbers arranged so that the sum of each row and column, and both long (main) diagonals are equal to the same sum (which is called the magic number or magic constant).

    The numbers are usually (but not always) the first N2 positive integers.

    A magic square whose rows and columns add up to a magic number but whose main diagonals do not, is known as a semimagic square.

    {| style=\"float:right;border: 4px solid blue; background:lightgreen; color:black; margin-left:auto;margin-right:auto;text-align:center;width:15em;height:15em;table-layout:fixed;font-size:150%\"

    ", + "

    |-

    ", + "

    | 8 || 1 || 6

    ", + "

    |-

    ", + "

    | 3 || 5 || 7

    ", + "

    |-

    ", + "

    | 4 || 9 || 2

    ", + "

    |}

    ", + "Task

    For any odd N, generate a magic square with the integers 1 ──► N, and show the results here.

    Optionally, show the magic number.

    You should demonstrate the generator by showing at least a magic square for N = 5.

    ", + " Related tasks", + "Magic squares of singly even order", + "Magic squares of doubly even order See also:", + "MathWorld™ entry: Magic_square ", + "Odd Magic Squares (1728.org)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "{{trans|Mathematica}}", + "( and referring to http://www.jsoftware.com/papers/eem/magicsq.htm )", + "", + "(function () {", + "", + " // n -> [[n]]", + " function magic(n) {", + " return n % 2 ? rotation(", + " transposed(", + " rotation(", + " table(n)", + " )", + " )", + " ) : null;", + " }", + "", + " // [[a]] -> [[a]]", + " function rotation(lst) {", + " return lst.map(function (row, i) {", + " return rotated(", + " row, ((row.length + 1) / 2) - (i + 1)", + " );", + " })", + " }", + "", + " // [[a]] -> [[a]]", + " function transposed(lst) {", + " return lst[0].map(function (col, i) {", + " return lst.map(function (row) {", + " return row[i];", + " })", + " });", + " }", + "", + " // [a] -> n -> [a]", + " function rotated(lst, n) {", + " var lng = lst.length,", + " m = (typeof n === 'undefined') ? 1 : (", + " n < 0 ? lng + n : (n > lng ? n % lng : n)", + " );", + "", + " return m ? (", + " lst.slice(-m).concat(lst.slice(0, lng - m))", + " ) : lst;", + " }", + "", + " // n -> [[n]]", + " function table(n) {", + " var rngTop = rng(1, n);", + "", + " return rng(0, n - 1).map(function (row) {", + " return rngTop.map(function (x) {", + " return row * n + x;", + " });", + " });", + " }", + "", + " // [m..n]", + " function rng(m, n) {", + " return Array.apply(null, Array(n - m + 1)).map(", + " function (x, i) {", + " return m + i;", + " });", + " }", + "", + " /******************** TEST WITH 3, 5, 11 ***************************/", + "", + " // Results as right-aligned wiki tables", + " function wikiTable(lstRows, blnHeaderRow, strStyle) {", + " var css = strStyle ? 'style=\"' + strStyle + '\"' : '';", + "", + " return '{| class=\"wikitable\" ' + css + lstRows.map(", + " function (lstRow, iRow) {", + " var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|'),", + " strDbl = strDelim + strDelim;", + "", + " return '\\n|-\\n' + strDelim + ' ' + lstRow.join(' ' + strDbl + ' ');", + " }).join('') + '\\n|}';", + " }", + "", + " return [3, 5, 11].map(", + " function (n) {", + " var w = 2.5 * n;", + " return 'magic(' + n + ')\\n\\n' + wikiTable(", + " magic(n), false, 'text-align:center;width:' + w + 'em;height:' + w + 'em;table-layout:fixed;'", + " )", + " }", + " ).join('\\n\\n')", + "})();", + "", + "Output:", + "", + "magic(3)", + "", + "{| class=\"wikitable\" style=\"text-align:center;width:7.5em;height:7.5em;table-layout:fixed;\"", + "|-", + "| 8 || 3 || 4", + "|-", + "| 1 || 5 || 9", + "|-", + "| 6 || 7 || 2", + "|}", + "", + "magic(5)", + "", + "{| class=\"wikitable\" style=\"text-align:center;width:12.5em;height:12.5em;table-layout:fixed;\"", + "|-", + "| 17 || 23 || 4 || 10 || 11", + "|-", + "| 24 || 5 || 6 || 12 || 18", + "|-", + "| 1 || 7 || 13 || 19 || 25", + "|-", + "| 8 || 14 || 20 || 21 || 2", + "|-", + "| 15 || 16 || 22 || 3 || 9", + "|}", + "", + "magic(11)", + "", + "{| class=\"wikitable\" style=\"text-align:center;width:27.5em;height:27.5em;table-layout:fixed;\"", + "|-", + "| 68 || 80 || 92 || 104 || 116 || 7 || 19 || 31 || 43 || 55 || 56", + "|-", + "| 81 || 93 || 105 || 117 || 8 || 20 || 32 || 44 || 45 || 57 || 69", + "|-", + "| 94 || 106 || 118 || 9 || 21 || 33 || 34 || 46 || 58 || 70 || 82", + "|-", + "| 107 || 119 || 10 || 22 || 23 || 35 || 47 || 59 || 71 || 83 || 95", + "|-", + "| 120 || 11 || 12 || 24 || 36 || 48 || 60 || 72 || 84 || 96 || 108", + "|-", + "| 1 || 13 || 25 || 37 || 49 || 61 || 73 || 85 || 97 || 109 || 121", + "|-", + "| 14 || 26 || 38 || 50 || 62 || 74 || 86 || 98 || 110 || 111 || 2", + "|-", + "| 27 || 39 || 51 || 63 || 75 || 87 || 99 || 100 || 112 || 3 || 15", + "|-", + "| 40 || 52 || 64 || 76 || 88 || 89 || 101 || 113 || 4 || 16 || 28", + "|-", + "| 53 || 65 || 77 || 78 || 90 || 102 || 114 || 5 || 17 || 29 || 41", + "|-", + "| 66 || 67 || 79 || 91 || 103 || 115 || 6 || 18 || 30 || 42 || 54", + "|}", + "", + "===ES6===", + "====Cycled . transposed . cycled====", + "{{Trans|Haskell}} ", + "", + "(2nd Haskell version: ''cycledRows . transpose . cycledRows'')", + "(() => {", + "", + " // magicSquare :: Int -> [[Int]]", + " const magicSquare = n =>", + " n % 2 !== 0 ? (", + " compose([transpose, cycled, transpose, cycled, enumSquare])(n)", + " ) : [];", + "", + " // Size of square -> rows containing integers [1..]", + " // enumSquare :: Int -> [[Int]]", + " const enumSquare = n =>", + " chunksOf(n, enumFromTo(1, n * n));", + "", + " // Table of integers -> Table with rows rotated by descending deltas", + " // cycled :: [[Int]] -> [[Int]]", + " const cycled = rows => {", + " const d = Math.floor(rows.length / 2);", + " return zipWith(listCycle, enumFromTo(d, -d), rows)", + " };", + "", + " // Number of positions to shift to right -> List -> Wrap-cycled list", + " // listCycle :: Int -> [a] -> [a]", + " const listCycle = (n, xs) => {", + " const d = -(n % xs.length);", + " return (d !== 0 ? xs.slice(d)", + " .concat(xs.slice(0, d)) : xs);", + " };", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // chunksOf :: Int -> [a] -> [[a]]", + " const chunksOf = (n, xs) =>", + " xs.reduce((a, _, i, xs) =>", + " i % n ? a : a.concat([xs.slice(i, i + n)]), []);", + "", + " // compose :: [(a -> a)] -> (a -> a)", + " const compose = fs => x => fs.reduceRight((a, f) => f(a), x);", + "", + " // enumFromTo :: Int -> Int -> Maybe Int -> [Int]", + " const enumFromTo = (m, n, step) => {", + " const d = (step || 1) * (n >= m ? 1 : -1);", + " return Array.from({", + " length: Math.floor((n - m) / d) + 1", + " }, (_, i) => m + (i * d));", + " };", + "", + " // intercalate :: String -> [a] -> String", + " const intercalate = (s, xs) => xs.join(s);", + "", + " // min :: Ord a => a -> a -> a", + " const min = (a, b) => b < a ? b : a;", + "", + " // show :: a -> String", + " const show = JSON.stringify;", + "", + " // transpose :: [[a]] -> [[a]]", + " const transpose = xs =>", + " xs[0].map((_, iCol) => xs.map(row => row[iCol]));", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " const zipWith = (f, xs, ys) =>", + " Array.from({", + " length: min(xs.length, ys.length)", + " }, (_, i) => f(xs[i], ys[i]));", + "", + " // TEST -------------------------------------------------------------------", + " return intercalate('\\n\\n', [3, 5, 7]", + " .map(magicSquare)", + " .map(xs => unlines(xs.map(show))));", + "})();", + "{{Out}}", + "
    [8,1,6]",
    +        "[3,5,7]",
    +        "[4,9,2]",
    +        "",
    +        "[17,24,1,8,15]",
    +        "[23,5,7,14,16]",
    +        "[4,6,13,20,22]",
    +        "[10,12,19,21,3]",
    +        "[11,18,25,2,9]",
    +        "",
    +        "[30,39,48,1,10,19,28]",
    +        "[38,47,7,9,18,27,29]",
    +        "[46,6,8,17,26,35,37]",
    +        "[5,14,16,25,34,36,45]",
    +        "[13,15,24,33,42,44,4]",
    +        "[21,23,32,41,43,3,12]",
    +        "[22,31,40,49,2,11,20]
    ", + "", + "====Traditional 'Siamese' method====", + "Encoding the traditional [[wp:Siamese_method|'Siamese' method]]", + "{{Trans|Haskell}}", + "(() => {", + "", + " // Number of rows -> n rows of integers", + " // oddMagicTable :: Int -> [[Int]]", + " const oddMagicTable = n =>", + " mapAsTable(n, siamMap(quot(n, 2)));", + "", + " // Highest index of square -> Siam xys so far -> xy -> next xy coordinate", + " // nextSiam :: Int -> M.Map (Int, Int) Int -> (Int, Int) -> (Int, Int)", + " const nextSiam = (uBound, sMap, [x, y]) => {", + " const [a, b] = [x + 1, y - 1];", + " return (a > uBound && b < 0) ? (", + " [uBound, 1] // Move down if obstructed by corner", + " ) : a > uBound ? (", + " [0, b] // Wrap at right edge", + " ) : b < 0 ? (", + " [a, uBound] // Wrap at upper edge", + " ) : mapLookup(sMap, [a, b])", + " .nothing ? ( // Unimpeded default: one up one right", + " [a, b]", + " ) : [a - 1, b + 2]; // Position occupied: move down", + " };", + "", + " // Order of table -> Siamese indices keyed by coordinates", + " // siamMap :: Int -> M.Map (Int, Int) Int", + " const siamMap = n => {", + " const", + " uBound = 2 * n,", + " sPath = (uBound, sMap, xy, n) => {", + " const [x, y] = xy,", + " newMap = mapInsert(sMap, xy, n);", + " return (y == uBound && x == quot(uBound, 2) ? (", + " newMap", + " ) : sPath(", + " uBound, newMap, nextSiam(uBound, newMap, [x, y]), n + 1));", + " };", + " return sPath(uBound, {}, [n, 0], 1);", + " };", + "", + " // Size of square -> integers keyed by coordinates -> rows of integers", + " // mapAsTable :: Int -> M.Map (Int, Int) Int -> [[Int]]", + " const mapAsTable = (nCols, dct) => {", + " const axis = enumFromTo(0, nCols - 1);", + " return map(row => map(k => fromJust(mapLookup(dct, k)), row),", + " bind(axis, y => [bind(axis, x => [", + " [x, y]", + " ])]));", + " };", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // bind :: [a] -> (a -> [b]) -> [b]", + " const bind = (xs, f) => [].concat.apply([], xs.map(f));", + "", + " // curry :: Function -> Function", + " const curry = (f, ...args) => {", + " const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :", + " function () {", + " return go(xs.concat(Array.from(arguments)));", + " };", + " return go([].slice.call(args, 1));", + " };", + "", + " // enumFromTo :: Int -> Int -> [Int]", + " const enumFromTo = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // fromJust :: M a -> a", + " const fromJust = m => m.nothing ? {} : m.just;", + "", + " // fst :: [a, b] -> a", + " const fst = pair => pair.length === 2 ? pair[0] : undefined;", + "", + " // intercalate :: String -> [a] -> String", + " const intercalate = (s, xs) => xs.join(s);", + "", + " // justifyRight :: Int -> Char -> Text -> Text", + " const justifyRight = (n, cFiller, strText) =>", + " n > strText.length ? (", + " (cFiller.repeat(n) + strText)", + " .slice(-n)", + " ) : strText;", + "", + " // length :: [a] -> Int", + " const length = xs => xs.length;", + "", + " // log :: a -> IO ()", + " const log = (...args) =>", + " console.log(", + " args", + " .map(show)", + " .join(' -> ')", + " );", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = (f, xs) => xs.map(f);", + "", + " // mapInsert :: Dictionary -> k -> v -> Dictionary", + " const mapInsert = (dct, k, v) =>", + " (dct[(typeof k === 'string' && k) || show(k)] = v, dct);", + "", + " // mapKeys :: Map k a -> [k]", + " const mapKeys = dct =>", + " sortBy(mappendComparing([snd, fst]),", + " map(JSON.parse, Object.keys(dct)));", + "", + " // mapLookup :: Dictionary -> k -> Maybe v", + " const mapLookup = (dct, k) => {", + " const", + " v = dct[(typeof k === 'string' && k) || show(k)],", + " blnJust = (typeof v !== 'undefined');", + " return {", + " nothing: !blnJust,", + " just: v", + " };", + " };", + "", + " // mappendComparing :: [(a -> b)] -> (a -> a -> Ordering)", + " const mappendComparing = fs => (x, y) =>", + " fs.reduce((ord, f) => {", + " if (ord !== 0) return ord;", + " const", + " a = f(x),", + " b = f(y);", + " return a < b ? -1 : a > b ? 1 : 0", + " }, 0);", + "", + " // maximum :: [a] -> a", + " const maximum = xs =>", + " xs.reduce((a, x) => (x > a || a === undefined ? x : a), undefined);", + "", + " // Integral a => a -> a -> a", + " const quot = (n, m) => Math.floor(n / m);", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x);", + " //", + " // snd :: (a, b) -> b", + " const snd = tpl => Array.isArray(tpl) ? tpl[1] : undefined;", + " //", + " // sortBy :: (a -> a -> Ordering) -> [a] -> [a]", + " const sortBy = (f, xs) => xs.slice()", + " .sort(f);", + "", + " // table :: String -> [[String]] -> [String]", + " const table = (delim, rows) =>", + " map(curry(intercalate)(delim),", + " transpose(map(col =>", + " map(curry(justifyRight)(maximum(map(length, col)))(' '), col),", + " transpose(rows))));", + "", + " // transpose :: [[a]] -> [[a]]", + " const transpose = xs =>", + " xs[0].map((_, col) => xs.map(row => row[col]));", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + " // TEST -------------------------------------------------------------------", + "", + " return intercalate('\\n\\n',", + " bind([3, 5, 7],", + " n => unlines(table(\" \",", + " map(xs => map(show, xs), oddMagicTable(n))))));", + "})();", + "{{Out}}", + "
    8  1  6",
    +        "3  5  7",
    +        "4  9  2",
    +        "",
    +        "17  24   1   8  15",
    +        "23   5   7  14  16",
    +        " 4   6  13  20  22",
    +        "10  12  19  21   3",
    +        "11  18  25   2   9",
    +        "",
    +        "30  39  48   1  10  19  28",
    +        "38  47   7   9  18  27  29",
    +        "46   6   8  17  26  35  37",
    +        " 5  14  16  25  34  36  45",
    +        "13  15  24  33  42  44   4",
    +        "21  23  32  41  43   3  12",
    +        "22  31  40  49   2  11  20
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f04", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function () {\n\n // n -> [[n]]\n function magic(n) {\n return n % 2 ? rotation(\n transposed(\n rotation(\n table(n)\n )\n )\n ) : null;\n }\n\n // [[a]] -> [[a]]\n function rotation(lst) {\n return lst.map(function (row, i) {\n return rotated(\n row, ((row.length + 1) / 2) - (i + 1)\n );\n })\n }\n\n // [[a]] -> [[a]]\n function transposed(lst) {\n return lst[0].map(function (col, i) {\n return lst.map(function (row) {\n return row[i];\n })\n });\n }\n\n // [a] -> n -> [a]\n function rotated(lst, n) {\n var lng = lst.length,\n m = (typeof n === 'undefined') ? 1 : (\n n < 0 ? lng + n : (n > lng ? n % lng : n)\n );\n\n return m ? (\n lst.slice(-m).concat(lst.slice(0, lng - m))\n ) : lst;\n }\n\n // n -> [[n]]\n function table(n) {\n var rngTop = rng(1, n);\n\n return rng(0, n - 1).map(function (row) {\n return rngTop.map(function (x) {\n return row * n + x;\n });\n });\n }\n\n // [m..n]\n function rng(m, n) {\n return Array.apply(null, Array(n - m + 1)).map(\n function (x, i) {\n return m + i;\n });\n }\n\n /******************** TEST WITH 3, 5, 11 ***************************/\n\n // Results as right-aligned wiki tables\n function wikiTable(lstRows, blnHeaderRow, strStyle) {\n var css = strStyle ? 'style=\"' + strStyle + '\"' : '';\n\n return '{| class=\"wikitable\" ' + css + lstRows.map(\n function (lstRow, iRow) {\n var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|'),\n strDbl = strDelim + strDelim;\n\n return '\\n|-\\n' + strDelim + ' ' + lstRow.join(' ' + strDbl + ' ');\n }).join('') + '\\n|}';\n }\n\n return [3, 5, 11].map(\n function (n) {\n var w = 2.5 * n;\n return 'magic(' + n + ')\\n\\n' + wikiTable(\n magic(n), false, 'text-align:center;width:' + w + 'em;height:' + w + 'em;table-layout:fixed;'\n )\n }\n ).join('\\n\\n')\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Magic squares of singly even order", + "type": "Waypoint", + "description": [ + "

    A magic square is an NxN square matrix whose numbers consist of consecutive numbers arranged so that the sum of each row and column, and both diagonals are equal to the same sum (which is called the magic number or magic constant).

    A magic square of singly even order has a size that is a multiple of 4, plus 2 (e.g. 6, 10, 14). This means that the subsquares have an odd size, which plays a role in the construction.

    ", + "Task", + "

    Create a magic square of 6 x 6.

    ", + " Related tasks", + "Magic squares of odd order", + "Magic squares of doubly even order", + " See also", + "Singly Even Magic Squares (1728.org)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f05", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Main step of GOST 28147-89", + "type": "Waypoint", + "description": [ + "

    GOST 28147-89 is a standard symmetric encryption based on a Feistel network. Structure of the algorithm consists of three levels:

    encryption modes - simple replacement, application range, imposing a range of feedback and authentication code generation;", + "cycles - 32-З, 32-Р and 16-З, is a repetition of the main step;", + "main step, a function that takes a 64-bit block of text and one of the eight 32-bit encryption key elements, and uses the replacement table (8x16 matrix of 4-bit values), and returns encrypted block.", + "

    Implement the main step of this encryption algorithm.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "var Таблица_замен = [", + " [ 4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3],", + " [14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9],", + " [ 5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11],", + " [ 7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3],", + " [ 6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2],", + " [ 4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14],", + " [13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12],", + " [ 1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12]];", + "", + "function ОсновнойШаг(блок_текста, элемент_ключа) {", + " var N = блок_текста.slice(0);", + " var X = элемент_ключа;", + " var S = (N[0] + X) & 0xFFFFFFFF;", + " var ячейка; var нов_S = 0;", + " for (var сч = 0; сч < 4; сч++) {", + " ячейка = (S >>> (сч << 3)) & 0xFF;", + " нов_S += (Таблица_замен[сч*2][ячейка & 0x0F] + (Таблица_замен[сч*2+1][ячейка >>> 4] << 4)) << (сч << 3);", + " }", + " S = (((нов_S << 11) + (нов_S >>> 21)) & 0xFFFFFFFF) ^ N[1];", + " N[1] = N[0]; N[0] = S;", + " return N;", + "}", + "", + "Note: the variable \"блок_текста\" is an array of two 32-bit values that make up the block.", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f06", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var Таблица_замен = [\n [ 4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3],\n [14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9],\n [ 5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11],\n [ 7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3],\n [ 6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2],\n [ 4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14],\n [13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12],\n [ 1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12]];\n\nfunction ОсновнойШаг(блок_текста, элемент_ключа) {\n var N = блок_текста.slice(0);\n var X = элемент_ключа;\n var S = (N[0] + X) & 0xFFFFFFFF;\n var ячейка; var нов_S = 0;\n for (var сч = 0; сч < 4; сч++) {\n ячейка = (S >>> (сч << 3)) & 0xFF;\n нов_S += (Таблица_замен[сч*2][ячейка & 0x0F] + (Таблица_замен[сч*2+1][ячейка >>> 4] << 4)) << (сч << 3);\n }\n S = (((нов_S << 11) + (нов_S >>> 21)) & 0xFFFFFFFF) ^ N[1];\n N[1] = N[0]; N[0] = S;\n return N;\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Make directory path", + "type": "Waypoint", + "description": [ + "Task:", + "

    Create a directory and any missing parents.

    This task is named after the posix mkdir -p command, and several libraries which implement the same behavior.

    Please implement a function of a single path string (for example ./path/to/dir) which has the above side-effect.

    ", + "

    If the directory already exists, return successfully.

    ", + "

    Ideally implementations will work equally well cross-platform (on windows, linux, and OS X).

    It's likely that your language implements such a function as part of its standard library. If so, please also show how such a function would be implemented.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|Node.js}}", + "", + "Simplified version of the popular [https://www.npmjs.org/package/mkdirp mkdirp library]:", + "", + "var path = require('path');", + "var fs = require('fs');", + "", + "function mkdirp (p, cb) {", + " cb = cb || function () {};", + " p = path.resolve(p);", + "", + " fs.mkdir(p, function (er) {", + " if (!er) {", + " return cb(null);", + " }", + " switch (er.code) {", + " case 'ENOENT':", + " // The directory doesn't exist. Make its parent and try again.", + " mkdirp(path.dirname(p), function (er) {", + " if (er) cb(er);", + " else mkdirp(p, cb);", + " });", + " break;", + "", + " // In the case of any other error, something is borked.", + " default:", + " cb(er);", + " break;", + " }", + " });", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f07", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var path = require('path');\nvar fs = require('fs');\n\nfunction mkdirp (p, cb) {\n cb = cb || function () {};\n p = path.resolve(p);\n\n fs.mkdir(p, function (er) {\n if (!er) {\n return cb(null);\n }\n switch (er.code) {\n case 'ENOENT':\n // The directory doesn't exist. Make its parent and try again.\n mkdirp(path.dirname(p), function (er) {\n if (er) cb(er);\n else mkdirp(p, cb);\n });\n break;\n\n // In the case of any other error, something is borked.\n default:\n cb(er);\n break;\n }\n });\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Mandelbrot set", + "type": "Waypoint", + "description": [ + "Task:", + "

    Generate and draw the Mandelbrot set.

    ", + "

    Note that there are many algorithms to draw Mandelbrot set and there are many functions which generate it .

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|Firefox|3.5.11}}", + "", + "This needs the canvas tag of HTML 5 (it will not run on IE8 and lower or old browsers).", + "", + "The code can be run directly from the Javascript console in modern browsers by copying and pasting it.", + "", + "function mandelIter(cx, cy, maxIter) {", + " var x = 0.0;", + " var y = 0.0;", + " var xx = 0;", + " var yy = 0;", + " var xy = 0;", + "", + " var i = maxIter;", + " while (i-- && xx + yy <= 4) {", + " xy = x * y;", + " xx = x * x;", + " yy = y * y;", + " x = xx - yy + cx;", + " y = xy + xy + cy;", + " }", + " return maxIter - i;", + "}", + "", + "function mandelbrot(canvas, xmin, xmax, ymin, ymax, iterations) {", + " var width = canvas.width;", + " var height = canvas.height;", + "", + " var ctx = canvas.getContext('2d');", + " var img = ctx.getImageData(0, 0, width, height);", + " var pix = img.data;", + " ", + " for (var ix = 0; ix < width; ++ix) {", + " for (var iy = 0; iy < height; ++iy) {", + " var x = xmin + (xmax - xmin) * ix / (width - 1);", + " var y = ymin + (ymax - ymin) * iy / (height - 1);", + " var i = mandelIter(x, y, iterations);", + " var ppos = 4 * (width * iy + ix);", + " ", + " if (i > iterations) {", + " pix[ppos] = 0;", + " pix[ppos + 1] = 0;", + " pix[ppos + 2] = 0;", + " } else {", + " var c = 3 * Math.log(i) / Math.log(iterations - 1.0);", + " ", + " if (c < 1) {", + " pix[ppos] = 255 * c;", + " pix[ppos + 1] = 0;", + " pix[ppos + 2] = 0;", + " }", + " else if ( c < 2 ) {", + " pix[ppos] = 255;", + " pix[ppos + 1] = 255 * (c - 1);", + " pix[ppos + 2] = 0;", + " } else {", + " pix[ppos] = 255;", + " pix[ppos + 1] = 255;", + " pix[ppos + 2] = 255 * (c - 2);", + " }", + " }", + " pix[ppos + 3] = 255;", + " }", + " }", + " ", + " ctx.putImageData(img, 0, 0);", + "}", + "", + "var canvas = document.createElement('canvas');", + "canvas.width = 900;", + "canvas.height = 600;", + "", + "document.body.insertBefore(canvas, document.body.childNodes[0]);", + "", + "mandelbrot(canvas, -2, 1, -1, 1, 1000);", + "", + "{{out}} with default parameters:", + "[[File:Mandelbrot-Javascript.png]]", + "", + "=== ES6/WebAssembly ===", + "", + "With ES6 and WebAssembly, the program can run faster. Of course, this requires a compiled WASM file, but one can easily build", + "one for instance with the [https://mbebenita.github.io/WasmExplorer/ WebAssembly explorer]", + "", + "var mandelIter;", + "fetch(\"./mandelIter.wasm\")", + " .then(res => {", + " if (res.ok) return res.arrayBuffer();", + " throw new Error('Unable to fetch WASM.');", + " })", + " .then(bytes => { return WebAssembly.compile(bytes); })", + " .then(module => { return WebAssembly.instantiate(module); })", + " .then(instance => { WebAssembly.instance = instance; draw(); })", + "", + "function mandelbrot(canvas, xmin, xmax, ymin, ymax, iterations) {", + " // ...", + " var i = WebAssembly.instance.exports.mandelIter(x, y, iterations);", + " // ...", + "}", + "", + "function draw() {", + " // canvas initialization if necessary", + " // ...", + " mandelbrot(canvas, -2, 1, -1, 1, 1000);", + " // ...", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f08", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function mandelIter(cx, cy, maxIter) {\n var x = 0.0;\n var y = 0.0;\n var xx = 0;\n var yy = 0;\n var xy = 0;\n\n var i = maxIter;\n while (i-- && xx + yy <= 4) {\n xy = x * y;\n xx = x * x;\n yy = y * y;\n x = xx - yy + cx;\n y = xy + xy + cy;\n }\n return maxIter - i;\n}\n\nfunction mandelbrot(canvas, xmin, xmax, ymin, ymax, iterations) {\n var width = canvas.width;\n var height = canvas.height;\n\n var ctx = canvas.getContext('2d');\n var img = ctx.getImageData(0, 0, width, height);\n var pix = img.data;\n \n for (var ix = 0; ix < width; ++ix) {\n for (var iy = 0; iy < height; ++iy) {\n var x = xmin + (xmax - xmin) * ix / (width - 1);\n var y = ymin + (ymax - ymin) * iy / (height - 1);\n var i = mandelIter(x, y, iterations);\n var ppos = 4 * (width * iy + ix);\n \n if (i > iterations) {\n pix[ppos] = 0;\n pix[ppos + 1] = 0;\n pix[ppos + 2] = 0;\n } else {\n var c = 3 * Math.log(i) / Math.log(iterations - 1.0);\n \n if (c < 1) {\n pix[ppos] = 255 * c;\n pix[ppos + 1] = 0;\n pix[ppos + 2] = 0;\n }\n else if ( c < 2 ) {\n pix[ppos] = 255;\n pix[ppos + 1] = 255 * (c - 1);\n pix[ppos + 2] = 0;\n } else {\n pix[ppos] = 255;\n pix[ppos + 1] = 255;\n pix[ppos + 2] = 255 * (c - 2);\n }\n }\n pix[ppos + 3] = 255;\n }\n }\n \n ctx.putImageData(img, 0, 0);\n}\n\nvar canvas = document.createElement('canvas');\ncanvas.width = 900;\ncanvas.height = 600;\n\ndocument.body.insertBefore(canvas, document.body.childNodes[0]);\n\nmandelbrot(canvas, -2, 1, -1, 1, 1000);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Man or boy test", + "type": "Waypoint", + "description": [ + "

    Background: The man or boy test was proposed by computer scientist Donald Knuth as a means of evaluating implementations of the ALGOL 60 programming language. The aim of the test was to distinguish compilers that correctly implemented \"recursion and non-local references\" from those that did not.

    ", + "

    I have written the following simple routine, which may separate the 'man-compilers' from the 'boy-compilers' — Donald Knuth

    Task: Imitate Knuth's example in Algol 60 in another language, as far as possible.

    Details: Local variables of routines are often kept in activation records (also call frames). In many languages, these records are kept on a call stack. In Algol (and e.g. in Smalltalk), they are allocated on a heap instead. Hence it is possible to pass references to routines that still can use and update variables from their call environment, even if the routine where those variables are declared already returned. This difference in implementations is sometimes called the Funarg Problem.

    In Knuth's example, each call to A allocates an activation record for the variable A. When B is called from A, any access to k now refers to this activation record. Now B in turn calls A, but passes itself as an argument. This argument remains bound to the activation record. This call to A also \"shifts\" the variables xi by one place, so eventually the argument B (still bound to its particular

    ", + "

    activation record) will appear as x4 or x5 in a call to A. If this happens when the expression x4 + x5 is evaluated, then this will again call B, which in turn will update k in the activation record it was originally bound to. As this activation record is shared with other instances of calls to A and B, it will influence the whole computation.

    So all the example does is to set up a convoluted calling structure, where updates to k can influence the behavior

    ", + "

    in completely different parts of the call tree.

    Knuth used this to test the correctness of the compiler, but one can of course also use it to test that other languages can emulate the Algol behavior correctly. If the handling of activation records is correct, the computed value will be −67.

    Performance and Memory: Man or Boy is intense and can be pushed to challenge any machine. Memory (both stack and heap) not CPU time is the constraining resource as the recursion creates a proliferation activation records which will quickly exhaust memory and present itself through a stack error. Each language may have ways of adjusting the amount of memory or increasing the recursion depth. Optionally, show how you would make such adjustments.

    The table below shows the result, call depths, and total calls for a range of k:

    ", + "

    {| style=\"font-size: 85%\"

    ", + "

    ! k

    ", + "

    ! 0

    ", + "

    ! 1

    ", + "

    ! 2

    ", + "

    ! 3

    ", + "

    ! 4

    ", + "

    ! 5

    ", + "

    ! 6

    ", + "

    ! 7

    ", + "

    ! 8

    ", + "

    ! 9

    ", + "

    ! 10

    ", + "

    ! 11

    ", + "

    ! 12

    ", + "

    ! 13

    ", + "

    ! 14

    ", + "

    ! 15

    ", + "

    ! 16

    ", + "

    ! 17

    ", + "

    ! 18

    ", + "

    ! 19

    ", + "

    ! 20

    ", + "

    ! 21

    ", + "

    ! 22

    ", + "

    ! 23

    ", + "

    ! 24

    ", + "

    ! 25

    ", + "

    ! 26

    ", + "

    ! 27

    ", + "

    ! 28

    ", + "

    ! 29

    ", + "

    ! 30

    ", + "

    |-

    ", + "

    ! A

    ", + "

    |align=\"right\"| 1

    ", + "

    |align=\"right\"| 0

    ", + "

    |align=\"right\"| -2

    ", + "

    |align=\"right\"| 0

    ", + "

    |align=\"right\"| 1

    ", + "

    |align=\"right\"| 0

    ", + "

    |align=\"right\"| 1

    ", + "

    |align=\"right\"| -1

    ", + "

    |align=\"right\"| -10

    ", + "

    |align=\"right\"| -30

    ", + "

    |align=\"right\"| -67

    ", + "

    |align=\"right\"| -138

    ", + "

    |align=\"right\"| -291

    ", + "

    |align=\"right\"| -642

    ", + "

    |align=\"right\"| -1,446

    ", + "

    |align=\"right\"| -3,250

    ", + "

    |align=\"right\"| -7,244

    ", + "

    |align=\"right\"| -16,065

    ", + "

    |align=\"right\"| -35,601

    ", + "

    |align=\"right\"| -78,985

    ", + "

    |align=\"right\"| -175,416

    ", + "

    |align=\"right\"| -389,695

    ", + "

    |align=\"right\"| -865,609

    ", + "

    |align=\"right\"| -1,922,362

    ", + "

    |align=\"right\"| -4,268,854

    ", + "

    |align=\"right\"| -9,479,595

    ", + "

    |align=\"right\"| -21,051,458

    ", + "

    |align=\"right\"| -46,750,171

    ", + "

    |align=\"right\"| -103,821,058

    ", + "

    |align=\"right\"| -230,560,902

    ", + "

    |align=\"right\"| -512,016,658

    ", + "

    |-

    ", + "

    ! A called

    ", + "

    |align=\"right\"| 1

    ", + "

    |align=\"right\"| 2

    ", + "

    |align=\"right\"| 3

    ", + "

    |align=\"right\"| 4

    ", + "

    |align=\"right\"| 8

    ", + "

    |align=\"right\"| 18

    ", + "

    |align=\"right\"| 38

    ", + "

    |align=\"right\"| 80

    ", + "

    |align=\"right\"| 167

    ", + "

    |align=\"right\"| 347

    ", + "

    |align=\"right\"| 722

    ", + "

    |align=\"right\"| 1,509

    ", + "

    |align=\"right\"| 3,168

    ", + "

    |align=\"right\"| 6,673

    ", + "

    |align=\"right\"| 14,091

    ", + "

    |align=\"right\"| 29,825

    ", + "

    |align=\"right\"| 63,287

    ", + "

    |align=\"right\"| 134,652

    ", + "

    |align=\"right\"| 287,264

    ", + "

    |align=\"right\"| 614,442

    ", + "

    |align=\"right\"| 1,317,533

    ", + "

    |align=\"right\"| 2,831,900

    ", + "

    |align=\"right\"| 6,100,852

    ", + "

    |align=\"right\"| 13,172,239

    ", + "

    |align=\"right\"| 28,499,827

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |-

    ", + "

    ! A depth

    ", + "

    |align=\"right\"| 1

    ", + "

    |align=\"right\"| 2

    ", + "

    |align=\"right\"| 3

    ", + "

    |align=\"right\"| 4

    ", + "

    |align=\"right\"| 8

    ", + "

    |align=\"right\"| 16

    ", + "

    |align=\"right\"| 32

    ", + "

    |align=\"right\"| 64

    ", + "

    |align=\"right\"| 128

    ", + "

    |align=\"right\"| 256

    ", + "

    |align=\"right\"| 512

    ", + "

    |align=\"right\"| 1,024

    ", + "

    |align=\"right\"| 2,048

    ", + "

    |align=\"right\"| 4,096

    ", + "

    |align=\"right\"| 8,192

    ", + "

    |align=\"right\"| 16,384

    ", + "

    |align=\"right\"| 32,768

    ", + "

    |align=\"right\"| 65,536

    ", + "

    |align=\"right\"| 131,072

    ", + "

    |align=\"right\"| 262,144

    ", + "

    |align=\"right\"| 524,288

    ", + "

    |align=\"right\"| 1,048,576

    ", + "

    |align=\"right\"| 2,097,152

    ", + "

    |align=\"right\"| 4,194,304

    ", + "

    |align=\"right\"| 8,388,608

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |-

    ", + "

    ! B called

    ", + "

    |align=\"right\"| 0

    ", + "

    |align=\"right\"| 1

    ", + "

    |align=\"right\"| 2

    ", + "

    |align=\"right\"| 3

    ", + "

    |align=\"right\"| 7

    ", + "

    |align=\"right\"| 17

    ", + "

    |align=\"right\"| 37

    ", + "

    |align=\"right\"| 79

    ", + "

    |align=\"right\"| 166

    ", + "

    |align=\"right\"| 346

    ", + "

    |align=\"right\"| 721

    ", + "

    |align=\"right\"| 1,508

    ", + "

    |align=\"right\"| 3,167

    ", + "

    |align=\"right\"| 6,672

    ", + "

    |align=\"right\"| 14,090

    ", + "

    |align=\"right\"| 29,824

    ", + "

    |align=\"right\"| 63,286

    ", + "

    |align=\"right\"| 134,651

    ", + "

    |align=\"right\"| 287,263

    ", + "

    |align=\"right\"| 614,441

    ", + "

    |align=\"right\"| 1,317,532

    ", + "

    |align=\"right\"| 2,831,899

    ", + "

    |align=\"right\"| 6,100,851

    ", + "

    |align=\"right\"| 13,172,238

    ", + "

    |align=\"right\"| 28,499,826

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |-

    ", + "

    ! B depth

    ", + "

    |align=\"right\"| 0

    ", + "

    |align=\"right\"| 1

    ", + "

    |align=\"right\"| 2

    ", + "

    |align=\"right\"| 3

    ", + "

    |align=\"right\"| 7

    ", + "

    |align=\"right\"| 15

    ", + "

    |align=\"right\"| 31

    ", + "

    |align=\"right\"| 63

    ", + "

    |align=\"right\"| 127

    ", + "

    |align=\"right\"| 255

    ", + "

    |align=\"right\"| 511

    ", + "

    |align=\"right\"| 1,023

    ", + "

    |align=\"right\"| 2,047

    ", + "

    |align=\"right\"| 4,095

    ", + "

    |align=\"right\"| 8,191

    ", + "

    |align=\"right\"| 16,383

    ", + "

    |align=\"right\"| 32,767

    ", + "

    |align=\"right\"| 65,535

    ", + "

    |align=\"right\"| 131,071

    ", + "

    |align=\"right\"| 262,143

    ", + "

    |align=\"right\"| 524,287

    ", + "

    |align=\"right\"| 1,048,575

    ", + "

    |align=\"right\"| 2,097,151

    ", + "

    |align=\"right\"| 4,194,303

    ", + "

    |align=\"right\"| 8,388,607

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |

    ", + "

    |}

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "In Chrome we get a \"Maximum call stack size exceeded\" when a > 13. In Firefox we get \"too much recursion\" when a > 12.", + "function a(k, x1, x2, x3, x4, x5) {", + " function b() {", + " k -= 1;", + " return a(k, b, x1, x2, x3, x4);", + " }", + " return (k > 0) ? b() : x4() + x5();", + "}", + "", + "// this uses lambda wrappers around the numeric arguments", + "function x(n) {", + " return function () {", + " return n;", + " };", + "}", + "alert(a(10, x(1), x(-1), x(-1), x(1), x(0)));", + "", + "Implemented using ES6 syntax", + "var x = n => () => n;", + "", + "var a = (k, x1, x2, x3, x4, x5) => {", + " var b = () => return a(--k, b, x1, x2, x3, x4); //decrement k before use", + " return (k > 0) ? b() : x4() + x5();", + "};", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f09", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function a(k, x1, x2, x3, x4, x5) {\n function b() {\n k -= 1;\n return a(k, b, x1, x2, x3, x4);\n }\n return (k > 0) ? b() : x4() + x5();\n}\n\n// this uses lambda wrappers around the numeric arguments\nfunction x(n) {\n return function () {\n return n;\n };\n}\nalert(a(10, x(1), x(-1), x(-1), x(1), x(0)));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Map range", + "type": "Waypoint", + "description": [ + "

    Given two ranges:

    ", + "

    ::* $[a_1,a_2]$ and

    ", + "

    ::* $[b_1,b_2]$;

    ", + "

    ::* then a value $s$ in range $[a_1,a_2]$

    ", + "

    ::* is linearly mapped to a value $t$ in range $[b_1,b_2]$

    ", + " where: ", + "

    ::* $t = b_1 + {(s - a_1)(b_2 - b_1) \\over (a_2 - a_1)}$

    ", + "Task:", + "

    Write a function/subroutine/... that takes two ranges and a real number, and returns the mapping of the real number from the first to the second range.

    Use this function to map values from the range [0, 10] to the range [-1, 0].

    ", + "Extra credit:", + "

    Show additional idiomatic ways of performing the mapping, using tools available to the language.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "// Javascript doesn't have built-in support for ranges", + "// Insted we use arrays of two elements to represent ranges", + "var mapRange = function(from, to, s) {", + " return to[0] + (s - from[0]) * (to[1] - to[0]) / (from[1] - from[0]);", + "};", + "", + "var range = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];", + "for (var i = 0; i < range.length; i++) {", + " range[i] = mapRange([0, 10], [-1, 0], range[i]);", + "}", + "", + "console.log(range);", + "{{out}}", + "
    [-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.30000000000000004, -0.19999999999999996, -0.09999999999999998, 0]
    ", + "", + "=== Extra credit ===", + "Here we will use the [https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map ECMAScript 5 support for map] and the [http://underscorejs.org/#range _.range] function from Underscore.js.", + "{{libheader|Underscore.js}}", + "var mapRange = function(from, to, s) {", + " // mapRange expects ranges generated by _.range", + " var a1 = from[0];", + " var a2 = from[from.length - 1];", + " var b1 = to[0];", + " var b2 = to[to.length - 1];", + " return b1 + (s - a1) * (b2 - b1) / (a2 - a1);", + "};", + "", + "// The range function is exclusive", + "var fromRange = _.range(0, 11);", + "var toRange = _.range(-1, 1);", + "", + "// .map constructs a new array", + "fromRange = fromRange.map(function(s) {", + " return mapRange(fromRange, toRange, s);", + "});", + "", + "console.log(fromRange);", + "{{out}}", + "
    [-1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.30000000000000004, -0.19999999999999996, -0.09999999999999998, 0]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f0a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// Javascript doesn't have built-in support for ranges\n// Insted we use arrays of two elements to represent ranges\nvar mapRange = function(from, to, s) {\n return to[0] + (s - from[0]) * (to[1] - to[0]) / (from[1] - from[0]);\n};\n\nvar range = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\nfor (var i = 0; i < range.length; i++) {\n range[i] = mapRange([0, 10], [-1, 0], range[i]);\n}\n\nconsole.log(range);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Matrix arithmetic", + "type": "Waypoint", + "description": [ + "

    For a given matrix, return the determinant and the permanent of the matrix.

    The determinant is given by

    ", + "

    : $\\det(A) = \\sum_\\sigma\\sgn(\\sigma)\\prod_{i=1}^n M_{i,\\sigma_i}$

    ", + "

    while the permanent is given by

    ", + "

    : $ \\operatorname{perm}(A)=\\sum_\\sigma\\prod_{i=1}^n M_{i,\\sigma_i}$

    ", + "

    In both cases the sum is over the permutations $\\sigma$ of the permutations of 1, 2, ..., n. (A permutation's sign is 1 if there are an even number of inversions and -1 otherwise; see parity of a permutation.)

    More efficient algorithms for the determinant are known: LU decomposition, see for example [[wp:LU decomposition#Computing the determinant]]. Efficient methods for calculating the permanent are not known.

    Cf.:", + "Permutations by swapping" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f0b", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Matrix-exponentiation operator", + "type": "Waypoint", + "description": [ + "

    Most programming languages have a built-in implementation of exponentiation for integers and reals only.

    ", + "

    Demonstrate how to implement matrix exponentiation as an operator.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|SpiderMonkey}} for the print() and ''Array''.forEach() functions.", + "", + "Extends [[Matrix Transpose#JavaScript]] and [[Matrix multiplication#JavaScript]]", + "// IdentityMatrix is a \"subclass\" of Matrix", + "function IdentityMatrix(n) {", + " this.height = n;", + " this.width = n;", + " this.mtx = [];", + " for (var i = 0; i < n; i++) {", + " this.mtx[i] = [];", + " for (var j = 0; j < n; j++) {", + " this.mtx[i][j] = (i == j ? 1 : 0);", + " }", + " }", + "}", + "IdentityMatrix.prototype = Matrix.prototype;", + "", + "// the Matrix exponentiation function", + "// returns a new matrix", + "Matrix.prototype.exp = function(n) {", + " var result = new IdentityMatrix(this.height);", + " for (var i = 1; i <= n; i++) {", + " result = result.mult(this);", + " }", + " return result;", + "}", + "", + "var m = new Matrix([[3, 2], [2, 1]]);", + "[0,1,2,3,4,10].forEach(function(e){print(m.exp(e)); print()})", + "output", + "
    1,0",
    +        "0,1",
    +        "",
    +        "3,2",
    +        "2,1",
    +        "",
    +        "13,8",
    +        "8,5",
    +        "",
    +        "55,34",
    +        "34,21",
    +        "",
    +        "233,144",
    +        "144,89",
    +        "",
    +        "1346269,832040",
    +        "832040,514229",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f0c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// IdentityMatrix is a \"subclass\" of Matrix\nfunction IdentityMatrix(n) {\n this.height = n;\n this.width = n;\n this.mtx = [];\n for (var i = 0; i < n; i++) {\n this.mtx[i] = [];\n for (var j = 0; j < n; j++) {\n this.mtx[i][j] = (i == j ? 1 : 0);\n }\n }\n}\nIdentityMatrix.prototype = Matrix.prototype;\n\n// the Matrix exponentiation function\n// returns a new matrix\nMatrix.prototype.exp = function(n) {\n var result = new IdentityMatrix(this.height);\n for (var i = 1; i <= n; i++) {\n result = result.mult(this);\n }\n return result;\n}\n\nvar m = new Matrix([[3, 2], [2, 1]]);\n[0,1,2,3,4,10].forEach(function(e){print(m.exp(e)); print()})\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Matrix multiplication", + "type": "Waypoint", + "description": [ + "Task:", + "

    Multiply two matrices together.

    They can be of any dimensions, so long as the number of columns of the first matrix is equal to the number of rows of the second matrix.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "====Iterative====", + "{{works with|SpiderMonkey}} for the print() function", + "", + "Extends [[Matrix Transpose#JavaScript]]", + "// returns a new matrix", + "Matrix.prototype.mult = function(other) {", + " if (this.width != other.height) {", + " throw \"error: incompatible sizes\";", + " }", + "", + " var result = [];", + " for (var i = 0; i < this.height; i++) {", + " result[i] = [];", + " for (var j = 0; j < other.width; j++) {", + " var sum = 0;", + " for (var k = 0; k < this.width; k++) {", + " sum += this.mtx[i][k] * other.mtx[k][j];", + " }", + " result[i][j] = sum;", + " }", + " }", + " return new Matrix(result); ", + "}", + "", + "var a = new Matrix([[1,2],[3,4]])", + "var b = new Matrix([[-3,-8,3],[-2,1,4]]);", + "print(a.mult(b));", + "{{out}}", + "
    -7,-6,11",
    +        "-17,-20,25
    ", + "", + "====Functional====", + "(function () {", + " 'use strict';", + "", + " // matrixMultiply:: [[n]] -> [[n]] -> [[n]] ", + " function matrixMultiply(a, b) {", + " var bCols = transpose(b);", + "", + " return a.map(function (aRow) {", + " return bCols.map(function (bCol) {", + " return dotProduct(aRow, bCol);", + " });", + " });", + " }", + " ", + " // [[n]] -> [[n]] -> [[n]]", + " function dotProduct(xs, ys) {", + " return sum(zipWith(product, xs, ys));", + " }", + "", + " return matrixMultiply(", + " [[-1, 1, 4],", + " [ 6, -4, 2],", + " [-3, 5, 0],", + " [ 3, 7, -2]],", + "", + " [[-1, 1, 4, 8],", + " [ 6, 9, 10, 2],", + " [11, -4, 5, -3]]", + " );", + "", + " // --> [[51, -8, 26, -18], [-8, -38, -6, 34], ", + " // [33, 42, 38, -14], [17, 74, 72, 44]]", + "", + "", + " // GENERIC LIBRARY FUNCTIONS", + "", + " // (a -> b -> c) -> [a] -> [b] -> [c]", + " function zipWith(f, xs, ys) {", + " return xs.length === ys.length ? (", + " xs.map(function (x, i) {", + " return f(x, ys[i]);", + " })", + " ) : undefined;", + " }", + "", + " // [[a]] -> [[a]]", + " function transpose(lst) {", + " return lst[0].map(function (_, iCol) {", + " return lst.map(function (row) {", + " return row[iCol];", + " });", + " });", + " }", + "", + " // sum :: (Num a) => [a] -> a", + " function sum(xs) {", + " return xs.reduce(function (a, x) {", + " return a + x;", + " }, 0);", + " }", + "", + " // product :: n -> n -> n", + " function product(a, b) {", + " return a * b;", + " }", + "", + "})();", + "{{Out}}", + "[[51, -8, 26, -18], [-8, -38, -6, 34], ", + " [33, 42, 38, -14], [17, 74, 72, 44]]", + "", + "===ES6===", + "((() => {", + " 'use strict';", + "", + " // matrixMultiply :: Num a => [[a]] -> [[a]] -> [[a]]", + " const matrixMultiply = (a, b) => {", + " const bCols = transpose(b);", + " return a.map(aRow => bCols.map(bCol => dotProduct(aRow, bCol)));", + " }", + "", + " // dotProduct :: Num a => [[a]] -> [[a]] -> [[a]]", + " const dotProduct = (xs, ys) => sum(zipWith(product, xs, ys));", + "", + "", + " // GENERIC", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " const zipWith = (f, xs, ys) =>", + " xs.length === ys.length ? (", + " xs.map((x, i) => f(x, ys[i]))", + " ) : undefined;", + "", + " // transpose :: [[a]] -> [[a]]", + " const transpose = xs =>", + " xs[0].map((_, iCol) => xs.map(row => row[iCol]));", + "", + " // sum :: (Num a) => [a] -> a", + " const sum = xs =>", + " xs.reduce((a, x) => a + x, 0);", + "", + " // product :: Num a => a -> a -> a", + " const product = (a, b) => a * b;", + "", + "", + " // TEST", + " return matrixMultiply(", + " [", + " [-1, 1, 4],", + " [6, -4, 2],", + " [-3, 5, 0],", + " [3, 7, -2]", + " ],", + "", + " [", + " [-1, 1, 4, 8],", + " [6, 9, 10, 2],", + " [11, -4, 5, -3]", + " ]", + " );", + "", + " // --> [[51, -8, 26, -18], [-8, -38, -6, 34],", + " // [33, 42, 38, -14], [17, 74, 72, 44]]", + "}))();", + "{{Out}}", + "[[51, -8, 26, -18], [-8, -38, -6, 34], ", + "[33, 42, 38, -14], [17, 74, 72, 44]]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f0d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// returns a new matrix\nMatrix.prototype.mult = function(other) {\n if (this.width != other.height) {\n throw \"error: incompatible sizes\";\n }\n\n var result = [];\n for (var i = 0; i < this.height; i++) {\n result[i] = [];\n for (var j = 0; j < other.width; j++) {\n var sum = 0;\n for (var k = 0; k < this.width; k++) {\n sum += this.mtx[i][k] * other.mtx[k][j];\n }\n result[i][j] = sum;\n }\n }\n return new Matrix(result); \n}\n\nvar a = new Matrix([[1,2],[3,4]])\nvar b = new Matrix([[-3,-8,3],[-2,1,4]]);\nprint(a.mult(b));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Matrix transposition", + "type": "Waypoint", + "description": [ + "

    Transpose an arbitrarily sized rectangular Matrix.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "{{works with|SpiderMonkey}} for the print() function", + "function Matrix(ary) {", + " this.mtx = ary", + " this.height = ary.length;", + " this.width = ary[0].length;", + "}", + "", + "Matrix.prototype.toString = function() {", + " var s = []", + " for (var i = 0; i < this.mtx.length; i++) ", + " s.push( this.mtx[i].join(\",\") );", + " return s.join(\"\\n\");", + "}", + "", + "// returns a new matrix", + "Matrix.prototype.transpose = function() {", + " var transposed = [];", + " for (var i = 0; i < this.width; i++) {", + " transposed[i] = [];", + " for (var j = 0; j < this.height; j++) {", + " transposed[i][j] = this.mtx[j][i];", + " }", + " }", + " return new Matrix(transposed);", + "}", + "", + "var m = new Matrix([[1,1,1,1],[2,4,8,16],[3,9,27,81],[4,16,64,256],[5,25,125,625]]);", + "print(m);", + "print();", + "print(m.transpose());", + "", + "produces", + "
    1,1,1,1",
    +        "2,4,8,16",
    +        "3,9,27,81",
    +        "4,16,64,256",
    +        "5,25,125,625",
    +        "",
    +        "1,2,3,4,5",
    +        "1,4,9,16,25",
    +        "1,8,27,64,125",
    +        "1,16,81,256,625
    ", + "", + "", + "Or, as a functional expression (rather than an imperative procedure):", + "", + "(function () {", + " 'use strict';", + "", + " function transpose(lst) {", + " return lst[0].map(function (_, iCol) {", + " return lst.map(function (row) {", + " return row[iCol];", + " })", + " });", + " }", + " ", + " return transpose(", + " [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]", + " );", + "", + "})();", + "", + "", + "{{Out}}", + "", + "
    [[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]]
    ", + "", + "===ES6===", + "", + "(() => {", + " 'use strict';", + "", + " // transpose :: [[a]] -> [[a]]", + " let transpose = xs =>", + " xs[0].map((_, iCol) => xs.map((row) => row[iCol]));", + "", + "", + "", + " // TEST", + " return transpose([", + " [1, 2],", + " [3, 4],", + " [5, 6]", + " ]);", + "})();", + "", + "{{Out}}", + "[[1, 3, 5], [2, 4, 6]]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f0e", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function Matrix(ary) {\n this.mtx = ary\n this.height = ary.length;\n this.width = ary[0].length;\n}\n\nMatrix.prototype.toString = function() {\n var s = []\n for (var i = 0; i < this.mtx.length; i++) \n s.push( this.mtx[i].join(\",\") );\n return s.join(\"\\n\");\n}\n\n// returns a new matrix\nMatrix.prototype.transpose = function() {\n var transposed = [];\n for (var i = 0; i < this.width; i++) {\n transposed[i] = [];\n for (var j = 0; j < this.height; j++) {\n transposed[i][j] = this.mtx[j][i];\n }\n }\n return new Matrix(transposed);\n}\n\nvar m = new Matrix([[1,1,1,1],[2,4,8,16],[3,9,27,81],[4,16,64,256],[5,25,125,625]]);\nprint(m);\nprint();\nprint(m.transpose());\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Maximum triangle path sum", + "type": "Waypoint", + "description": [ + "

    Starting from the top of a pyramid of numbers like this, you can walk down going one step on the right or on the left, until you reach the bottom row:

    ", + "
    ",
    +        "                          55",
    +        "                        94 48",
    +        "                       95 30 96",
    +        "                     77 71 26 67",
    +        "

    One of such walks is 55 - 94 - 30 - 26.

    ", + "

    You can compute the total of the numbers you have seen in such walk,

    ", + "

    in this case it's 205.

    Your problem is to find the maximum total among all possible paths from the top to the bottom row of the triangle. In the little example above it's 321.

    ", + "Task:", + "

    Find the maximum total in the triangle below:

    ", + "
    ",
    +        "                          55",
    +        "                        94 48",
    +        "                       95 30 96",
    +        "                     77 71 26 67",
    +        "                    97 13 76 38 45",
    +        "                  07 36 79 16 37 68",
    +        "                 48 07 09 18 70 26 06",
    +        "               18 72 79 46 59 79 29 90",
    +        "              20 76 87 11 32 07 07 49 18",
    +        "            27 83 58 35 71 11 25 57 29 85",
    +        "           14 64 36 96 27 11 58 56 92 18 55",
    +        "         02 90 03 60 48 49 41 46 33 36 47 23",
    +        "        92 50 48 02 36 59 42 79 72 20 82 77 42",
    +        "      56 78 38 80 39 75 02 71 66 66 01 03 55 72",
    +        "     44 25 67 84 71 67 11 61 40 57 58 89 40 56 36",
    +        "   85 32 25 85 57 48 84 35 47 62 17 01 01 99 89 52",
    +        "  06 71 28 75 94 48 37 10 23 51 06 48 53 18 74 98 15",
    +        "27 02 92 23 08 71 76 84 15 52 92 63 81 10 44 10 69 93",
    +        "

    Such numbers can be included in the solution code, or read from a \"triangle.txt\" file.

    This task is derived from the Euler Problem #18.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f0f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Maze solving", + "type": "Waypoint", + "description": [ + "

    For a maze generated by this task, write a function

    ", + "

    that finds (and displays) the shortest path between two cells.

    ", + "

    Note that because these mazes are generated by the Depth-first search algorithm, they contain no circular paths,

    ", + "

    and a simple depth-first tree search can be used.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Animated: generating and solving.
    To start solving, click to choose a 'start' and an 'end' points.", + "
    Go [http://paulo-jorente.de/tests/mazesolver/ here] to see it in action.", + "", + "var ctx, wid, hei, cols, rows, maze, stack = [], start = {x:-1, y:-1}, end = {x:-1, y:-1}, grid = 8;", + "function drawMaze() {", + " for( var i = 0; i < cols; i++ ) {", + " for( var j = 0; j < rows; j++ ) {", + " switch( maze[i][j] ) {", + " case 0: ctx.fillStyle = \"black\"; break;", + " case 1: ctx.fillStyle = \"green\"; break;", + " case 2: ctx.fillStyle = \"red\"; break;", + " case 3: ctx.fillStyle = \"yellow\"; break;", + " case 4: ctx.fillStyle = \"#500000\"; break;", + " }", + " ctx.fillRect( grid * i, grid * j, grid, grid );", + " }", + " }", + "}", + "function getFNeighbours( sx, sy, a ) {", + " var n = [];", + " if( sx - 1 > 0 && maze[sx - 1][sy] == a ) {", + " n.push( { x:sx - 1, y:sy } );", + " }", + " if( sx + 1 < cols - 1 && maze[sx + 1][sy] == a ) {", + " n.push( { x:sx + 1, y:sy } );", + " }", + " if( sy - 1 > 0 && maze[sx][sy - 1] == a ) {", + " n.push( { x:sx, y:sy - 1 } );", + " }", + " if( sy + 1 < rows - 1 && maze[sx][sy + 1] == a ) {", + " n.push( { x:sx, y:sy + 1 } );", + " }", + " return n;", + "}", + "function solveMaze() {", + " if( start.x == end.x && start.y == end.y ) {", + " for( var i = 0; i < cols; i++ ) {", + " for( var j = 0; j < rows; j++ ) {", + " switch( maze[i][j] ) {", + " case 2: maze[i][j] = 3; break;", + " case 4: maze[i][j] = 0; break;", + " }", + " }", + " }", + " drawMaze();", + " return;", + " }", + " var neighbours = getFNeighbours( start.x, start.y, 0 );", + " if( neighbours.length ) {", + " stack.push( start );", + " start = neighbours[0];", + " maze[start.x][start.y] = 2;", + " } else {", + " maze[start.x][start.y] = 4;", + " start = stack.pop();", + " }", + "", + " drawMaze();", + " requestAnimationFrame( solveMaze );", + "}", + "function getCursorPos( event ) {", + " var rect = this.getBoundingClientRect();", + " var x = Math.floor( ( event.clientX - rect.left ) / grid ), ", + " y = Math.floor( ( event.clientY - rect.top ) / grid );", + " if( maze[x][y] ) return;", + " if( start.x == -1 ) {", + " start = { x: x, y: y };", + " } else {", + " end = { x: x, y: y };", + " maze[start.x][start.y] = 2;", + " solveMaze();", + " }", + "}", + "function getNeighbours( sx, sy, a ) {", + " var n = [];", + " if( sx - 1 > 0 && maze[sx - 1][sy] == a && sx - 2 > 0 && maze[sx - 2][sy] == a ) {", + " n.push( { x:sx - 1, y:sy } ); n.push( { x:sx - 2, y:sy } );", + " }", + " if( sx + 1 < cols - 1 && maze[sx + 1][sy] == a && sx + 2 < cols - 1 && maze[sx + 2][sy] == a ) {", + " n.push( { x:sx + 1, y:sy } ); n.push( { x:sx + 2, y:sy } );", + " }", + " if( sy - 1 > 0 && maze[sx][sy - 1] == a && sy - 2 > 0 && maze[sx][sy - 2] == a ) {", + " n.push( { x:sx, y:sy - 1 } ); n.push( { x:sx, y:sy - 2 } );", + " }", + " if( sy + 1 < rows - 1 && maze[sx][sy + 1] == a && sy + 2 < rows - 1 && maze[sx][sy + 2] == a ) {", + " n.push( { x:sx, y:sy + 1 } ); n.push( { x:sx, y:sy + 2 } );", + " }", + " return n;", + "}", + "function createArray( c, r ) {", + " var m = new Array( c );", + " for( var i = 0; i < c; i++ ) {", + " m[i] = new Array( r );", + " for( var j = 0; j < r; j++ ) {", + " m[i][j] = 1;", + " }", + " }", + " return m;", + "}", + "function createMaze() {", + " var neighbours = getNeighbours( start.x, start.y, 1 ), l;", + " if( neighbours.length < 1 ) {", + " if( stack.length < 1 ) {", + " drawMaze(); stack = [];", + " start.x = start.y = -1;", + " document.getElementById( \"canvas\" ).addEventListener( \"mousedown\", getCursorPos, false );", + " return;", + " }", + " start = stack.pop();", + " } else {", + " var i = 2 * Math.floor( Math.random() * ( neighbours.length / 2 ) )", + " l = neighbours[i]; maze[l.x][l.y] = 0;", + " l = neighbours[i + 1]; maze[l.x][l.y] = 0;", + " start = l", + " stack.push( start )", + " }", + " drawMaze();", + " requestAnimationFrame( createMaze );", + "}", + "function createCanvas( w, h ) {", + " var canvas = document.createElement( \"canvas\" );", + " wid = w; hei = h;", + " canvas.width = wid; canvas.height = hei;", + " canvas.id = \"canvas\";", + " ctx = canvas.getContext( \"2d\" );", + " ctx.fillStyle = \"black\"; ctx.fillRect( 0, 0, wid, hei );", + " document.body.appendChild( canvas ); ", + "}", + "function init() {", + " cols = 73; rows = 53;", + " createCanvas( grid * cols, grid * rows );", + " maze = createArray( cols, rows );", + " start.x = Math.floor( Math.random() * ( cols / 2 ) );", + " start.y = Math.floor( Math.random() * ( rows / 2 ) );", + " if( !( start.x & 1 ) ) start.x++; if( !( start.y & 1 ) ) start.y++;", + " maze[start.x][start.y] = 0;", + " createMaze();", + "}", + "", + "HTML to test.", + "
    ",
    +        "",
    +        "",
    +        "Maze",
    +        "",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f11", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nvar ctx, wid, hei, cols, rows, maze, stack = [], start = {x:-1, y:-1}, end = {x:-1, y:-1}, grid = 8;\nfunction drawMaze() {\n for( var i = 0; i < cols; i++ ) {\n for( var j = 0; j < rows; j++ ) {\n switch( maze[i][j] ) {\n case 0: ctx.fillStyle = \"black\"; break;\n case 1: ctx.fillStyle = \"green\"; break;\n case 2: ctx.fillStyle = \"red\"; break;\n case 3: ctx.fillStyle = \"yellow\"; break;\n case 4: ctx.fillStyle = \"#500000\"; break;\n }\n ctx.fillRect( grid * i, grid * j, grid, grid );\n }\n }\n}\nfunction getFNeighbours( sx, sy, a ) {\n var n = [];\n if( sx - 1 > 0 && maze[sx - 1][sy] == a ) {\n n.push( { x:sx - 1, y:sy } );\n }\n if( sx + 1 < cols - 1 && maze[sx + 1][sy] == a ) {\n n.push( { x:sx + 1, y:sy } );\n }\n if( sy - 1 > 0 && maze[sx][sy - 1] == a ) {\n n.push( { x:sx, y:sy - 1 } );\n }\n if( sy + 1 < rows - 1 && maze[sx][sy + 1] == a ) {\n n.push( { x:sx, y:sy + 1 } );\n }\n return n;\n}\nfunction solveMaze() {\n if( start.x == end.x && start.y == end.y ) {\n for( var i = 0; i < cols; i++ ) {\n for( var j = 0; j < rows; j++ ) {\n switch( maze[i][j] ) {\n case 2: maze[i][j] = 3; break;\n case 4: maze[i][j] = 0; break;\n }\n }\n }\n drawMaze();\n return;\n }\n var neighbours = getFNeighbours( start.x, start.y, 0 );\n if( neighbours.length ) {\n stack.push( start );\n start = neighbours[0];\n maze[start.x][start.y] = 2;\n } else {\n maze[start.x][start.y] = 4;\n start = stack.pop();\n }\n\n drawMaze();\n requestAnimationFrame( solveMaze );\n}\nfunction getCursorPos( event ) {\n var rect = this.getBoundingClientRect();\n var x = Math.floor( ( event.clientX - rect.left ) / grid ), \n y = Math.floor( ( event.clientY - rect.top ) / grid );\n if( maze[x][y] ) return;\n if( start.x == -1 ) {\n start = { x: x, y: y };\n } else {\n end = { x: x, y: y };\n maze[start.x][start.y] = 2;\n solveMaze();\n }\n}\nfunction getNeighbours( sx, sy, a ) {\n var n = [];\n if( sx - 1 > 0 && maze[sx - 1][sy] == a && sx - 2 > 0 && maze[sx - 2][sy] == a ) {\n n.push( { x:sx - 1, y:sy } ); n.push( { x:sx - 2, y:sy } );\n }\n if( sx + 1 < cols - 1 && maze[sx + 1][sy] == a && sx + 2 < cols - 1 && maze[sx + 2][sy] == a ) {\n n.push( { x:sx + 1, y:sy } ); n.push( { x:sx + 2, y:sy } );\n }\n if( sy - 1 > 0 && maze[sx][sy - 1] == a && sy - 2 > 0 && maze[sx][sy - 2] == a ) {\n n.push( { x:sx, y:sy - 1 } ); n.push( { x:sx, y:sy - 2 } );\n }\n if( sy + 1 < rows - 1 && maze[sx][sy + 1] == a && sy + 2 < rows - 1 && maze[sx][sy + 2] == a ) {\n n.push( { x:sx, y:sy + 1 } ); n.push( { x:sx, y:sy + 2 } );\n }\n return n;\n}\nfunction createArray( c, r ) {\n var m = new Array( c );\n for( var i = 0; i < c; i++ ) {\n m[i] = new Array( r );\n for( var j = 0; j < r; j++ ) {\n m[i][j] = 1;\n }\n }\n return m;\n}\nfunction createMaze() {\n var neighbours = getNeighbours( start.x, start.y, 1 ), l;\n if( neighbours.length < 1 ) {\n if( stack.length < 1 ) {\n drawMaze(); stack = [];\n start.x = start.y = -1;\n document.getElementById( \"canvas\" ).addEventListener( \"mousedown\", getCursorPos, false );\n return;\n }\n start = stack.pop();\n } else {\n var i = 2 * Math.floor( Math.random() * ( neighbours.length / 2 ) )\n l = neighbours[i]; maze[l.x][l.y] = 0;\n l = neighbours[i + 1]; maze[l.x][l.y] = 0;\n start = l\n stack.push( start )\n }\n drawMaze();\n requestAnimationFrame( createMaze );\n}\nfunction createCanvas( w, h ) {\n var canvas = document.createElement( \"canvas\" );\n wid = w; hei = h;\n canvas.width = wid; canvas.height = hei;\n canvas.id = \"canvas\";\n ctx = canvas.getContext( \"2d\" );\n ctx.fillStyle = \"black\"; ctx.fillRect( 0, 0, wid, hei );\n document.body.appendChild( canvas ); \n}\nfunction init() {\n cols = 73; rows = 53;\n createCanvas( grid * cols, grid * rows );\n maze = createArray( cols, rows );\n start.x = Math.floor( Math.random() * ( cols / 2 ) );\n start.y = Math.floor( Math.random() * ( rows / 2 ) );\n if( !( start.x & 1 ) ) start.x++; if( !( start.y & 1 ) ) start.y++;\n maze[start.x][start.y] = 0;\n createMaze();\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "MD4", + "type": "Waypoint", + "description": [ + "

    Find the MD4 message digest of a string of octets.

    ", + "

    Use the ASCII encoded string “Rosetta Code” (without quotes).

    ", + "

    You may either call an MD4 library, or implement MD4 in your language.

    MD4 is an obsolete hash function that computes a 128-bit message digest that sometimes appears in obsolete protocols.

    RFC 1320 specifies the MD4 algorithm. RFC 6150 declares that MD4 is obsolete.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f12", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "MD5/Implementation", + "type": "Waypoint", + "description": [ + "

    The purpose of this task to code and validate an implementation of the MD5 Message Digest Algorithm by coding the algorithm directly (not using a call to a built-in or external hashing library). For details of the algorithm refer to MD5 on Wikipedia or the MD5 definition in IETF RFC (1321).

    The implementation needs to implement the key functionality namely producing a correct message digest for an input string. It is not necessary to mimic all of the calling modes such as adding to a digest one block at a time over subsequent calls. ", + "In addition to coding and verifying your implementation, note any challenges your language presented implementing the solution, implementation choices made, or limitations of your solution. ", + "Solutions on this page should implement MD5 directly and NOT use built in (MD5) functions, call outs to operating system calls or library routines written in other languages as is common in the original MD5 task.", + "The following are acceptable:", + "* An original implementation from the specification, reference implementation, or pseudo-code", + "* A translation of a correct implementation from another language", + "* A library routine in the same language; however, the source must be included here.", + "

    The solutions shown here will provide practical illustrations of bit manipulation, unsigned integers, working with little-endian data. Additionally, the task requires an attention to details such as boundary conditions since being out by even 1 bit will produce dramatically different results. Subtle implementation bugs can result in some hashes being correct while others are wrong. Not only is it critical to get the individual sub functions working correctly, even small errors in padding, endianness, or data layout will result in failure.

    The following verification strings and hashes come from RFC 1321:

                                hash code <== string ",
    +        "   0xd41d8cd98f00b204e9800998ecf8427e <== \"\"  ",
    +        "   0x0cc175b9c0f1b6a831c399e269772661 <== \"a\"",
    +        "   0x900150983cd24fb0d6963f7d28e17f72 <== \"abc\"",
    +        "   0xf96b697d7cb7938d525a2f31aaf161d0 <== \"message digest\"",
    +        "   0xc3fcd3d76192e4007dfb496cca67e13b <== \"abcdefghijklmnopqrstuvwxyz\"",
    +        "   0xd174ab98d277d9f5a5611c2c9f419d9f <== \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"",
    +        "   0x57edf4a22be3c955ac49da2e2107b67a <== \"12345678901234567890123456789012345678901234567890123456789012345678901234567890\"

    In addition, intermediate outputs to aid in developing an implementation can be found here.

    The MD5 Message-Digest Algorithm was developed by RSA Data Security, Inc. in 1991.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f13", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "MD5", + "type": "Waypoint", + "description": [ + "Task:", + "

    Encode a string using an MD5 algorithm. The algorithm can be found on Wikipedia.

    ", + "

    Optionally, validate your implementation by running all of the test values in IETF RFC (1321) for MD5.

    Additionally, RFC 1321 provides more precise information on the algorithm than the Wikipedia article.

    ", + "

    If the solution on this page is a library solution, see MD5/Implementation for an implementation from scratch.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f14", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Median filter", + "type": "Waypoint", + "description": [ + "

    The median filter takes in the neighbourhood the median color (see Median filter)

    (to test the function below, you can use these input and output solutions)

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f15", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Metaprogramming", + "type": "Waypoint", + "description": [ + "

    Name and briefly demonstrate any support your language has for metaprogramming. Your demonstration may take the form of cross-references to other tasks on Rosetta Code. When possible, provide links to relevant documentation.

    For the purposes of this task, \"support for metaprogramming\" means any way the user can effectively modify the language's syntax that's built into the language (like Lisp macros) or that's conventionally used with the language (like the C preprocessor). Such facilities need not be very powerful: even user-defined infix operators count. On the other hand, in general, neither operator overloading nor eval count. The task author acknowledges that what qualifies as metaprogramming is largely a judgment call.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f19", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Metered concurrency", + "type": "Waypoint", + "description": [ + "

    The goal of this task is to create a counting semaphore used to control the execution of a set of concurrent units. This task intends to demonstrate coordination of active concurrent units through the use of a passive concurrent unit. The operations for a counting semaphore are acquire, release, and count. Each active concurrent unit should attempt to acquire the counting semaphore before executing its assigned duties. In this case the active concurrent unit should report that it has acquired the semaphore. It should sleep for 2 seconds and then release the semaphore.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f1a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Metronome", + "type": "Waypoint", + "description": [ + "

    ", + "

    The task is to implement a metronome.

    The metronome should be capable of producing high and low audio beats, accompanied by a visual beat indicator, and the beat pattern and tempo should be configurable.

    For the purpose of this task, it is acceptable to play sound files for production of the beat notes, and an external player may be used.

    However, the playing of the sounds should not interfere with the timing of the metronome.

    The visual indicator can simply be a blinking red or green area of the screen (depending on whether a high or low beat is being produced), and the metronome can be implemented using a terminal display, or optionally, a graphical display, depending on the language capabilities.

    If the language has no facility to output sound, then it is permissible for this to implemented using just the visual indicator.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f1b", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Middle three digits", + "type": "Waypoint", + "description": [ + "Task:", + "

    Write a function/procedure/subroutine that is called with an integer value and returns the middle three digits of the integer if possible or a clear indication of an error if this is not possible.

    Note: The order of the middle digits should be preserved.

    Your function should be tested with the following values; the first line should return valid answers, those of the second line should return clear indications of an error:

    ", + "
    ",
    +        "123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345",
    +        "1, 2, -1, -10, 2002, -2002, 0",
    +        "
    ", + "

    Show your output on this page.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function middleThree(x){", + " var n=''+Math.abs(x); var l=n.length-1;", + " if(l<2||l%2) throw new Error(x+': Invalid length '+(l+1));", + " return n.slice(l/2-1,l/2+2);", + "}", + "", + "[123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345,", + "1, 2, -1, -10, 2002, -2002, 0].forEach(function(n){", + " try{console.log(n,middleThree(n))}catch(e){console.error(e.message)}", + "});", + "", + "
    123 \"123\"",
    +        "12345 \"234\"",
    +        "1234567 \"345\"",
    +        "987654321 \"654\"",
    +        "10001 \"000\"",
    +        "-10001 \"000\"",
    +        "-123 \"123\"",
    +        "-100 \"100\"",
    +        "100 \"100\"",
    +        "-12345 \"234\"",
    +        "1: Invalid length 1",
    +        "2: Invalid length 1",
    +        "-1: Invalid length 1",
    +        "-10: Invalid length 2",
    +        "2002: Invalid length 4",
    +        "-2002: Invalid length 4",
    +        "0: Invalid length 1
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f1c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function middleThree(x){\n var n=''+Math.abs(x); var l=n.length-1;\n if(l<2||l%2) throw new Error(x+': Invalid length '+(l+1));\n return n.slice(l/2-1,l/2+2);\n}\n\n[123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345,\n1, 2, -1, -10, 2002, -2002, 0].forEach(function(n){\n try{console.log(n,middleThree(n))}catch(e){console.error(e.message)}\n});\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Miller–Rabin primality test", + "type": "Waypoint", + "description": [ + "

    The Miller–Rabin primality test or Rabin–Miller primality test is a primality test: an algorithm which determines whether a given number is prime or not.

    The algorithm, as modified by Michael O. Rabin to avoid the generalized Riemann hypothesis, is a probabilistic algorithm.

    The pseudocode, from Wikipedia is:

    ", + "

    Input: n > 2, an odd integer to be tested for primality;

    ", + "

    k, a parameter that determines the accuracy of the test

    ", + "

    Output: composite if n is composite, otherwise probably prime

    ", + "

    write n − 1 as 2s·d with d odd by factoring powers of 2 from n − 1

    ", + "

    LOOP: repeat k times:

    ", + "

    pick a randomly in the range [2, n − 1]

    ", + "

    x ← ad mod n

    ", + "

    if x = 1 or x = n − 1 then do next LOOP

    ", + "

    for r = 1 .. s − 1

    ", + "

    x ← x2 mod n

    ", + "

    if x = 1 then return composite

    ", + "

    if x = n − 1 then do next LOOP

    ", + "

    return composite

    ", + "

    return probably prime

    The nature of the test involves big numbers, so the use of \"big numbers\" libraries (or similar features of the language of your choice) are suggested, but not mandatory.", + "Deterministic variants of the test exist and can be implemented as extra (not mandatory to complete the task)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "For the return values of this function, true means \"probably prime\" and false means \"definitely composite.\"", + "", + "function probablyPrime(n, k) {", + "\tif (n === 2 || n === 3)", + "\t\treturn true;", + "\tif (n % 2 === 0 || n < 2)", + "\t\treturn false;", + "", + "\t// Write (n - 1) as 2^s * d", + "\tvar s = 0, d = n - 1;", + "\twhile (d % 2 === 0) {", + "\t\td /= 2;", + "\t\t++s;", + "\t}", + "", + "\tWitnessLoop: do {", + "\t\t// A base between 2 and n - 2", + "\t\tvar x = Math.pow(2 + Math.floor(Math.random() * (n - 3)), d) % n;", + "", + "\t\tif (x === 1 || x === n - 1)", + "\t\t\tcontinue;", + "", + "\t\tfor (var i = s - 1; i--;) {", + "\t\t\tx = x * x % n;", + "\t\t\tif (x === 1)", + "\t\t\t\treturn false;", + "\t\t\tif (x === n - 1)", + "\t\t\t\tcontinue WitnessLoop;", + "\t\t}", + "", + "\t\treturn false;", + "\t} while (--k);", + "", + "\treturn true;", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f1d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function probablyPrime(n, k) {\n\tif (n === 2 || n === 3)\n\t\treturn true;\n\tif (n % 2 === 0 || n < 2)\n\t\treturn false;\n\n\t// Write (n - 1) as 2^s * d\n\tvar s = 0, d = n - 1;\n\twhile (d % 2 === 0) {\n\t\td /= 2;\n\t\t++s;\n\t}\n\n\tWitnessLoop: do {\n\t\t// A base between 2 and n - 2\n\t\tvar x = Math.pow(2 + Math.floor(Math.random() * (n - 3)), d) % n;\n\n\t\tif (x === 1 || x === n - 1)\n\t\t\tcontinue;\n\n\t\tfor (var i = s - 1; i--;) {\n\t\t\tx = x * x % n;\n\t\t\tif (x === 1)\n\t\t\t\treturn false;\n\t\t\tif (x === n - 1)\n\t\t\t\tcontinue WitnessLoop;\n\t\t}\n\n\t\treturn false;\n\t} while (--k);\n\n\treturn true;\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Modular exponentiation", + "type": "Waypoint", + "description": [ + "

    Find the last 40 decimal digits of $a^b$, where

    $a = 2988348162058574136915891421498819466320163312926952423791023078876139$", + "$b = 2351399303373464486466122544523690094744975233415544072992656881240319$", + "

    A computer is too slow to find the entire value of $a^b$.

    Instead, the program must use a fast algorithm for modular exponentiation: $a^b \\mod m$.

    The algorithm must work for any integers $a, b, m$ where $b \\ge 0$ and $m > 0$.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f1f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Modular inverse", + "type": "Waypoint", + "description": [ + "

    From Wikipedia:

    In modular arithmetic, the modular multiplicative inverse of an integer a modulo m is an integer x such that

    :$a\\,x \\equiv 1 \\pmod{m}.$

    Or in other words, such that:

    :$\\exists k \\in\\Z,\\qquad a\\, x = 1 + k\\,m$

    It can be shown that such an inverse exists if and only if a and m are coprime, but we will ignore this for this task.

    ", + "Task:", + "

    Either by implementing the algorithm, by using a dedicated library or by using a built-in function in

    ", + "

    your language, compute the modular inverse of 42 modulo 2017.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Using brute force.", + "var modInverse = function(a, b) {", + " a %= b;", + " for (var x = 1; x < b; x++) {", + " if ((a*x)%b == 1) {", + " return x;", + " }", + " }", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f20", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var modInverse = function(a, b) {\n a %= b;\n for (var x = 1; x < b; x++) {\n if ((a*x)%b == 1) {\n return x;\n }\n }\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Monte Carlo methods", + "type": "Waypoint", + "description": [ + "

    A Monte Carlo Simulation is a way of approximating the value of a function

    ", + "

    where calculating the actual value is difficult or impossible.

    ", + "

    It uses random sampling to define constraints on the value

    ", + "

    and then makes a sort of \"best guess.\"

    A simple Monte Carlo Simulation can be used to calculate the value for $\\pi$.

    If you had a circle and a square where the length of a side of the square

    ", + "

    was the same as the diameter of the circle, the ratio of the area of the circle

    ", + "

    to the area of the square would be $\\pi/4$.

    So, if you put this circle inside the square and select many random points

    ", + "

    inside the square, the number of points inside the circle

    ", + "

    divided by the number of points inside the square and the circle

    ", + "

    would be approximately $\\pi/4$.

    ", + "Task:", + "

    Write a function to run a simulation like this, with a variable number of random points to select.

    Also, show the results of a few different sample sizes.

    For software where the number $\\pi$ is not built-in,

    ", + "

    we give $\\pi$ as a number of digits:

    ", + "

    3.141592653589793238462643383280

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "function mcpi(n) {", + " var x, y, m = 0;", + "", + " for (var i = 0; i < n; i += 1) {", + " x = Math.random();", + " y = Math.random();", + "", + " if (x * x + y * y < 1) {", + " m += 1;", + " }", + " }", + "", + " return 4 * m / n;", + "}", + "", + "console.log(mcpi(1000));", + "console.log(mcpi(10000));", + "console.log(mcpi(100000));", + "console.log(mcpi(1000000));", + "console.log(mcpi(10000000));", + "
    3.168",
    +        "3.1396",
    +        "3.13692",
    +        "3.140512",
    +        "3.1417656",
    +        "
    ", + "", + "===ES6===", + "(() => {", + " 'use strict';", + "", + " // monteCarloPi :: Int -> Float", + " const monteCarloPi = n =>", + " 4 * range(1, n)", + " .reduce(a => {", + " const [x, y] = [rnd(), rnd()];", + " return x * x + y * y < 1 ? a + 1 : a;", + " }, 0) / n;", + "", + "", + " // GENERIC FUNCTIONS", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // rnd :: () -> Float", + " const rnd = Math.random;", + "", + "", + " // TEST with from 1000 samples to 10E8 samples", + " return range(3, 8)", + " .map(x => monteCarloPi(Math.pow(10, x)));", + "", + " // e.g. -> [3.14, 3.1404, 3.13304, 3.142408, 3.1420304, 3.14156788]", + "})();", + "", + "", + "{{Out}} (5 sample runs with increasing sample sizes)", + "[3.14, 3.1404, 3.13304, 3.142408, 3.1420304, 3.14156788]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f21", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function mcpi(n) {\n var x, y, m = 0;\n\n for (var i = 0; i < n; i += 1) {\n x = Math.random();\n y = Math.random();\n\n if (x * x + y * y < 1) {\n m += 1;\n }\n }\n\n return 4 * m / n;\n}\n\nconsole.log(mcpi(1000));\nconsole.log(mcpi(10000));\nconsole.log(mcpi(100000));\nconsole.log(mcpi(1000000));\nconsole.log(mcpi(10000000));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Monty Hall problem", + "type": "Waypoint", + "description": [ + "

    Run random simulations of the Monty Hall game. Show the effects of a strategy of the contestant always keeping his first guess so it can be contrasted with the strategy of the contestant always switching his guess.

    Suppose you're on a game show and you're given the choice of three doors. Behind one door is a car; behind the others, goats. The car and the goats were placed randomly behind the doors before the show. The rules of the game show are as follows: After you have chosen a door, the door remains closed for the time being. The game show host, Monty Hall, who knows what is behind the doors, now has to open one of the two remaining doors, and the door he opens must have a goat behind it. If both remaining doors have goats behind them, he chooses one randomly. After Monty Hall opens a door with a goat, he will ask you to decide whether you want to stay with your first choice or to switch to the last remaining door. Imagine that you chose Door 1 and the host opens Door 3, which has a goat. He then asks you \"Do you want to switch to Door Number 2?\" Is it to your advantage to change your choice? (Krauss and Wang 2003:10)

    Note that the player may initially choose any of the three doors (not just Door 1), that the host opens a different door revealing a goat (not necessarily Door 3), and that he gives the player a second choice between the two remaining unopened doors.

    ", + "Task:", + "

    Simulate at least a thousand games using three doors for each strategy and show the results in such a way as to make it easy to compare the effects of each strategy.

    ", + "Reference:", + "Monty Hall Problem - Numberphile. (Video)." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Extensive Solution===", + "", + "This solution can test with n doors, the difference in probability for switching is shown to diminish as the number of doors increases.", + "", + "", + "function montyhall(tests, doors) {", + "\t'use strict';", + "\ttests = tests ? tests : 1000;", + "\tdoors = doors ? doors : 3;", + "\tvar prizeDoor, chosenDoor, shownDoor, switchDoor, chosenWins = 0, switchWins = 0;", + "\t", + "\t// randomly pick a door excluding input doors", + "\tfunction pick(excludeA, excludeB) {", + "\t\tvar door;", + "\t\tdo {", + "\t\t\tdoor = Math.floor(Math.random() * doors);", + "\t\t} while (door === excludeA || door === excludeB);", + "\t\treturn door;", + "\t}", + "\t", + "\t// run tests", + "\tfor (var i = 0; i < tests; i ++) {", + "\t\t", + "\t\t// pick set of doors", + "\t\tprizeDoor = pick();", + "\t\tchosenDoor = pick();", + "\t\tshownDoor = pick(prizeDoor, chosenDoor);", + "\t\tswitchDoor = pick(chosenDoor, shownDoor);", + "", + "\t\t// test set for both choices", + "\t\tif (chosenDoor === prizeDoor) {", + "\t\t\tchosenWins ++;", + "\t\t} else if (switchDoor === prizeDoor) {", + "\t\t\tswitchWins ++;", + "\t\t}", + "\t}", + "\t", + "\t// results", + "\treturn {", + "\t\tstayWins: chosenWins + ' ' + (100 * chosenWins / tests) + '%',", + "\t\tswitchWins: switchWins + ' ' + (100 * switchWins / tests) + '%'", + "\t};", + "}", + "", + "", + "{{out}}", + "", + "montyhall(1000, 3)", + "Object {stayWins: \"349 34.9%\", switchWins: \"651 65.1%\"}", + "montyhall(1000, 4)", + "Object {stayWins: \"253 25.3%\", switchWins: \"384 38.4%\"}", + "montyhall(1000, 5)", + "Object {stayWins: \"202 20.2%\", switchWins: \"265 26.5%\"}", + "", + "", + "===Basic Solution===", + "", + "", + "", + "var totalGames = 10000,", + " selectDoor = function () {", + "\treturn Math.floor(Math.random() * 3); // Choose a number from 0, 1 and 2.", + " },", + " games = (function () {", + "\tvar i = 0, games = [];", + "", + "\tfor (; i < totalGames; ++i) {", + "\t games.push(selectDoor()); // Pick a door which will hide the prize.", + "\t}", + "", + "\treturn games;", + " }()),", + " play = function (switchDoor) {", + "\tvar i = 0, j = games.length, winningDoor, randomGuess, totalTimesWon = 0;", + "", + "\tfor (; i < j; ++i) {", + "\t winningDoor = games[i];", + "\t randomGuess = selectDoor();", + "\t if ((randomGuess === winningDoor && !switchDoor) || ", + "\t\t(randomGuess !== winningDoor && switchDoor)) ", + "\t {", + "\t\t/*", + "\t\t * If I initially guessed the winning door and didn't switch,", + "\t\t * or if I initially guessed a losing door but then switched,", + "\t\t * I've won.", + "\t\t *", + "\t\t * The only time I lose is when I initially guess the winning door ", + "\t\t * and then switch.", + "\t\t */", + "", + "\t\ttotalTimesWon++;", + "\t }", + "\t}", + "\treturn totalTimesWon;", + " };", + "", + "/*", + " * Start the simulation", + " */", + "", + "console.log(\"Playing \" + totalGames + \" games\");", + "console.log(\"Wins when not switching door\", play(false));", + "console.log(\"Wins when switching door\", play(true));", + "", + "", + "{{out}}", + "", + "Playing 10000 games", + "Wins when not switching door 3326", + "Wins when switching door 6630", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f22", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nfunction montyhall(tests, doors) {\n\t'use strict';\n\ttests = tests ? tests : 1000;\n\tdoors = doors ? doors : 3;\n\tvar prizeDoor, chosenDoor, shownDoor, switchDoor, chosenWins = 0, switchWins = 0;\n\t\n\t// randomly pick a door excluding input doors\n\tfunction pick(excludeA, excludeB) {\n\t\tvar door;\n\t\tdo {\n\t\t\tdoor = Math.floor(Math.random() * doors);\n\t\t} while (door === excludeA || door === excludeB);\n\t\treturn door;\n\t}\n\t\n\t// run tests\n\tfor (var i = 0; i < tests; i ++) {\n\t\t\n\t\t// pick set of doors\n\t\tprizeDoor = pick();\n\t\tchosenDoor = pick();\n\t\tshownDoor = pick(prizeDoor, chosenDoor);\n\t\tswitchDoor = pick(chosenDoor, shownDoor);\n\n\t\t// test set for both choices\n\t\tif (chosenDoor === prizeDoor) {\n\t\t\tchosenWins ++;\n\t\t} else if (switchDoor === prizeDoor) {\n\t\t\tswitchWins ++;\n\t\t}\n\t}\n\t\n\t// results\n\treturn {\n\t\tstayWins: chosenWins + ' ' + (100 * chosenWins / tests) + '%',\n\t\tswitchWins: switchWins + ' ' + (100 * switchWins / tests) + '%'\n\t};\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Morse code", + "type": "Waypoint", + "description": [ + "

    Morse code is one of the simplest and most versatile methods of telecommunication in existence.

    ", + "

    It has been in use for more than 160 years — longer than any other electronic encoding system.

    ", + "Task:", + "

    Send a string as audible Morse code to an audio device (e.g., the PC speaker).

    ", + "

    As the standard Morse code does not contain all possible characters,

    ", + "

    you may either ignore unknown characters in the file,

    ", + "

    or indicate them somehow (e.g. with a different pitch).

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "This implementation utilises the fairly new Web Audio API in the browser for generating tones, as such it only uses one vendor implementation (WebKit). It is split into three modules; 1. translating the characters into morse code. 2. creating timings for the morse code. 3. creating tones with the timings.", + "", + "", + "var globalAudioContext = new webkitAudioContext();", + "", + "function morsecode(text, unit, freq) {", + "\t'use strict';", + "", + "\t// defaults", + "\tunit = unit ? unit : 0.05;", + "\tfreq = freq ? freq : 700;", + "\tvar cont = globalAudioContext;", + "\tvar time = cont.currentTime;", + "", + "\t// morsecode", + "\tvar code = {", + "\t\ta: '._', b: '_...', c: '_._.', d: '_..', e: '.', f: '.._.',", + "\t\tg: '__.', h: '....', i: '..', j: '.___', k: '_._', l: '._..',", + "\t\tm: '__', n: '_.', o: '___', p: '.__.', q: '__._', r: '._.',", + "\t\ts: '...', t: '_', u: '.._', v: '..._', w: '.__', x: '_.._',", + "\t\ty: '_.__', z: '__..', 0: '_____', 1: '.____', 2: '..___', 3: '...__',", + "\t\t4: '...._', 5: '.....', 6: '_....', 7: '__...', 8: '___..', 9: '____.'", + "\t};", + "", + "\t// generate code for text", + "\tfunction makecode(data) {", + "\t\tfor (var i = 0; i <= data.length; i ++) {", + "\t\t\tvar codedata = data.substr(i, 1).toLowerCase();", + "\t\t\tcodedata = code[codedata];", + "\t\t\t// recognised character", + "\t\t\tif (codedata !== undefined) {", + "\t\t\t\tmaketime(codedata);", + "\t\t\t}", + "\t\t\t// unrecognised character", + "\t\t\telse {", + "\t\t\t\ttime += unit * 7;", + "\t\t\t}", + "\t\t}", + "\t}", + "", + "\t// generate time for code", + "\tfunction maketime(data) {", + "\t\tfor (var i = 0; i <= data.length; i ++) {", + "\t\t\tvar timedata = data.substr(i, 1);", + "\t\t\ttimedata = (timedata === '.') ? 1 : (timedata === '_') ? 3 : 0;", + "\t\t\ttimedata *= unit;", + "\t\t\tif (timedata > 0) {", + "\t\t\t\tmaketone(timedata);", + "\t\t\t\ttime += timedata;", + "\t\t\t\t// tone gap", + "\t\t\t\ttime += unit * 1;", + "\t\t\t}", + "\t\t}", + "\t\t// char gap", + "\t\ttime += unit * 2;", + "\t}", + "", + "\t// generate tone for time", + "\tfunction maketone(data) {", + "\t\tvar start = time;", + "\t\tvar stop = time + data;", + "\t\t// filter: envelope the tone slightly", + "\t\tgain.gain.linearRampToValueAtTime(0, start);", + "\t\tgain.gain.linearRampToValueAtTime(1, start + (unit / 8));", + "\t\tgain.gain.linearRampToValueAtTime(1, stop - (unit / 16));", + "\t\tgain.gain.linearRampToValueAtTime(0, stop);", + "\t}", + "", + "\t// create: oscillator, gain, destination", + "\tvar osci = cont.createOscillator();", + "\tosci.frequency.value = freq;", + "\tvar gain = cont.createGainNode();", + "\tgain.gain.value = 0;", + "\tvar dest = cont.destination;", + "\t// connect: oscillator -> gain -> destination", + "\tosci.connect(gain);", + "\tgain.connect(dest);", + "\t// start oscillator", + "\tosci.start(time);", + "", + "\t// begin encoding: text -> code -> time -> tone", + "\tmakecode(text);", + "", + "\t// return web audio context for reuse / control", + "\treturn cont;", + "}", + "", + "", + "Usage:", + "", + "", + "morsecode('Hello World');", + "", + "", + "{{out}}", + "", + "[http://jsbin.com/orubaq/1/edit Live Version]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f23", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nvar globalAudioContext = new webkitAudioContext();\n\nfunction morsecode(text, unit, freq) {\n\t'use strict';\n\n\t// defaults\n\tunit = unit ? unit : 0.05;\n\tfreq = freq ? freq : 700;\n\tvar cont = globalAudioContext;\n\tvar time = cont.currentTime;\n\n\t// morsecode\n\tvar code = {\n\t\ta: '._', b: '_...', c: '_._.', d: '_..', e: '.', f: '.._.',\n\t\tg: '__.', h: '....', i: '..', j: '.___', k: '_._', l: '._..',\n\t\tm: '__', n: '_.', o: '___', p: '.__.', q: '__._', r: '._.',\n\t\ts: '...', t: '_', u: '.._', v: '..._', w: '.__', x: '_.._',\n\t\ty: '_.__', z: '__..', 0: '_____', 1: '.____', 2: '..___', 3: '...__',\n\t\t4: '...._', 5: '.....', 6: '_....', 7: '__...', 8: '___..', 9: '____.'\n\t};\n\n\t// generate code for text\n\tfunction makecode(data) {\n\t\tfor (var i = 0; i <= data.length; i ++) {\n\t\t\tvar codedata = data.substr(i, 1).toLowerCase();\n\t\t\tcodedata = code[codedata];\n\t\t\t// recognised character\n\t\t\tif (codedata !== undefined) {\n\t\t\t\tmaketime(codedata);\n\t\t\t}\n\t\t\t// unrecognised character\n\t\t\telse {\n\t\t\t\ttime += unit * 7;\n\t\t\t}\n\t\t}\n\t}\n\n\t// generate time for code\n\tfunction maketime(data) {\n\t\tfor (var i = 0; i <= data.length; i ++) {\n\t\t\tvar timedata = data.substr(i, 1);\n\t\t\ttimedata = (timedata === '.') ? 1 : (timedata === '_') ? 3 : 0;\n\t\t\ttimedata *= unit;\n\t\t\tif (timedata > 0) {\n\t\t\t\tmaketone(timedata);\n\t\t\t\ttime += timedata;\n\t\t\t\t// tone gap\n\t\t\t\ttime += unit * 1;\n\t\t\t}\n\t\t}\n\t\t// char gap\n\t\ttime += unit * 2;\n\t}\n\n\t// generate tone for time\n\tfunction maketone(data) {\n\t\tvar start = time;\n\t\tvar stop = time + data;\n\t\t// filter: envelope the tone slightly\n\t\tgain.gain.linearRampToValueAtTime(0, start);\n\t\tgain.gain.linearRampToValueAtTime(1, start + (unit / 8));\n\t\tgain.gain.linearRampToValueAtTime(1, stop - (unit / 16));\n\t\tgain.gain.linearRampToValueAtTime(0, stop);\n\t}\n\n\t// create: oscillator, gain, destination\n\tvar osci = cont.createOscillator();\n\tosci.frequency.value = freq;\n\tvar gain = cont.createGainNode();\n\tgain.gain.value = 0;\n\tvar dest = cont.destination;\n\t// connect: oscillator -> gain -> destination\n\tosci.connect(gain);\n\tgain.connect(dest);\n\t// start oscillator\n\tosci.start(time);\n\n\t// begin encoding: text -> code -> time -> tone\n\tmakecode(text);\n\n\t// return web audio context for reuse / control\n\treturn cont;\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Move-to-front algorithm", + "type": "Waypoint", + "description": [ + "

    Given a symbol table of a zero-indexed array of all possible input symbols

    ", + "

    this algorithm reversibly transforms a sequence

    ", + "

    of input symbols into an array of output numbers (indices).

    ", + "

    The transform in many cases acts to give frequently repeated input symbols

    ", + "

    lower indices which is useful in some compression algorithms.

    Encoding algorithm:", + "
    ",
    +        "    for each symbol of the input sequence:",
    +        "        output the index of the symbol in the symbol table",
    +        "        move that symbol to the front of the symbol table",
    +        "
    Decoding algorithm:", + "
    ",
    +        "    # Using the same starting symbol table",
    +        "    for each index of the input sequence:",
    +        "        output the symbol at that index of the symbol table",
    +        "        move that symbol to the front of the symbol table",
    +        "
    Example:", + "

    Encoding the string of character symbols 'broood' using a symbol table of

    ", + "

    the characters 'a'-to-'z'

    {| border=\"1\"

    ", + "

    |-

    ", + "

    ! Input

    ", + "

    ! Output

    ", + "

    ! SymbolTable

    ", + "

    |-

    ", + "

    | broood

    ", + "

    | 1

    ", + "

    | 'abcdefghijklmnopqrstuvwxyz'

    ", + "

    |-

    ", + "

    | broood

    ", + "

    | 1 17

    ", + "

    | 'bacdefghijklmnopqrstuvwxyz'

    ", + "

    |-

    ", + "

    | broood

    ", + "

    | 1 17 15

    ", + "

    | 'rbacdefghijklmnopqstuvwxyz'

    ", + "

    |-

    ", + "

    | broood

    ", + "

    | 1 17 15 0

    ", + "

    | 'orbacdefghijklmnpqstuvwxyz'

    ", + "

    |-

    ", + "

    | broood

    ", + "

    | 1 17 15 0 0

    ", + "

    | 'orbacdefghijklmnpqstuvwxyz'

    ", + "

    |-

    ", + "

    | broood

    ", + "

    | 1 17 15 0 0 5

    ", + "

    | 'orbacdefghijklmnpqstuvwxyz'

    ", + "

    |}

    Decoding the indices back to the original symbol order:

    ", + "

    {| border=\"1\"

    ", + "

    |-

    ", + "

    ! Input

    ", + "

    ! Output

    ", + "

    ! SymbolTable

    ", + "

    |-

    ", + "

    | 1 17 15 0 0 5

    ", + "

    | b

    ", + "

    | 'abcdefghijklmnopqrstuvwxyz'

    ", + "

    |-

    ", + "

    | 1 17 15 0 0 5

    ", + "

    | br

    ", + "

    | 'bacdefghijklmnopqrstuvwxyz'

    ", + "

    |-

    ", + "

    | 1 17 15 0 0 5

    ", + "

    | bro

    ", + "

    | 'rbacdefghijklmnopqstuvwxyz'

    ", + "

    |-

    ", + "

    | 1 17 15 0 0 5

    ", + "

    | broo

    ", + "

    | 'orbacdefghijklmnpqstuvwxyz'

    ", + "

    |-

    ", + "

    | 1 17 15 0 0 5

    ", + "

    | brooo

    ", + "

    | 'orbacdefghijklmnpqstuvwxyz'

    ", + "

    |-

    ", + "

    | 1 17 15 0 0 5

    ", + "

    | broood

    ", + "

    | 'orbacdefghijklmnpqstuvwxyz'

    ", + "

    |}

    Task:", + "Encode and decode the following three strings of characters using the symbol table of the characters 'a'-to-'z' as above. ", + "Show the strings and their encoding here.", + "Add a check to ensure that the decoded string is the same as the original.", + "

    The strings are:

    broood

    ", + "

    bananaaa

    ", + "

    hiphophiphop

    (Note the spellings.)

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "var encodeMTF = function (word) {", + " var init = {wordAsNumbers: [], charList: 'abcdefghijklmnopqrstuvwxyz'.split('')};", + "", + " return word.split('').reduce(function (acc, char) {", + " var charNum = acc.charList.indexOf(char); //get index of char", + " acc.wordAsNumbers.push(charNum); //add original index to acc", + " acc.charList.unshift(acc.charList.splice(charNum, 1)[0]); //put at beginning of list", + " return acc;", + " }, init).wordAsNumbers; //return number list", + "};", + "", + "var decodeMTF = function (numList) {", + " var init = {word: '', charList: 'abcdefghijklmnopqrstuvwxyz'.split('')};", + "", + " return numList.reduce(function (acc, num) {", + " acc.word += acc.charList[num];", + " acc.charList.unshift(acc.charList.splice(num, 1)[0]); //put at beginning of list", + " return acc;", + " }, init).word;", + "};", + "", + "//test our algorithms", + "var words = ['broood', 'bananaaa', 'hiphophiphop'];", + "var encoded = words.map(encodeMTF);", + "var decoded = encoded.map(decodeMTF);", + "", + "//print results", + "console.log(\"from encoded:\");", + "console.log(encoded);", + "console.log(\"from decoded:\");", + "console.log(decoded);", + "{{out}}", + "
    from encoded:",
    +        "[",
    +        "  [1, 17, 15, 0, 0, 5],",
    +        "  [1, 1, 13, 1, 1, 1, 0, 0],",
    +        "  [7, 8, 15, 2, 15, 2, 2, 3, 2, 2, 3, 2]",
    +        "]",
    +        "from decoded:",
    +        "['broood', 'bananaaa', 'hiphophiphop']
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f25", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var encodeMTF = function (word) {\n var init = {wordAsNumbers: [], charList: 'abcdefghijklmnopqrstuvwxyz'.split('')};\n\n return word.split('').reduce(function (acc, char) {\n var charNum = acc.charList.indexOf(char); //get index of char\n acc.wordAsNumbers.push(charNum); //add original index to acc\n acc.charList.unshift(acc.charList.splice(charNum, 1)[0]); //put at beginning of list\n return acc;\n }, init).wordAsNumbers; //return number list\n};\n\nvar decodeMTF = function (numList) {\n var init = {word: '', charList: 'abcdefghijklmnopqrstuvwxyz'.split('')};\n\n return numList.reduce(function (acc, num) {\n acc.word += acc.charList[num];\n acc.charList.unshift(acc.charList.splice(num, 1)[0]); //put at beginning of list\n return acc;\n }, init).word;\n};\n\n//test our algorithms\nvar words = ['broood', 'bananaaa', 'hiphophiphop'];\nvar encoded = words.map(encodeMTF);\nvar decoded = encoded.map(decodeMTF);\n\n//print results\nconsole.log(\"from encoded:\");\nconsole.log(encoded);\nconsole.log(\"from decoded:\");\nconsole.log(decoded);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Multifactorial", + "type": "Waypoint", + "description": [ + "

    The factorial of a number, written as $n!$, is defined as $n! = n(n-1)(n-2)...(2)(1)$.

    Multifactorials generalize factorials as follows:

    ", + "

    $n! = n(n-1)(n-2)...(2)(1)$

    ", + "

    $n!! = n(n-2)(n-4)...$

    ", + "

    $n!! ! = n(n-3)(n-6)...$

    ", + "

    $n!! !! = n(n-4)(n-8)...$

    ", + "

    $n!! !! ! = n(n-5)(n-10)...$

    In all cases, the terms in the products are positive integers.

    If we define the degree of the multifactorial as the difference in successive terms that are multiplied together for a multifactorial (the number of exclamation marks), then the task is twofold:

    ", + "Write a function that given n and the degree, calculates the multifactorial.", + "Use the function to generate and display here a table of the first ten members (1 to 10) of the first five degrees of multifactorial.

    Note: The wikipedia entry on multifactorials gives a different formula. This task uses the Wolfram mathworld definition.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Iterative===", + "{{trans|C}}", + "", + "function multifact(n, deg){", + "\tvar result = n;", + "\twhile (n >= deg + 1){", + "\t\tresult *= (n - deg);", + "\t\tn -= deg;", + "\t}", + "\treturn result;", + "}", + "", + "", + "", + "function test (n, deg) {", + "\tfor (var i = 1; i <= deg; i ++) {", + "\t\tvar results = '';", + "\t\tfor (var j = 1; j <= n; j ++) {", + "\t\t\tresults += multifact(j, i) + ' ';", + "\t\t}", + "\t\tconsole.log('Degree ' + i + ': ' + results);", + "\t}", + "}", + "", + "", + "{{out}}", + "", + "test(10, 5)", + "Degree 1: 1 2 6 24 120 720 5040 40320 362880 3628800 ", + "Degree 2: 1 2 3 8 15 48 105 384 945 3840 ", + "Degree 3: 1 2 3 4 10 18 28 80 162 280 ", + "Degree 4: 1 2 3 4 5 12 21 32 45 120 ", + "Degree 5: 1 2 3 4 5 6 14 24 36 50 ", + "", + "", + "===Recursive===", + "", + "{{trans|C}}", + "function multifact(n, deg){", + " return n <= deg ? n : n * multifact(n - deg, deg);", + "}", + "", + "{{test}}", + "function test (n, deg) {", + " for (var i = 1; i <= deg; i ++) {", + " var results = '';", + " for (var j = 1; j <= n; j ++) {", + " results += multifact(j, i) + ' ';", + " }", + " console.log('Degree ' + i + ': ' + results);", + " }", + "}", + "{{Out}}", + "", + "test(10, 5)", + "Degree 1: 1 2 6 24 120 720 5040 40320 362880 3628800 ", + "Degree 2: 1 2 3 8 15 48 105 384 945 3840 ", + "Degree 3: 1 2 3 4 10 18 28 80 162 280 ", + "Degree 4: 1 2 3 4 5 12 21 32 45 120 ", + "Degree 5: 1 2 3 4 5 6 14 24 36 50 ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f26", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nfunction multifact(n, deg){\n\tvar result = n;\n\twhile (n >= deg + 1){\n\t\tresult *= (n - deg);\n\t\tn -= deg;\n\t}\n\treturn result;\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Multiple distinct objects", + "type": "Waypoint", + "description": [ + "

    Create a sequence (array, list, whatever) consisting of n distinct, initialized items of the same type. n should be determined at runtime.

    By distinct we mean that if they are mutable, changes to one do not affect all others; if there is an appropriate equality operator they are considered unequal; etc. The code need not specify a particular kind of distinction, but do not use e.g. a numeric-range generator which does not generalize.

    By initialized we mean that each item must be in a well-defined state appropriate for its type, rather than e.g. arbitrary previous memory contents in an array allocation. Do not show only an initialization technique which initializes only to \"zero\" values (e.g. calloc() or int a[n] = {}; in C), unless user-defined types can provide definitions of \"zero\" for that type.

    This task was inspired by the common error of intending to do this, but instead creating a sequence of n references to the same mutable object; it might be informative to show the way to do that as well, both as a negative example and as how to do it when that's all that's actually necessary.

    This task is most relevant to languages operating in the pass-references-by-value style (most object-oriented, garbage-collected, and/or 'dynamic' languages).

    See also: Closures/Value capture

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "var a = new Array(n);", + "for (var i = 0; i < n; i++)", + " a[i] = new Foo();", + "", + "", + "===ES6===", + "", + "(n => {", + "", + " let nObjects = n => Array.from({", + " length: n + 1", + " }, (_, i) => {", + " // optionally indexed object constructor", + " return {", + " index: i", + " };", + " });", + "", + " return nObjects(6);", + "", + "})(6);", + "", + "", + "{{Out}}", + "[{\"index\":0}, {\"index\":1}, {\"index\":2}, {\"index\":3}, ", + "{\"index\":4}, {\"index\":5}, {\"index\":6}]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f27", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var a = new Array(n);\nfor (var i = 0; i < n; i++)\n a[i] = new Foo();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Multiple regression", + "type": "Waypoint", + "description": [ + "Task:", + "

    Given a set of data vectors in the following format:

    $y = \\{ y_1, y_2, ..., y_n \\}\\,$

    $X_i = \\{ x_{i1}, x_{i2}, ..., x_{in} \\}, i \\in 1..k\\,$

    Compute the vector $\\beta = \\{ \\beta_1, \\beta_2, ..., \\beta_k \\}$ using ordinary least squares regression using the following equation:

    $y_j = \\Sigma_i \\beta_i \\cdot x_{ij} , j \\in 1..n$

    You can assume y is given to you as a vector (a one-dimensional array), and X is given to you as a two-dimensional array (i.e. matrix).

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|SpiderMonkey}} for the print() and ''Array''.map() functions.", + "", + "{{trans|Ruby}}", + "", + "Extends the Matrix class from [[Matrix Transpose#JavaScript]], [[Matrix multiplication#JavaScript]], [[Reduced row echelon form#JavaScript]].", + "Uses the IdentityMatrix from [[Matrix exponentiation operator#JavaScript]]", + "// modifies the matrix \"in place\"", + "Matrix.prototype.inverse = function() {", + " if (this.height != this.width) {", + " throw \"can't invert a non-square matrix\";", + " } ", + "", + " var I = new IdentityMatrix(this.height);", + " for (var i = 0; i < this.height; i++) ", + " this.mtx[i] = this.mtx[i].concat(I.mtx[i])", + " this.width *= 2;", + "", + " this.toReducedRowEchelonForm();", + "", + " for (var i = 0; i < this.height; i++) ", + " this.mtx[i].splice(0, this.height);", + " this.width /= 2;", + "", + " return this;", + "}", + "", + "function ColumnVector(ary) {", + " return new Matrix(ary.map(function(v) {return [v]}))", + "}", + "ColumnVector.prototype = Matrix.prototype", + "", + "Matrix.prototype.regression_coefficients = function(x) {", + " var x_t = x.transpose();", + " return x_t.mult(x).inverse().mult(x_t).mult(this);", + "}", + "", + "// the Ruby example", + "var y = new ColumnVector([1,2,3,4,5]);", + "var x = new ColumnVector([2,1,3,4,5]);", + "print(y.regression_coefficients(x));", + "print();", + "", + "// the Tcl example", + "y = new ColumnVector([", + " 52.21, 53.12, 54.48, 55.84, 57.20, 58.57, 59.93, 61.29, ", + " 63.11, 64.47, 66.28, 68.10, 69.92, 72.19, 74.46", + "]);", + "x = new Matrix(", + " [1.47,1.50,1.52,1.55,1.57,1.60,1.63,1.65,1.68,1.70,1.73,1.75,1.78,1.80,1.83].map(", + " function(v) {return [Math.pow(v,0), Math.pow(v,1), Math.pow(v,2)]}", + " )", + ");", + "print(y.regression_coefficients(x));", + "{{out}}", + "
    0.9818181818181818",
    +        "",
    +        "128.8128035798277",
    +        "-143.1620228653037",
    +        "61.960325442985436
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f28", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// modifies the matrix \"in place\"\nMatrix.prototype.inverse = function() {\n if (this.height != this.width) {\n throw \"can't invert a non-square matrix\";\n } \n\n var I = new IdentityMatrix(this.height);\n for (var i = 0; i < this.height; i++) \n this.mtx[i] = this.mtx[i].concat(I.mtx[i])\n this.width *= 2;\n\n this.toReducedRowEchelonForm();\n\n for (var i = 0; i < this.height; i++) \n this.mtx[i].splice(0, this.height);\n this.width /= 2;\n\n return this;\n}\n\nfunction ColumnVector(ary) {\n return new Matrix(ary.map(function(v) {return [v]}))\n}\nColumnVector.prototype = Matrix.prototype\n\nMatrix.prototype.regression_coefficients = function(x) {\n var x_t = x.transpose();\n return x_t.mult(x).inverse().mult(x_t).mult(this);\n}\n\n// the Ruby example\nvar y = new ColumnVector([1,2,3,4,5]);\nvar x = new ColumnVector([2,1,3,4,5]);\nprint(y.regression_coefficients(x));\nprint();\n\n// the Tcl example\ny = new ColumnVector([\n 52.21, 53.12, 54.48, 55.84, 57.20, 58.57, 59.93, 61.29, \n 63.11, 64.47, 66.28, 68.10, 69.92, 72.19, 74.46\n]);\nx = new Matrix(\n [1.47,1.50,1.52,1.55,1.57,1.60,1.63,1.65,1.68,1.70,1.73,1.75,1.78,1.80,1.83].map(\n function(v) {return [Math.pow(v,0), Math.pow(v,1), Math.pow(v,2)]}\n )\n);\nprint(y.regression_coefficients(x));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Multiplication tables", + "type": "Waypoint", + "description": [ + "Task:", + "

    Produce a formatted 12×12 multiplication table of the kind memorized by rote when in primary (or elementary) school.

    ", + "

    Only print the top half triangle of products.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Imperative===", + "", + "", + "", + "", + "12 times table", + "", + "", + "", + "", + "
    ", + "", + "
    ", + "", + "{{out}} (minus the style):", + "
    x123456789101112
    1123456789101112
    2 4681012141618202224
    3 9121518212427303336
    4 162024283236404448
    5 2530354045505560
    6 36424854606672
    7 495663707784
    8 6472808896
    9 819099108
    10 100110120
    11 121132
    12 144
    ", + "", + "", + "===Functional (ES5)===", + "", + "(function (m, n) {", + " ", + " // [m..n]", + " function range(m, n) {", + " return Array.apply(null, Array(n - m + 1)).map(function (x, i) {", + " return m + i;", + " });", + " }", + " ", + " // Monadic bind (chain) for lists", + " function mb(xs, f) {", + " return [].concat.apply([], xs.map(f));", + " }", + " ", + " var rng = range(m, n),", + " ", + " lstTable = [['x'].concat( rng )]", + " .concat(mb(rng, function (x) {", + " return [[x].concat(mb(rng, function (y) {", + " ", + " return y < x ? [''] : [x * y]; // triangle only", + " ", + " }))]}));", + " ", + " /* FORMATTING OUTPUT */", + " ", + " // [[a]] -> bool -> s -> s", + " function wikiTable(lstRows, blnHeaderRow, strStyle) {", + " return '{| class=\"wikitable\" ' + (", + " strStyle ? 'style=\"' + strStyle + '\"' : ''", + " ) + lstRows.map(function (lstRow, iRow) {", + " var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|');", + " ", + " return '\\n|-\\n' + strDelim + ' ' + lstRow.map(function (v) {", + " return typeof v === 'undefined' ? ' ' : v;", + " }).join(' ' + strDelim + strDelim + ' ');", + " }).join('') + '\\n|}';", + " }", + " ", + " // Formatted as WikiTable", + " return wikiTable(", + " lstTable, true,", + " 'text-align:center;width:33em;height:33em;table-layout:fixed;'", + " ) + '\\n\\n' +", + " ", + " // or simply stringified as JSON", + " JSON.stringify(lstTable);", + " ", + "})(1, 12);", + "", + "{{out}}", + "", + "{| class=\"wikitable\" style=\"text-align:center;width:33em;height:33em;table-layout:fixed;\"", + "|-", + "! x !! 1 !! 2 !! 3 !! 4 !! 5 !! 6 !! 7 !! 8 !! 9 !! 10 !! 11 !! 12", + "|-", + "| 1 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12", + "|-", + "| 2 || || 4 || 6 || 8 || 10 || 12 || 14 || 16 || 18 || 20 || 22 || 24", + "|-", + "| 3 || || || 9 || 12 || 15 || 18 || 21 || 24 || 27 || 30 || 33 || 36", + "|-", + "| 4 || || || || 16 || 20 || 24 || 28 || 32 || 36 || 40 || 44 || 48", + "|-", + "| 5 || || || || || 25 || 30 || 35 || 40 || 45 || 50 || 55 || 60", + "|-", + "| 6 || || || || || || 36 || 42 || 48 || 54 || 60 || 66 || 72", + "|-", + "| 7 || || || || || || || 49 || 56 || 63 || 70 || 77 || 84", + "|-", + "| 8 || || || || || || || || 64 || 72 || 80 || 88 || 96", + "|-", + "| 9 || || || || || || || || || 81 || 90 || 99 || 108", + "|-", + "| 10 || || || || || || || || || || 100 || 110 || 120", + "|-", + "| 11 || || || || || || || || || || || 121 || 132", + "|-", + "| 12 || || || || || || || || || || || || 144", + "|}", + "", + "[[\"x\",1,2,3,4,5,6,7,8,9,10,11,12],", + " [1,1,2,3,4,5,6,7,8,9,10,11,12],", + " [2,\"\",4,6,8,10,12,14,16,18,20,22,24],", + " [3,\"\",\"\",9,12,15,18,21,24,27,30,33,36],", + " [4,\"\",\"\",\"\",16,20,24,28,32,36,40,44,48],", + " [5,\"\",\"\",\"\",\"\",25,30,35,40,45,50,55,60],", + " [6,\"\",\"\",\"\",\"\",\"\",36,42,48,54,60,66,72],", + " [7,\"\",\"\",\"\",\"\",\"\",\"\",49,56,63,70,77,84],", + " [8,\"\",\"\",\"\",\"\",\"\",\"\",\"\",64,72,80,88,96],", + " [9,\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",81,90,99,108],", + " [10,\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",100,110,120],", + " [11,\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",121,132],", + " [12,\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",144]]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f29", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function (m, n) {\n \n // [m..n]\n function range(m, n) {\n return Array.apply(null, Array(n - m + 1)).map(function (x, i) {\n return m + i;\n });\n }\n \n // Monadic bind (chain) for lists\n function mb(xs, f) {\n return [].concat.apply([], xs.map(f));\n }\n \n var rng = range(m, n),\n \n lstTable = [['x'].concat( rng )]\n .concat(mb(rng, function (x) {\n return [[x].concat(mb(rng, function (y) {\n \n return y < x ? [''] : [x * y]; // triangle only\n \n }))]}));\n \n /* FORMATTING OUTPUT */\n \n // [[a]] -> bool -> s -> s\n function wikiTable(lstRows, blnHeaderRow, strStyle) {\n return '{| class=\"wikitable\" ' + (\n strStyle ? 'style=\"' + strStyle + '\"' : ''\n ) + lstRows.map(function (lstRow, iRow) {\n var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|');\n \n return '\\n|-\\n' + strDelim + ' ' + lstRow.map(function (v) {\n return typeof v === 'undefined' ? ' ' : v;\n }).join(' ' + strDelim + strDelim + ' ');\n }).join('') + '\\n|}';\n }\n \n // Formatted as WikiTable\n return wikiTable(\n lstTable, true,\n 'text-align:center;width:33em;height:33em;table-layout:fixed;'\n ) + '\\n\\n' +\n \n // or simply stringified as JSON\n JSON.stringify(lstTable);\n \n})(1, 12);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Multiplicative order", + "type": "Waypoint", + "description": [ + "

    The multiplicative order of a relative to m is the least positive integer n such that a^n is 1 (modulo m).

    ", + "Example:", + "

    The multiplicative order of 37 relative to 1000 is 100 because 37^100 is 1 (modulo 1000), and no number smaller than 100 would do.

    ", + "

    One possible algorithm that is efficient also for large numbers is the following: By the Chinese Remainder Theorem, it's enough to calculate the multiplicative order for each prime exponent p^k of m, and

    ", + "

    combine the results with the least common multiple operation.

    Now the order of a with regard to p^k must divide Φ(p^k). Call this number t, and determine it's factors q^e. Since each multiple of the order will also yield 1 when used as exponent for a, it's enough to find the least d such that (q^d)*(t/(q^e)) yields 1 when used as exponent.

    ", + "Task:", + "

    Implement a routine to calculate the multiplicative order along these lines. You may assume that routines to determine the factorization into prime powers are available in some library.

    ----

    An algorithm for the multiplicative order can be found in Bach & Shallit, Algorithmic Number Theory, Volume I: Efficient Algorithms, The MIT Press, 1996:

    Exercise 5.8, page 115:

    Suppose you are given a prime p and a complete factorization

    ", + "

    of p-1. Show how to compute the order of an

    ", + "

    element a in (Z/(p))* using O((lg p)4/(lg lg p)) bit

    ", + "

    operations.

    Solution, page 337:

    Let the prime factorization of p-1 be q1e1q2e2...qkek . We use the following observation:

    ", + "

    if x^((p-1)/qifi) = 1 (mod p) ,

    ", + "

    and fi=ei or x^((p-1)/qifi+1) != 1 (mod p) , then qiei-fi||ordp x. (This follows by combining Exercises 5.1 and 2.10.)

    Hence it suffices to find, for each i , the exponent fi such that the condition above holds.

    This can be done as follows: first compute q1e1, q2e2, ... ,

    ", + "

    qkek . This can be done using O((lg p)2) bit operations. Next, compute y1=(p-1)/q1e1, ... , yk=(p-1)/qkek .

    ", + "

    This can be done using O((lg p)2) bit operations. Now, using the binary method,

    ", + "

    compute x1=ay1(mod p), ... , xk=ayk(mod p) .

    ", + "

    This can be done using O(k(lg p)3) bit operations, and k=O((lg p)/(lg lg p)) by Theorem 8.8.10.

    ", + "

    Finally, for each i , repeatedly raise xi to the qi-th power (mod p) (as many as ei-1 times), checking to see when 1 is obtained.

    ", + "

    This can be done using O((lg p)3) steps.

    ", + "

    The total cost is dominated by O(k(lg p)3) , which is O((lg p)4/(lg lg p)).

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f2a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Multisplit", + "type": "Waypoint", + "description": [ + "

    It is often necessary to split a string into pieces

    ", + "

    based on several different (potentially multi-character) separator strings,

    ", + "

    while still retaining the information about which separators were present in the input.

    This is particularly useful when doing small parsing tasks.

    ", + "

    The task is to write code to demonstrate this.

    The function (or procedure or method, as appropriate) should

    ", + "

    take an input string and an ordered collection of separators.

    The order of the separators is significant:

    ", + "

    The delimiter order represents priority in matching, with the first defined delimiter having the highest priority.

    ", + "

    In cases where there would be an ambiguity as to

    ", + "

    which separator to use at a particular point

    ", + "

    (e.g., because one separator is a prefix of another)

    ", + "

    the separator with the highest priority should be used.

    ", + "

    Delimiters can be reused and the output from the function should be an ordered sequence of substrings.

    Test your code using the input string “a!===b=!=c” and the separators “==”, “!=” and “=”.

    For these inputs the string should be parsed as \"a\" (!=) \"\" (==) \"b\" (=) \"\" (!=) \"c\", where matched delimiters are shown in parentheses, and separated strings are quoted, so our resulting output is \"a\", empty string, \"b\", empty string, \"c\".

    ", + "

    Note that the quotation marks are shown for clarity and do not form part of the output.

    Extra Credit: provide information that indicates which separator was matched at each separation point and where in the input string that separator was matched.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Based on Ruby example.", + "{{libheader|Underscore.js}}", + "RegExp.escape = function(text) {", + " return text.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, \"\\\\$&\");", + "}", + "", + "multisplit = function(string, seps) {", + " var sep_regex = RegExp(_.map(seps, function(sep) { return RegExp.escape(sep); }).join('|'));", + " return string.split(sep_regex);", + "}", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f2b", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "RegExp.escape = function(text) {\n return text.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, \"\\\\$&\");\n}\n\nmultisplit = function(string, seps) {\n var sep_regex = RegExp(_.map(seps, function(sep) { return RegExp.escape(sep); }).join('|'));\n return string.split(sep_regex);\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Munching squares", + "type": "Waypoint", + "description": [ + "

    Render a graphical pattern where each pixel is colored by the value of 'x xor y' from an arbitrary color table.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f2c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Mutual recursion", + "type": "Waypoint", + "description": [ + "

    Two functions are said to be mutually recursive if the first calls the second,

    ", + "

    and in turn the second calls the first.

    Write two mutually recursive functions that compute members of the Hofstadter Female and Male sequences defined as:

    ", + "

    ", + "

    $

    ", + "

    \\begin{align}

    ", + "

    F(0)&=1\\ ;\\ M(0)=0 \\\\

    ", + "

    F(n)&=n-M(F(n-1)), \\quad n>0 \\\\

    ", + "

    M(n)&=n-F(M(n-1)), \\quad n>0.

    ", + "

    \\end{align}

    ", + "

    $

    ", + "
    (If a language does not allow for a solution using mutually recursive functions ", + "

    then state this rather than give a solution by other means).

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function f(num) {", + " return (num === 0) ? 1 : num - m(f(num - 1));", + "}", + "", + "function m(num) {", + " return (num === 0) ? 0 : num - f(m(num - 1));", + "}", + "", + "function range(m, n) {", + " return Array.apply(null, Array(n - m + 1)).map(", + " function (x, i) { return m + i; }", + " );", + "}", + "", + "var a = range(0, 19);", + "", + "//return a new array of the results and join with commas to print", + "console.log(a.map(function (n) { return f(n); }).join(', '));", + "console.log(a.map(function (n) { return m(n); }).join(', '));", + "{{out}}", + "
    1,1,2,2,3,3,4,5,5,6,6,7,8,8,9,9,10,11,11,12",
    +        "0,0,1,2,2,3,4,4,5,6,6,7,7,8,9,9,10,11,11,12
    ", + "", + "ES6 implementation", + "var f = num => (num === 0) ? 1 : num - m(f(num - 1));", + "var m = num => (num === 0) ? 0 : num - f(m(num - 1));", + "", + "function range(m, n) {", + " return Array.apply(null, Array(n - m + 1)).map(", + " function (x, i) { return m + i; }", + " );", + "}", + "", + "var a = range(0, 19);", + "", + "//return a new array of the results and join with commas to print", + "console.log(a.map(n => f(n)).join(', '));", + "console.log(a.map(n => m(n)).join(', '));", + "", + "More ES6 implementation", + "", + "var range = (m, n) => Array(... Array(n - m + 1)).map((x, i) => m + i)", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f2d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function f(num) {\n return (num === 0) ? 1 : num - m(f(num - 1));\n}\n\nfunction m(num) {\n return (num === 0) ? 0 : num - f(m(num - 1));\n}\n\nfunction range(m, n) {\n return Array.apply(null, Array(n - m + 1)).map(\n function (x, i) { return m + i; }\n );\n}\n\nvar a = range(0, 19);\n\n//return a new array of the results and join with commas to print\nconsole.log(a.map(function (n) { return f(n); }).join(', '));\nconsole.log(a.map(function (n) { return m(n); }).join(', '));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Narcissistic decimal number", + "type": "Waypoint", + "description": [ + "

    A Narcissistic decimal number is a non-negative integer, $n$, that is equal to the sum of the $m$-th powers of each of the digits in the decimal representation of $n$, where $m$ is the number of digits in the decimal representation of $n$.

    Narcissistic (decimal) numbers are sometimes called Armstrong numbers, named after Michael F. Armstrong.

    ", + "An example:", + "

    :::* if $n$ is 153

    ", + "

    :::* then $m$, (the number of decimal digits) is 3

    ", + "

    :::* we have 13 + 53 + 33 = 1 + 125 + 27 = 153

    ", + "

    :::* and so 153 is a narcissistic decimal number

    ", + "Task:", + "

    Generate and show here the first 25 narcissistic decimal numbers.

    ", + "

    Note: $0^1 = 0$, the first in the series.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "{{trans|Java}}", + "function isNarc(x) {", + " var str = x.toString(),", + " i,", + " sum = 0,", + " l = str.length;", + " if (x < 0) {", + " return false;", + " } else {", + " for (i = 0; i < l; i++) {", + " sum += Math.pow(str.charAt(i), l);", + " }", + " }", + " return sum == x;", + "}", + "function main(){", + " var n = []; ", + " for (var x = 0, count = 0; count < 25; x++){", + " if (isNarc(x)){", + " n.push(x);", + " count++;", + " }", + " }", + " return n.join(' '); ", + "}", + "{{out}}", + "
    \"0 1 2 3 4 5 6 7 8 9 153 370 371 407 1634 8208 9474 54748 92727 93084 548834 1741725 4210818 9800817 9926315\"
    ", + "", + "===ES6===", + "====Exhaustive search (integer series)====", + "(() => {", + " 'use strict';", + " ", + " // digits :: Int -> [Int]", + " const digits = n => n.toString()", + " .split('')", + " .map(x => parseInt(x, 10));", + " ", + " // pow :: Int -> Int -> Int", + " const pow = Math.pow;", + " ", + " // isNarc :: Int -> Bool", + " const isNarc = n => {", + " const", + " ds = digits(n),", + " len = ds.length;", + " ", + " return ds.reduce((a, x) =>", + " a + pow(x, len), 0) === n;", + " };", + " ", + " // until :: (a -> Bool) -> (a -> a) -> a -> a", + " const until = (p, f, x) => {", + " let v = x;", + " while (!p(v)) v = f(v);", + " return v;", + " };", + " ", + " return until(", + " x => x.narc.length > 24,", + " x => ({", + " n: x.n + 1,", + " narc: (isNarc(x.n) ? x.narc.concat(x.n) : x.narc)", + " }), {", + " n: 0,", + " narc: []", + " }", + " )", + " .narc", + "})();", + "{{Out}}", + "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407, 1634, 8208, 9474, 54748, 92727, 93084, 548834, 1741725, 4210818, 9800817, 9926315]", + "", + "", + "====Reduced search (unordered digit combinations)====", + "{{Trans|Haskell}}", + "As summing the nth power of the digits is unaffected by digit order, we can reduce the search space by filtering digit combinations of given length and arbitrary order, rather than filtering a full integer sequence.", + "", + "In this way we can find the 25th narcissistic number after '''length(concatMap(digitPowerSums, enumFromTo(0, 7))) === 19447''' tests – an improvement on the exhaustive trawl through '''9926315''' integers.", + "", + "(Generating the unordered digit combinations directly as power sums allows faster testing later, and needs less space)", + "(() => {", + " 'use strict';", + "", + " // DAFFODILS --------------------------------------------------------------", + "", + " // narcissiOfLength :: Int -> [Int]", + " const narcissiOfLength = n =>", + " n > 0 ? filter(curry(isDaffodil)(n), digitPowerSums(n)) : [0];", + "", + " // Do the decimal digits of N, each raised to the power E, sum to N itself ?", + "", + "// isDaffodil :: Int -> Int -> Bool", + "const isDaffodil = (e, n) => {", + " const", + " powerSum = (n, xs) => xs.reduce((a, x) => a + Math.pow(x, n), 0),", + " digitList = n => (n > 0) ? (", + " cons((n % 10), digitList(Math.floor(n / 10)))", + " ) : [],", + " ds = digitList(n);", + " return e === ds.length && n === powerSum(e, ds);", + "};", + "", + " // The subset of integers of n digits that actually need daffodil checking:", + "", + " // (Flattened leaves of a tree of unique digit combinations, in which", + " // order is not significant. Digit sequence doesn't affect power summing)", + "", + " // digitPowerSums :: Int -> [Int]", + " const digitPowerSums = nDigits => {", + " const", + " digitPowers = map(x => [x, pow(x, nDigits)], enumFromTo(0, 9)),", + " treeGrowth = (n, parentPairs) => (n > 0) ? (", + " treeGrowth(n - 1,", + " isNull(parentPairs) ? (", + " digitPowers", + " ) : concatMap(([parentDigit, parentSum]) =>", + " map(([leafDigit, leafSum]) => //", + " [leafDigit, parentSum + leafSum],", + " take(parentDigit + 1, digitPowers)", + " ),", + " parentPairs", + " ))", + " ) : parentPairs;", + " return map(snd, treeGrowth(nDigits, []));", + " };", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // enumFromTo :: Int -> Int -> Maybe Int -> [Int]", + " const enumFromTo = (m, n, step) => {", + " const d = (step || 1) * (n >= m ? 1 : -1);", + " return Array.from({", + " length: Math.floor((n - m) / d) + 1", + " }, (_, i) => m + (i * d));", + " };", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " const concatMap = (f, xs) => [].concat.apply([], xs.map(f));", + "", + " // cons :: a -> [a] -> [a]", + " const cons = (x, xs) => [x].concat(xs);", + "", + " // 2 or more arguments", + " // curry :: Function -> Function", + " const curry = (f, ...args) => {", + " const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :", + " function () {", + " return go(xs.concat([].slice.apply(arguments)));", + " };", + " return go([].slice.call(args, 1));", + " };", + "", + " // filter :: (a -> Bool) -> [a] -> [a]", + " const filter = (f, xs) => xs.filter(f);", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = curry((f, xs) => xs.map(f));", + "", + " // isNull :: [a] -> Bool", + " const isNull = xs => (xs instanceof Array) ? xs.length < 1 : undefined;", + "", + " // length :: [a] -> Int", + " const length = xs => xs.length;", + "", + " // pow :: Int -> Int -> Int", + " const pow = Math.pow", + "", + " // take :: Int -> [a] -> [a]", + " const take = (n, xs) => xs.slice(0, n);", + "", + " // show ::", + " // (a -> String) f, Num n =>", + " // a -> maybe f -> maybe n -> String", + " const show = JSON.stringify;", + "", + " // snd :: (a, b) -> b", + " const snd = tpl => Array.isArray(tpl) ? tpl[1] : undefined;", + "", + "", + " // TEST -------------------------------------------------------------------", + "", + " // return length(concatMap(digitPowerSums, enumFromTo(0, 7)));", + "", + " return show(", + " //digitPowerSums(3)", + " concatMap(narcissiOfLength, enumFromTo(0, 7))", + " );", + "})();", + "{{Out}}", + "(Tested in Atom editor, using Script package)", + "
    [0,1,2,3,4,5,6,7,8,9,153,370,371,407,1634,8208,9474,54748,92727,93084,548834,1741725,4210818,9800817,9926315]",
    +        "[Finished in 0.118s]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f30", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function isNarc(x) {\n var str = x.toString(),\n i,\n sum = 0,\n l = str.length;\n if (x < 0) {\n return false;\n } else {\n for (i = 0; i < l; i++) {\n sum += Math.pow(str.charAt(i), l);\n }\n }\n return sum == x;\n}\nfunction main(){\n var n = []; \n for (var x = 0, count = 0; count < 25; x++){\n if (isNarc(x)){\n n.push(x);\n count++;\n }\n }\n return n.join(' '); \n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Narcissist", + "type": "Waypoint", + "description": [ + "

    Quoting from the Esolangs wiki page:

    ", + "

    A narcissist (or Narcissus program) is the decision-problem version of a quine.

    ", + "
    ", + "

    A quine, when run, takes no input, but produces a copy of its own source code at its output. In contrast, a narcissist reads a string of symbols from its input, and produces no output except a \"1\" or \"accept\" if that string matches its own source code, or a \"0\" or \"reject\" if it does not.

    ", + "

    For concreteness, in this task we shall assume that symbol = character.

    The narcissist should be able to cope with any finite input, whatever its length.

    Any form of output is allowed, as long as the program always halts, and \"accept\", \"reject\" and \"not yet finished\" are distinguishable.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|SpiderMonkey|1.7.0}}", + "Based upon [[Quine#Using_eval|one of the quines]]. Outputs 'true' if source is equal to inputted line (newline terminated), 'false' otherwise.", + "var code='var q=String.fromCharCode(39);print(\"var code=\" + q + code + q + \"; eval(code)\" == readline())'; eval(code)", + "", + "{{works with|JScript}}", + "var oFSO = new ActiveXObject(\"Scripting.FileSystemObject\");", + "function readfile(fname) {", + "\tvar h = oFSO.OpenTextFile(fname, 1, false);", + "\tvar result = h.ReadAll();", + "\th.Close();", + "\treturn result;", + "}", + "", + "if (0 === WScript.Arguments.UnNamed.Count) {", + "\tWScript.Echo(WScript.ScriptName,\"filename\");", + "\tWScript.Quit();", + "}", + "", + "// first read self ", + "var self = readfile(WScript.ScriptFullName);", + "// read whatever file is given on commmand line", + "var whatever = readfile(WScript.Arguments.UnNamed(0));", + "", + "// compare and contrast", + "WScript.Echo(self === whatever ? \"Accept\" : \"Reject\");", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f31", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var code='var q=String.fromCharCode(39);print(\"var code=\" + q + code + q + \"; eval(code)\" == readline())'; eval(code)\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Natural sorting", + "type": "Waypoint", + "description": [ + "

    Natural sorting is the sorting of text that does more than rely on the

    ", + "

    order of individual characters codes to make the finding of

    ", + "

    individual strings easier for a human reader.

    There is no \"one true way\" to do this, but for the purpose of this task 'natural' orderings might include:

    ", + "

    1. Ignore leading, trailing and multiple adjacent spaces

    ", + "

    2. Make all whitespace characters equivalent.

    ", + "

    3. Sorting without regard to case.

    ", + "

    4. Sorting numeric portions of strings in numeric order. That is split the string into fields on numeric boundaries, then sort on each field, with the rightmost fields being the most significant, and numeric fields of integers treated as numbers.

    ", + "

    : foo9.txt before foo10.txt

    ", + "

    : As well as ... x9y99 before x9y100, before x10y0

    ", + "

    : ... (for any number of groups of integers in a string).

    ", + "

    5. Title sorts: without regard to a leading, very common, word such

    ", + "

    : as 'The' in \"The thirty-nine steps\".

    ", + "

    6. Sort letters without regard to accents.

    ", + "

    7. Sort ligatures as separate letters.

    ", + "

    8. Replacements:

    ", + "

    : Sort german scharfes S (ß) as ss

    ", + "

    : Sort ſ, LATIN SMALL LETTER LONG S as s

    ", + "

    : Sort ʒ, LATIN SMALL LETTER EZH as s

    ", + "

    : ...

    Task Description", + "Implement the first four of the eight given features in a natural sorting routine/function/method...", + "Test each feature implemented separately with an ordered list of test strings from the 'Sample inputs' section below, and make sure your naturally sorted output is in the same order as other language outputs such as Python. ", + "Print and display your output.", + "For extra credit implement more than the first four.", + "

    Note: It is not necessary to have individual control of which features are active in the natural sorting routine at any time.

    Sample input:
    ",
    +        "Ignoring leading spacesText strings:",
    +        "['ignore leading spaces: 2-2', ' ignore leading spaces: 2-1', '  ignore leading spaces: 2+0', '   ignore leading spaces: 2+1']Ignoring multiple adjacent spaces (m.a.s)Text strings:",
    +        "['ignore m.a.s spaces: 2-2', 'ignore m.a.s  spaces: 2-1', 'ignore m.a.s   spaces: 2+0', 'ignore m.a.s    spaces: 2+1']",
    +        "Equivalent whitespace charactersText strings:",
    +        "['Equiv. spaces: 3-3', 'Equiv.\\rspaces: 3-2', 'Equiv.\\x0cspaces: 3-1', 'Equiv.\\x0bspaces: 3+0', 'Equiv.\\nspaces: 3+1', 'Equiv.\\tspaces: 3+2']Case Indepenent sortText strings:",
    +        "['cASE INDEPENENT: 3-2', 'caSE INDEPENENT: 3-1', 'casE INDEPENENT: 3+0', 'case INDEPENENT: 3+1']Numeric fields as numericsText strings:",
    +        "['foo100bar99baz0.txt', 'foo100bar10baz0.txt', 'foo1000bar99baz10.txt', 'foo1000bar99baz9.txt']Title sortsText strings:",
    +        "['The Wind in the Willows', 'The 40th step more', 'The 39 steps', 'Wanda']Equivalent accented characters (and case)Text strings:",
    +        "[u'Equiv. \\xfd accents: 2-2', u'Equiv. \\xdd accents: 2-1', u'Equiv. y accents: 2+0', u'Equiv. Y accents: 2+1']",
    +        "Separated ligaturesText strings:",
    +        "[u'\\u0132 ligatured ij', 'no ligature']Character replacementsText strings:",
    +        "[u'Start with an \\u0292: 2-2', u'Start with an \\u017f: 2-1', u'Start with an \\xdf: 2+0', u'Start with an s: 2+1']
    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "Implements the first four rules. Rule 4 works for digits up to 20 characters.", + "", + "", + "var nsort = function(input) {", + " var e = function(s) {", + " return (' ' + s + ' ').replace(/[\\s]+/g, ' ').toLowerCase().replace(/[\\d]+/, function(d) {", + " d = '' + 1e20 + d;", + " return d.substring(d.length - 20);", + " });", + " };", + " return input.sort(function(a, b) {", + " return e(a).localeCompare(e(b));", + " });", + "};", + "", + "console.log(nsort([", + " \"file10.txt\",", + " \"\\nfile9.txt\",", + " \"File11.TXT\",", + " \"file12.txt\"", + "]));", + "// -> ['\\nfile9.txt', 'file10.txt', 'File11.TXT', 'file12.txt']", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f32", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nvar nsort = function(input) {\n var e = function(s) {\n return (' ' + s + ' ').replace(/[\\s]+/g, ' ').toLowerCase().replace(/[\\d]+/, function(d) {\n d = '' + 1e20 + d;\n return d.substring(d.length - 20);\n });\n };\n return input.sort(function(a, b) {\n return e(a).localeCompare(e(b));\n });\n};\n\nconsole.log(nsort([\n \"file10.txt\",\n \"\\nfile9.txt\",\n \"File11.TXT\",\n \"file12.txt\"\n]));\n// -> ['\\nfile9.txt', 'file10.txt', 'File11.TXT', 'file12.txt']\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Nautical bell", + "type": "Waypoint", + "description": [ + "Task

    Write a small program that emulates a nautical bell producing a ringing bell pattern at certain times throughout the day.

    The bell timing should be in accordance with Greenwich Mean Time, unless locale dictates otherwise.

    It is permissible for the program to daemonize, or to slave off a scheduler, and it is permissible to use alternative notification methods (such as producing a written notice \"Two Bells Gone\"), if these are more usual for the system type.

    ", + "Cf.:", + "Sleep" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f33", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Non-continuous subsequences", + "type": "Waypoint", + "description": [ + "

    Consider some sequence of elements. (It differs from a mere set of elements by having an ordering among members.)

    A subsequence contains some subset of the elements of this sequence, in the same order.

    A continuous subsequence is one in which no elements are missing between the first and last elements of the subsequence.

    Note: Subsequences are defined structurally, not by their contents.

    ", + "

    So a sequence a,b,c,d will always have the same subsequences and continuous subsequences, no matter which values are substituted; it may even be the same value.

    Task: Find all non-continuous subsequences for a given sequence.

    Example: For the sequence 1,2,3,4, there are five non-continuous subsequences, namely:

    ", + "

    :::* 1,3

    ", + "

    :::* 1,4

    ", + "

    :::* 2,4

    ", + "

    :::* 1,3,4

    ", + "

    :::* 1,2,4

    Goal: There are different ways to calculate those subsequences. Demonstrate algorithm(s) that are natural for the language.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Uses powerset() function from [[Power Set#JavaScript|here]]. Uses a JSON stringifier from http://www.json.org/js.html", + "", + "{{works with|SpiderMonkey}}", + "function non_continuous_subsequences(ary) {", + " var non_continuous = new Array();", + " for (var i = 0; i < ary.length; i++) {", + " if (! is_array_continuous(ary[i])) {", + " non_continuous.push(ary[i]);", + " }", + " }", + " return non_continuous;", + "}", + "", + "function is_array_continuous(ary) {", + " if (ary.length < 2)", + " return true;", + " for (var j = 1; j < ary.length; j++) {", + " if (ary[j] - ary[j-1] != 1) {", + " return false;", + " }", + " }", + " return true;", + "}", + "", + "load('json2.js'); /* http://www.json.org/js.html */", + "", + "print(JSON.stringify( non_continuous_subsequences( powerset([1,2,3,4]))));", + "", + "{{out}}", + "
    [[1,3],[1,4],[2,4],[1,2,4],[1,3,4]]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f35", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function non_continuous_subsequences(ary) {\n var non_continuous = new Array();\n for (var i = 0; i < ary.length; i++) {\n if (! is_array_continuous(ary[i])) {\n non_continuous.push(ary[i]);\n }\n }\n return non_continuous;\n}\n\nfunction is_array_continuous(ary) {\n if (ary.length < 2)\n return true;\n for (var j = 1; j < ary.length; j++) {\n if (ary[j] - ary[j-1] != 1) {\n return false;\n }\n }\n return true;\n}\n\nload('json2.js'); /* http://www.json.org/js.html */\n\nprint(JSON.stringify( non_continuous_subsequences( powerset([1,2,3,4]))));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Non-decimal radices/Convert", + "type": "Waypoint", + "description": [ + "

    Number base conversion is when you express a stored integer in an integer base, such as in octal (base 8) or binary (base 2). It also is involved when you take a string representing a number in a given base and convert it to the stored integer form. Normally, a stored integer is in binary, but that's typically invisible to the user, who normally enters or sees stored integers as decimal.

    ", + "Task:", + "

    Write a function (or identify the built-in function) which is passed a non-negative integer to convert, and another integer representing the base.

    It should return a string containing the digits of the resulting number, without leading zeros except for the number 0 itself.

    For the digits beyond 9, one should use the lowercase English alphabet, where the digit a = 9+1, b = a+1, etc.

    For example: the decimal number 26 expressed in base 16 would be 1a.

    Write a second function which is passed a string and an integer base, and it returns an integer representing that string interpreted in that base.

    The programs may be limited by the word size or other such constraint of a given language. There is no need to do error checking for negatives, bases less than 2, or inappropriate digits.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "k = 26", + "s = k.toString(16) //gives 1a", + "i = parseInt('1a',16) //gives 26", + "//optional special case for hex:", + "i = +('0x'+s) //hexadecimal base 16, if s='1a' then i=26.", + "", + "Converts a number of arbitrary length from any base to any base", + "Limitation: Any base or number that causes accumulator to overflow will lose precision!!", + "Debugging or following the process is easy as it is kept in the expected base string format and order.", + "", + "var baselist = \"0123456789abcdefghijklmnopqrstuvwxyz\", listbase = [];", + "for(var i = 0; i < baselist.length; i++) listbase[baselist[i]] = i; // Generate baselist reverse", + "function basechange(snumber, frombase, tobase)", + "{", + " var i, t, to = new Array(Math.ceil(snumber.length * Math.log(frombase) / Math.log(tobase))), accumulator;", + " if(1 < frombase < baselist.length || 1 < tobase < baselist.length) console.error(\"Invalid or unsupported base!\");", + " while(snumber[0] == baselist[0] && snumber.length > 1) snumber = snumber.substr(1); // Remove leading zeros character", + " console.log(\"Number is\", snumber, \"in base\", frombase, \"to base\", tobase, \"result should be\",", + " parseInt(snumber, frombase).toString(tobase));", + " for(i = snumber.length - 1, inexp = 1; i > -1; i--, inexp *= frombase)", + " for(accumulator = listbase[snumber[i]] * inexp, t = to.length - 1; accumulator > 0 || t >= 0; t--)", + " {", + " accumulator += listbase[to[t] || 0];", + " to[t] = baselist[(accumulator % tobase) || 0];", + " accumulator = Math.floor(accumulator / tobase);", + " }", + " return to.join('');", + "}", + "console.log(\"Result:\", basechange(\"zzzzzzzzzz\", 36, 10));", + "Using BigInteger, can convert any base.", + "", + "// Tom Wu jsbn.js http://www-cs-students.stanford.edu/~tjw/jsbn/", + "var baselist = \"0123456789abcdefghijklmnopqrstuvwxyz\", listbase = [];", + "for(var i = 0; i < baselist.length; i++) listbase[baselist[i]] = i; // Generate baselist reverse", + "function baseconvert(snumber, frombase, tobase) // String number in base X to string number in base Y, arbitrary length, base", + "{", + " var i, t, to, accum = new BigInteger(), inexp = new BigInteger('1', 10), tb = new BigInteger(),", + " fb = new BigInteger(), tmp = new BigInteger();", + " console.log(\"Number is\", snumber, \"in base\", frombase, \"to base\", tobase, \"result should be\",", + " frombase < 37 && tobase < 37 ? parseInt(snumber, frombase).toString(tobase) : 'too large');", + " while(snumber[0] == baselist[0] && snumber.length > 1) snumber = snumber.substr(1); // Remove leading zeros", + " tb.fromInt(tobase);", + " fb.fromInt(frombase);", + " for(i = snumber.length - 1, to = new Array(Math.ceil(snumber.length * Math.log(frombase) / Math.log(tobase))); i > -1; i--)", + " {", + " accum = inexp.clone();", + " accum.dMultiply(listbase[snumber[i]]);", + " for(t = to.length - 1; accum.compareTo(BigInteger.ZERO) > 0 || t >= 0; t--)", + " {", + " tmp.fromInt(listbase[to[t]] || 0);", + " accum = accum.add(tmp);", + " to[t] = baselist[accum.mod(tb).intValue()];", + " accum = accum.divide(tb);", + " }", + " inexp = inexp.multiply(fb);", + " }", + " while(to[0] == baselist[0] && to.length > 1) to = to.slice(1); // Remove leading zeros", + " return to.join('');", + "}", + "", + "", + "===ES6===", + "", + "For more flexibility with digit variants (upper and lower case hex, digits in other languages/scripts etc) we can define '''toBase'''(intBase, n) in terms of a more general '''inBaseDigits'''(strDigits, n) which derives the base from the number of digits to be used.", + "", + "(() => {", + " 'use strict';", + "", + " // toBase :: Int -> Int -> String", + " const toBase = (intBase, n) =>", + " intBase < 36 && intBase > 0 ?", + " inBaseDigits('0123456789abcdef'.substr(0, intBase), n) : [];", + "", + "", + " // inBaseDigits :: String -> Int -> [String]", + " const inBaseDigits = (digits, n) => {", + " const intBase = digits.length;", + "", + " return unfoldr(maybeResidue => {", + " const [divided, remainder] = quotRem(maybeResidue.new, intBase);", + "", + " return {", + " valid: divided > 0,", + " value: digits[remainder],", + " new: divided", + " };", + " }, n)", + " .reverse()", + " .join('');", + " };", + "", + "", + " // GENERIC FUNCTIONS", + "", + " // unfoldr :: (b -> Maybe (a, b)) -> b -> [a]", + " const unfoldr = (mf, v) => {", + " var xs = [];", + " return (until(", + " m => !m.valid,", + " m => {", + " const m2 = mf(m);", + " return (", + " xs = xs.concat(m2.value),", + " m2", + " );", + " }, {", + " valid: true,", + " value: v,", + " new: v,", + " }", + " ), xs);", + " };", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " const curry = f => a => b => f(a, b);", + "", + " // until :: (a -> Bool) -> (a -> a) -> a -> a", + " const until = (p, f, x) => {", + " let v = x;", + " while (!p(v)) v = f(v);", + " return v;", + " }", + "", + " // quotRem :: Integral a => a -> a -> (a, a)", + " const quotRem = (m, n) => [Math.floor(m / n), m % n];", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x, null, 2);", + "", + "", + " // OTHER FUNCTIONS DERIVABLE FROM inBaseDigits", + "", + " // inLowerHex :: Int -> String", + " const inLowerHex = curry(inBaseDigits)('0123456789abcdef');", + "", + " /// inUpperHex :: Int -> String", + " const inUpperHex = curry(inBaseDigits)('0123456789ABCDEF');", + "", + " // inOctal :: Int -> String", + " const inOctal = curry(inBaseDigits)('01234567');", + "", + " // inDevanagariDecimal :: Int -> String", + " const inDevanagariDecimal = curry(inBaseDigits)('०१२३४५६७८९');", + "", + "", + " // TESTS", + " // testNumber :: [Int]", + " const testNumbers = [255, 240];", + "", + " return testNumbers.map(n => show({", + " binary: toBase(2, n),", + " base5: toBase(5, n),", + " hex: toBase(16, n),", + " upperHex: inUpperHex(n),", + " octal: inOctal(n),", + " devanagariDecimal: inDevanagariDecimal(n)", + " }));", + "})();", + "", + "{{Out}}", + "
    {",
    +        "  \"binary\": \"11111111\",",
    +        "  \"base5\": \"2010\",",
    +        "  \"hex\": \"ff\",",
    +        "  \"upperHex\": \"FF\",",
    +        "  \"octal\": \"377\",",
    +        "  \"devanagariDecimal\": \"२५५\"",
    +        "}, {",
    +        "  \"binary\": \"11110000\",",
    +        "  \"base5\": \"1430\",",
    +        "  \"hex\": \"f0\",",
    +        "  \"upperHex\": \"F0\",",
    +        "  \"octal\": \"360\",",
    +        "  \"devanagariDecimal\": \"२४०\"",
    +        "}
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f36", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "k = 26\ns = k.toString(16) //gives 1a\ni = parseInt('1a',16) //gives 26\n//optional special case for hex:\ni = +('0x'+s) //hexadecimal base 16, if s='1a' then i=26.\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Non-decimal radices/Input", + "type": "Waypoint", + "description": [ + "

    It is common to have a string containing a number written in some format, with the most common ones being decimal, hexadecimal, octal and binary. Such strings are found in many places (user interfaces, configuration files, XML data, network protocols, etc.)

    This task requires parsing of such a string (which may be assumed to contain nothing else) using the language's built-in facilities if possible. Parsing of decimal strings is required, parsing of other formats is optional but should be shown (i.e., if the language can parse in base-19 then that should be illustrated).

    The solutions may assume that the base of the number in the string is known. In particular, if your language has a facility to guess the base of a number by looking at a prefix (e.g. \"0x\" for hexadecimal) or other distinguishing syntax as it parses it, please show that.

    The reverse operation is in task Non-decimal radices/Output

    For general number base conversion, see Non-decimal radices/Convert.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "For base 10 and 16 (\"0x\"-prefixed), (but not 8), it is fastest to parse strings using the unary plus (+) operator:", + "+\"0123459\"; // 123459", + "+\"0xabcf123\"; // 180154659", + "", + "// also supports negative numbers, but not for hex:", + "+\"-0123459\"; // -123459", + "+\"-0xabcf123\"; // NaN", + "See http://www.jibbering.com/faq/notes/type-conversion/#tcNumber for more information.", + "", + "The parseInt(''string'',''radix'') core function is the reverse of the ''number''.toString(''radix'') method. The following is taken from [http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Functions/parseInt#Example.3a_Using_parseInt Mozilla's JavaScript 1.5 reference].", + "", + "
    The following examples all return 15:", + "", + "parseInt(\" 0xF\", 16);", + "parseInt(\" F\", 16);", + "parseInt(\"17\", 8);", + "parseInt(021, 8);", + "parseInt(\"015\", 10);", + "parseInt(15.99, 10);", + "parseInt(\"FXX123\", 16);", + "parseInt(\"1111\", 2);", + "parseInt(\"15*3\", 10);", + "parseInt(\"15e2\", 10);", + "parseInt(\"15px\", 10);", + "parseInt(\"12\", 13);", + "", + "The following examples all return NaN:", + "", + "parseInt(\"Hello\", 8); // Not a number at all", + "parseInt(\"546\", 2); // Digits are not valid for binary representations", + "", + "The following examples all return -15:", + "", + "parseInt(\"-F\", 16);", + "parseInt(\"-0F\", 16);", + "parseInt(\"-0XF\", 16);", + "parseInt(-10, 16);", + "parseInt(-15.1, 10)", + "parseInt(\" -17\", 8);", + "parseInt(\" -15\", 10);", + "parseInt(\"-1111\", 2);", + "parseInt(\"-15e1\", 10);", + "parseInt(\"-12\", 13);", + "", + "The following example returns 224:", + "", + "parseInt(\"0e0\", 16);", + "", + "Although it is optional, most implementations interpret a numeric string beginning with a leading '0' as octal. The following may have an octal result.", + "", + "parseInt(\"0e0\"); // 0", + "parseInt(\"08\"); // 0, '8' is not an octal digit.
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f37", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "+\"0123459\"; // 123459\n+\"0xabcf123\"; // 180154659\n\n// also supports negative numbers, but not for hex:\n+\"-0123459\"; // -123459\n+\"-0xabcf123\"; // NaN\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Non-decimal radices/Output", + "type": "Waypoint", + "description": [ + "

    Programming languages often have built-in routines to convert a non-negative integer for printing in different number bases. Such common number bases might include binary, Octal and Hexadecimal.

    ", + "Task:", + "

    Print a small range of integers in some different bases, as supported by standard routines of your programming language.

    ", + "Note:", + "

    This is distinct from Number base conversion as a user-defined conversion function is not asked for.)

    The reverse operation is Common number base parsing.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "The number.toString(radix) method produces a string representation of a number in any radix between 2 and 36.", + "", + "var bases = [2, 8, 10, 16, 24];", + "for (var n = 0; n <= 33; n++) {", + " var row = [];", + " for (var i = 0; i < bases.length; i++)", + " row.push( n.toString(bases[i]) );", + " print(row.join(', '));", + "}", + "", + "outputs", + "
    0, 0, 0, 0, 0",
    +        "1, 1, 1, 1, 1",
    +        "10, 2, 2, 2, 2",
    +        "11, 3, 3, 3, 3",
    +        "100, 4, 4, 4, 4",
    +        "101, 5, 5, 5, 5",
    +        "110, 6, 6, 6, 6",
    +        "111, 7, 7, 7, 7",
    +        "1000, 10, 8, 8, 8",
    +        "1001, 11, 9, 9, 9",
    +        "1010, 12, 10, a, a",
    +        "1011, 13, 11, b, b",
    +        "1100, 14, 12, c, c",
    +        "1101, 15, 13, d, d",
    +        "1110, 16, 14, e, e",
    +        "1111, 17, 15, f, f",
    +        "10000, 20, 16, 10, g",
    +        "10001, 21, 17, 11, h",
    +        "10010, 22, 18, 12, i",
    +        "10011, 23, 19, 13, j",
    +        "10100, 24, 20, 14, k",
    +        "10101, 25, 21, 15, l",
    +        "10110, 26, 22, 16, m",
    +        "10111, 27, 23, 17, n",
    +        "11000, 30, 24, 18, 10",
    +        "11001, 31, 25, 19, 11",
    +        "11010, 32, 26, 1a, 12",
    +        "11011, 33, 27, 1b, 13",
    +        "11100, 34, 28, 1c, 14",
    +        "11101, 35, 29, 1d, 15",
    +        "11110, 36, 30, 1e, 16",
    +        "11111, 37, 31, 1f, 17",
    +        "100000, 40, 32, 20, 18",
    +        "100001, 41, 33, 21, 19
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f38", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var bases = [2, 8, 10, 16, 24];\nfor (var n = 0; n <= 33; n++) {\n var row = [];\n for (var i = 0; i < bases.length; i++)\n row.push( n.toString(bases[i]) );\n print(row.join(', '));\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Nonoblock", + "type": "Waypoint", + "description": [ + "

    Nonoblock is a chip off the old Nonogram puzzle.

    Given:", + "The number of cells in a row.", + "The size of each, (space separated), connected block of cells to fit in the row, in left-to right order.", + "

    The task is to

    ", + "show all possible positions ", + "and the number of positions of the blocks for the following cases", + "

    within the row. On this page. Using a \"neat\" diagram of the block positions.

    Enumerate the following configurations:", + "5 cells and [2, 1] blocks", + "5 cells and [] blocks (no blocks)", + "10 cells and [8] blocks", + "15 cells and [2, 3, 2, 3] blocks", + "5 cells and [2, 3] blocks (Should give some indication of this not being possible).", + "Example:", + "

    Given a row of five cells and a block of two cells followed

    ", + "

    by a block of 1 cell - in that order, the example could be shown as:

    |_|_|_|_|_| # 5 cells and [2, 1] blocks

    And would expand to the following 3 possible rows of block positions:

    |A|A|_|B|_|

    ", + "

    |A|A|_|_|B|

    ", + "

    |_|A|A|_|B|

    ", + "

    Note how the sets of blocks are always separated by a space.

    Note also that it is not necessary for each block to have a separate letter.

    ", + "

    Output approximating

    This:

    |#|#|_|#|_|

    ", + "

    |#|#|_|_|#|

    ", + "

    |_|#|#|_|#|

    Or even this:

    ##.#.

    ", + "

    ##..#

    ", + "

    .##.#

    Would also work.

    An algorithm:", + "Find the minimum space to the right that is needed to legally hold all but the leftmost block of cells (with a space between blocks remember).", + "The leftmost cell can legitimately be placed in all positions from the LHS up to a RH position that allows enough room for the rest of the blocks.", + "for each position of the LH block recursively compute the position of the rest of the blocks in the remaining space to the right of the current placement of the LH block.(This is the algorithm used in the Nonoblock#Python solution). Reference:", + "The blog post Nonogram puzzle solver (part 1) Inspired this task and donated its Nonoblock#Python solution." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f39", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Nonogram solver", + "type": "Waypoint", + "description": [ + "

    A nonogram is a puzzle that provides

    ", + "

    numeric clues used to fill in a grid of cells,

    ", + "

    establishing for each cell whether it is filled or not.

    ", + "

    The puzzle solution is typically a picture of some kind.

    Each row and column of a rectangular grid is annotated with the lengths

    ", + "

    of its distinct runs of occupied cells.

    ", + "

    Using only these lengths you should find one valid configuration

    ", + "

    of empty and occupied cells, or show a failure message.

    Example", + "
    Problem:                 Solution:. . . . . . . .  3       . # # # . . . .  3",
    +        ". . . . . . . .  2 1     # # . # . . . .  2 1",
    +        ". . . . . . . .  3 2     . # # # . . # #  3 2",
    +        ". . . . . . . .  2 2     . . # # . . # #  2 2",
    +        ". . . . . . . .  6       . . # # # # # #  6",
    +        ". . . . . . . .  1 5     # . # # # # # .  1 5",
    +        ". . . . . . . .  6       # # # # # # . .  6",
    +        ". . . . . . . .  1       . . . . # . . .  1",
    +        ". . . . . . . .  2       . . . # # . . .  2",
    +        "1 3 1 7 5 3 4 3          1 3 1 7 5 3 4 3",
    +        "2 1 5 1                  2 1 5 1
    ", + "

    The problem above could be represented by two lists of lists:

    ", + "
    x = 3], [2,1], [3,2], [2,2], [6], [1,5], [6], [1], [2",
    +        "y = 1,2], [3,1], [1,5], [7,1], [5], [3], [4], [3
    ", + "

    A more compact representation of the same problem uses strings,

    ", + "

    where the letters represent the numbers, A=1, B=2, etc:

    ", + "
    x = \"C BA CB BB F AE F A B\"",
    +        "y = \"AB CA AE GA E C D C\"
    Task", + "

    For this task, try to solve the 4 problems below, read from a “nonogram_problems.txt” file that has this content

    ", + "

    (the blank lines are separators):

    ", + "
    C BA CB BB F AE F A B",
    +        "AB CA AE GA E C D CF CAC ACAC CN AAA AABB EBB EAA ECCC HCCC",
    +        "D D AE CD AE A DA BBB CC AAB BAA AAB DA AAB AAA BAB AAA CD BBA DACA BDA ACC BD CCAC CBBAC BBBBB BAABAA ABAD AABB BBH BBBD ABBAAA CCEA AACAAB BCACC ACBH DCH ADBE ADBB DBE ECE DAA DB CC",
    +        "BC CAC CBAB BDD CDBDE BEBDF ADCDFA DCCFB DBCFC ABDBA BBF AAF BADB DBF AAAAD BDG CEF CBDB BBB FCE BCB BEA BH BEK AABAF ABAC BAA BFB OD JH BADCF Q Q R AN AAN EI H G",
    +        "E CB BAB AAA AAA AC BB ACC ACCA AGB AIA AJ AJ ACE AH BAF CAG DAG FAH FJ GJ ADK ABK BL CM

    Extra credit: generate nonograms with unique solutions, of desired height and width.

    ", + "

    This task is the problem n.98 of the \"99 Prolog Problems\" by Werner Hett (also thanks to Paul Singleton for the idea and the examples).

    ", + " Related tasks", + "Nonoblock.", + "See also", + "Arc Consistency Algorithm", + "http://www.haskell.org/haskellwiki/99_questions/Solutions/98 (Haskell)", + "http://twanvl.nl/blog/haskell/Nonograms (Haskell)", + "http://picolisp.com/5000/!wiki?99p98 (PicoLisp)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f3a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "N-queens problem", + "type": "Waypoint", + "description": [ + "

    Solve the eight queens puzzle.

    ", + "

    You can extend the problem to solve the puzzle with a board of size NxN.

    For the number of solutions for small values of N, see oeis.org sequence A170.

    ", + "Related tasks:", + "A* search algorithm", + "Solve a Hidato puzzle", + "Solve a Holy Knight's tour", + "Knight's tour", + "Solve a Hopido puzzle", + "Solve a Numbrix puzzle", + "Solve the no connection puzzle" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f3b", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "N'th", + "type": "Waypoint", + "description": [ + "

    Write a function/method/subroutine/... that when given an integer greater than or equal to zero returns a string of the number followed by an apostrophe then the ordinal suffix.

    ", + "Example returns would include 1'st 2'nd 3'rd 11'th 111'th 1001'st 1012'thTask:", + "

    Use your routine to show here the output for at least the following (inclusive) ranges of integer inputs:

    ", + "

    0..25, 250..265, 1000..1025

    Note: apostrophes are now optional to allow correct apostrophe-less English.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "console.log(function () {", + "", + " var lstSuffix = 'th st nd rd th th th th th th'.split(' '),", + "", + " fnOrdinalForm = function (n) {", + " return n.toString() + (", + " 11 <= n % 100 && 13 >= n % 100 ?", + " \"th\" : lstSuffix[n % 10]", + " );", + " },", + "", + " range = function (m, n) {", + " return Array.apply(", + " null, Array(n - m + 1)", + " ).map(function (x, i) {", + " return m + i;", + " });", + " };", + "", + " return [[0, 25], [250, 265], [1000, 1025]].map(function (tpl) {", + " return range.apply(null, tpl).map(fnOrdinalForm).join(' ');", + " }).join('\\n\\n');", + " ", + "}());", + "", + "", + "{{Out}}", + "", + "0th 1st 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th", + "", + "250th 251st 252nd 253rd 254th 255th 256th 257th 258th 259th 260th 261st 262nd 263rd 264th 265th", + "", + "1000th 1001st 1002nd 1003rd 1004th 1005th 1006th 1007th 1008th 1009th 1010th 1011th 1012th 1013th 1014th 1015th 1016th 1017th 1018th 1019th 1020th 1021st 1022nd 1023rd 1024th 1025th", + "", + "", + "===ES6===", + "", + "(function (lstTestRanges) {", + " 'use strict'", + "", + " let lstSuffix = 'th st nd rd th th th th th th'.split(' '),", + "", + " // ordinalString :: Int -> String", + " ordinalString = n =>", + " n.toString() + (", + " 11 <= n % 100 && 13 >= n % 100 ?", + " \"th\" : lstSuffix[n % 10]", + " ),", + " ", + " // range :: Int -> Int -> [Int]", + " range = (m, n) =>", + " Array.from({", + " length: (n - m) + 1", + " }, (_, i) => m + i);", + " ", + "", + " return lstTestRanges", + " .map(tpl => range", + " .apply(null, tpl)", + " .map(ordinalString)", + " );", + "", + "})([[0, 25], [250, 265], [1000, 1025]]);", + "", + "", + "{{Out}}", + "
    [[\"0th\", \"1st\", \"2nd\", \"3rd\", \"4th\", \"5th\", \"6th\", \"7th\", \"8th\", ",
    +        "\"9th\", \"10th\", \"11th\", \"12th\", \"13th\", \"14th\", \"15th\", \"16th\", ",
    +        "\"17th\", \"18th\", \"19th\", \"20th\", \"21st\", \"22nd\", \"23rd\", \"24th\", \"25th\"], ",
    +        "[\"250th\", \"251st\", \"252nd\", \"253rd\", \"254th\", \"255th\", \"256th\", \"257th\", ",
    +        "\"258th\", \"259th\", \"260th\", \"261st\", \"262nd\", \"263rd\", \"264th\", \"265th\"], ",
    +        "[\"1000th\", \"1001st\", \"1002nd\", \"1003rd\", \"1004th\", \"1005th\", \"1006th\", ",
    +        "\"1007th\", \"1008th\", \"1009th\", \"1010th\", \"1011th\", \"1012th\", \"1013th\", ",
    +        "\"1014th\", \"1015th\", \"1016th\", \"1017th\", \"1018th\", \"1019th\", \"1020th\", ",
    +        "\"1021st\", \"1022nd\", \"1023rd\", \"1024th\", \"1025th\"]]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f3c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "console.log(function () {\n\n var lstSuffix = 'th st nd rd th th th th th th'.split(' '),\n\n fnOrdinalForm = function (n) {\n return n.toString() + (\n 11 <= n % 100 && 13 >= n % 100 ?\n \"th\" : lstSuffix[n % 10]\n );\n },\n\n range = function (m, n) {\n return Array.apply(\n null, Array(n - m + 1)\n ).map(function (x, i) {\n return m + i;\n });\n };\n\n return [[0, 25], [250, 265], [1000, 1025]].map(function (tpl) {\n return range.apply(null, tpl).map(fnOrdinalForm).join(' ');\n }).join('\\n\\n');\n \n}());\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Nth root", + "type": "Waypoint", + "description": [ + "Task:

    Implement the algorithm to compute the principal nth root $\\sqrt[n]A$ of a positive real number A, as explained at the Wikipedia page.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Gives the ''n'':nth root of ''num'', with precision ''prec''. (''n'' defaults to 2 [e.g. sqrt], ''prec'' defaults to 12.)", + "", + "function nthRoot(num, nArg, precArg) {", + " var n = nArg || 2;", + " var prec = precArg || 12;", + " ", + " var x = 1; // Initial guess.", + " for (var i=0; i", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f3d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function nthRoot(num, nArg, precArg) {\n var n = nArg || 2;\n var prec = precArg || 12;\n \n var x = 1; // Initial guess.\n for (var i=0; ireplaceMe is a function.');" + ] + }, + { + "title": "Number names", + "type": "Waypoint", + "description": [ + "Task:", + "

    Show how to spell out a number in English.

    You can use a preexisting implementation or roll your own, but you should support inputs up to at least one million (or the maximum value of your language's default bounded integer type, if that's less).

    Support for inputs other than positive integers (like zero, negative integers, and floating-point numbers) is optional.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f3f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Numerical integration/Gauss-Legendre Quadrature", + "type": "Waypoint", + "description": [ + "

    {|border=1 cellspacing=0 cellpadding=3

    ", + "

    |In a general Gaussian quadrature rule, an definite integral of $f(x)$ is first approximated over the interval $[-1,1]$ by a polynomial approximable function $g(x)$ and a known weighting function $W(x)$.

    ", + "

    |$\\int_{-1}^1 f(x) \\, dx = \\int_{-1}^1 W(x) g(x) \\, dx$

    ", + "

    |-

    ", + "

    |Those are then approximated by a sum of function values at specified points $x_i$ multiplied by some weights $w_i$:

    ", + "

    |$\\int_{-1}^1 W(x) g(x) \\, dx \\approx \\sum_{i=1}^n w_i g(x_i)$

    ", + "

    |-

    ", + "

    |In the case of Gauss-Legendre quadrature, the weighting function $W(x) = 1$, so we can approximate an integral of $f(x)$ with:

    ", + "

    |$\\int_{-1}^1 f(x)\\,dx \\approx \\sum_{i=1}^n w_i f(x_i)$

    ", + "

    |}

    ", + "

    For this, we first need to calculate the nodes and the weights, but after we have them, we can reuse them for numerious integral evaluations, which greatly speeds up the calculation compared to more simple numerical integration methods.

    {|border=1 cellspacing=0 cellpadding=3

    ", + "

    |The $n$ evaluation points $x_i$ for a n-point rule, also called \"nodes\", are roots of n-th order Legendre Polynomials $P_n(x)$. Legendre polynomials are defined by the following recursive rule:

    ", + "

    |$P_0(x) = 1$

    ", + "

    $P_1(x) = x$

    ", + "

    $nP_{n}(x) = (2n-1)xP_{n-1}(x)-(n-1)P_{n-2}(x)$

    ", + "

    |-

    ", + "

    |There is also a recursive equation for their derivative:

    ", + "

    |$P_{n}'(x) = \\frac{n}{x^2-1} \\left( x P_n(x) - P_{n-1}(x) \\right)$

    ", + "

    |-

    ", + "

    |The roots of those polynomials are in general not analytically solvable, so they have to be approximated numerically, for example by Newton-Raphson iteration:

    ", + "

    |$x_{n+1} = x_n - \\frac{f(x_n)}{f'(x_n)}$

    ", + "

    |-

    ", + "

    |The first guess $x_0$ for the $i$-th root of a $n$-order polynomial $P_n$ can be given by

    ", + "

    |$x_0 = \\cos \\left( \\pi \\, \\frac{i - \\frac{1}{4}}{n+\\frac{1}{2}} \\right)$

    ", + "

    |-

    ", + "

    |After we get the nodes $x_i$, we compute the appropriate weights by:

    ", + "

    |$w_i = \\frac{2}{\\left( 1-x_i^2 \\right) [P'_n(x_i)]^2}$

    ", + "

    |-

    ", + "

    |After we have the nodes and the weights for a n-point quadrature rule, we can approximate an integral over any interval $[a,b]$ by

    ", + "

    |$\\int_a^b f(x)\\,dx \\approx \\frac{b-a}{2} \\sum_{i=1}^n w_i f\\left(\\frac{b-a}{2}x_i + \\frac{a+b}{2}\\right)$

    ", + "

    |}

    ", + "

    Task description

    Similar to the task Numerical Integration, the task here is to calculate the definite integral of a function $f(x)$, but by applying an n-point Gauss-Legendre quadrature rule, as described here, for example. The input values should be an function f to integrate, the bounds of the integration interval a and b, and the number of gaussian evaluation points n. An reference implementation in Common Lisp is provided for comparison.

    To demonstrate the calculation, compute the weights and nodes for an 5-point quadrature rule and then use them to compute:

    ", + "

    $\\int_{-3}^{3} \\exp(x) \\, dx \\approx \\sum_{i=1}^5 w_i \\; \\exp(x_i) \\approx 20.036$

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f41", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Numerical integration", + "type": "Waypoint", + "description": [ + "

    Write functions to calculate the definite integral of a function ƒ(x) using all five of the following methods:

    ", + "

    :* rectangular

    ", + "

    :::* left

    ", + "

    :::* right

    ", + "

    :::* midpoint

    ", + "

    :* trapezium

    ", + "

    :* Simpson's

    ", + "

    Your functions should take in the upper and lower bounds (a and b), and the number of approximations to make in that range (n).

    Assume that your example already has a function that gives values for ƒ(x).

    Simpson's method is defined by the following pseudo-code:

    ", + "
    ",
    +        "h := (b - a) / n",
    +        "sum1 := f(a + h/2)",
    +        "sum2 := 0loop on i from 1 to (n - 1)",
    +        "    sum1 := sum1 + f(a + h * i + h/2)",
    +        "    sum2 := sum2 + f(a + h * i)answer := (h / 6) * (f(a) + f(b) + 4*sum1 + 2*sum2)",
    +        "

    Demonstrate your function by showing the results for:

    ", + " ƒ(x) = x3, where x is [0,1], with 100 approximations. The exact result is 1/4, or 0.25.", + " ƒ(x) = 1/x, where x is [1,100], with 1,000 approximations. The exact result is the natural log of 100, or about 4.605170", + " ƒ(x) = x, where x is [0,5000], with 5,000,000 approximations. The exact result is 12,500,000.", + " ƒ(x) = x, where x is [0,6000], with 6,000,000 approximations. The exact result is 18,000,000.", + "

    See also

    ", + "Active object for integrating a function of real time.", + "Numerical integration/Gauss-Legendre Quadrature for another integration method." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f42", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Numeric error propagation", + "type": "Waypoint", + "description": [ + "

    If f, a, and b are values with uncertainties σf, σa, and σb, and c is a constant;

    ", + "then if f is derived from a, b, and c in the following ways, ", + "then σf can be calculated as follows:

    ;Addition/Subtraction

    ", + "

    * If f = a ± c, or f = c ± a then σf = σa

    ", + "

    * If f = a ± b then σf2 = σa2 + σb2

    ;Multiplication/Division

    ", + "

    * If f = ca or f = ac then σf = |cσa|

    ", + "

    * If f = ab or f = a / b then σf2 = f2( (σa / a)2 + (σb / b)2)

    ;Exponentiation

    ", + "

    * If f = ac then σf = |fc(σa / a)|

    ", + "

    Caution:

    ", + "

    :This implementation of error propagation does not address issues of dependent and independent values. It is assumed that a and b are independent and so the formula for multiplication should not be applied to a*a for example. See the talk page for some of the implications of this issue.

    ", + "Task details:", + "Add an uncertain number type to your language that can support addition, subtraction, multiplication, division, and exponentiation between numbers with an associated error term together with 'normal' floating point numbers without an associated error term. Implement enough functionality to perform the following calculations.", + "Given coordinates and their errors:x1 = 100 ± 1.1y1 = 50 ± 1.2x2 = 200 ± 2.2y2 = 100 ± 2.3 if point p1 is located at (x1, y1) and p2 is at (x2, y2); calculate the distance between the two points using the classic Pythagorean formula: d = √ (x1 - x2)² + (y1 - y2)² ", + "Print and display both d and its error.", + "

    References:", + "A Guide to Error Propagation B. Keeney, 2005.", + "Propagation of uncertainty Wikipedia.Related task:", + " Quaternion type" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f43", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Odd word problem", + "type": "Waypoint", + "description": [ + "Task:", + "

    Write a program that solves the odd word problem with the restrictions given below.

    ", + "Description:", + "

    You are promised an input stream consisting of English letters and punctuations.

    It is guaranteed that:

    ", + "the words (sequence of consecutive letters) are delimited by one and only one punctuation,", + "the stream will begin with a word,", + "the words will be at least one letter long, and ", + "a full stop (a period, [.]) appears after, and only after, the last word.Example:", + "

    A stream with six words:

    ", + "

    : what,is,the;meaning,of:life.

    ", + "

    The task is to reverse the letters in every other word while leaving punctuations intact, producing:

    ", + "

    : what,si,the;gninaem,of:efil.

    ", + "

    while observing the following restrictions:

    ", + "Only I/O allowed is reading or writing one character at a time, which means: no reading in a string, no peeking ahead, no pushing characters back into the stream, and no storing characters in a global variable for later use;", + "You are not to explicitly save characters in a collection data structure, such as arrays, strings, hash tables, etc, for later reversal;", + "You are allowed to use recursions, closures, continuations, threads, co-routines, etc., even if their use implies the storage of multiple characters.Test cases:", + "

    Work on both the \"life\" example given above, and also the text:

    ", + "

    : we,are;not,in,kansas;any,more.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f45", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Old lady swallowed a fly", + "type": "Waypoint", + "description": [ + "Task:", + "

    Present a program which emits the lyrics to the song I Knew an Old Lady Who Swallowed a Fly, taking advantage of the repetitive structure of the song's lyrics.

    This song has multiple versions with slightly different lyrics, so all these programs might not emit identical output.

    ", + "Related task:", + " 99 Bottles of Beer" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f46", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Optional parameters", + "type": "Waypoint", + "description": [ + "Task:", + "

    Define a function/method/subroutine which sorts a sequence (\"table\") of sequences (\"rows\") of strings (\"cells\"), by one of the strings. Besides the input to be sorted, it shall have the following optional parameters:

    ", + "

    {|

    ", + "

    |

    ", + "

    ----

    ", + " ordering", + "

    A function specifying the ordering of strings; lexicographic by default.

    ", + " column", + "

    An integer specifying which string of each row to compare; the first by default.

    ", + " reverse", + "

    Reverses the ordering.

    ", + "

    ----

    ", + "

    |}

    This task should be considered to include both positional and named optional parameters, as well as overloading on argument count as in Java or selector name as in Smalltalk, or, in the extreme, using different function names. Provide these variations of sorting in whatever way is most natural to your language. If the language supports both methods naturally, you are encouraged to describe both.

    Do not implement a sorting algorithm; this task is about the interface. If you can't use a built-in sort routine, just omit the implementation (with a comment).

    See also:

    ", + "Named Arguments" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "See [[Named parameters#JavaScript]], to pass named parameters one uses an object with properties set:", + "function sorter(table, options) {", + " opts = {}", + " opts.ordering = options.ordering || 'lexicographic';", + " opts.column = options.column || 0;", + " opts.reverse = options.reverse || false;", + " ", + " // ...", + "}", + "", + "sorter(the_data, {reverse: true, ordering: 'numeric'});", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f4c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function sorter(table, options) {\n opts = {}\n opts.ordering = options.ordering || 'lexicographic';\n opts.column = options.column || 0;\n opts.reverse = options.reverse || false;\n \n // ...\n}\n\nsorter(the_data, {reverse: true, ordering: 'numeric'});\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Order disjoint list items", + "type": "Waypoint", + "description": [ + "

    Given M as a list of items and another list N of items chosen from M, create M' as a list with the first occurrences of items from N sorted to be in one of the set of indices of their original occurrence in M but in the order given by their order in N.

    That is, items in N are taken from M without replacement, then the corresponding positions in M' are filled by successive items from N.

    ", + "For example:", + "

    if M is 'the cat sat on the mat'

    ", + "

    And N is 'mat cat'

    ", + "

    Then the result M' is 'the mat sat on the cat'.

    The words not in N are left in their original positions.

    ", + "

    If there are duplications then only the first instances in M up to as many as are mentioned in N are potentially re-ordered.

    ", + "For example:", + "

    M = 'A B C A B C A B C'

    ", + "

    N = 'C A C A'

    Is ordered as:

    ", + "

    M' = 'C B A C B A A B C'

    ", + "

    Show the output, here, for at least the following inputs:

    ", + "
    ",
    +        "Data M: 'the cat sat on the mat' Order N: 'mat cat'",
    +        "Data M: 'the cat sat on the mat' Order N: 'cat mat'",
    +        "Data M: 'A B C A B C A B C'      Order N: 'C A C A'",
    +        "Data M: 'A B C A B D A B E'      Order N: 'E A D A'",
    +        "Data M: 'A B'                    Order N: 'B'      ",
    +        "Data M: 'A B'                    Order N: 'B A'    ",
    +        "Data M: 'A B B A'                Order N: 'B A'",
    +        "
    ", + "Cf:", + "Sort disjoint sublist" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES6===", + "", + "Accumulating a segmentation of M over a fold/reduce, and zipping with N:", + "", + "(() => {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " const concatMap = (f, xs) => [].concat.apply([], xs.map(f));", + "", + " // deleteFirst :: a -> [a] -> [a]", + " const deleteFirst = (x, xs) =>", + " xs.length > 0 ? (", + " x === xs[0] ? (", + " xs.slice(1)", + " ) : [xs[0]].concat(deleteFirst(x, xs.slice(1)))", + " ) : [];", + "", + " // flatten :: Tree a -> [a]", + " const flatten = t => (t instanceof Array ? concatMap(flatten, t) : [t]);", + "", + " // unwords :: [String] -> String", + " const unwords = xs => xs.join(' ');", + "", + " // words :: String -> [String]", + " const words = s => s.split(/\\s+/);", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " const zipWith = (f, xs, ys) => {", + " const ny = ys.length;", + " return (xs.length <= ny ? xs : xs.slice(0, ny))", + " .map((x, i) => f(x, ys[i]));", + " };", + "", + " //------------------------------------------------------------------------", + "", + " // ORDER DISJOINT LIST ITEMS", + "", + " // disjointOrder :: [String] -> [String] -> [String]", + " const disjointOrder = (ms, ns) =>", + " flatten(", + " zipWith(", + " (a, b) => a.concat(b),", + " segments(ms, ns),", + " ns.concat('')", + " )", + " );", + "", + " // segments :: [String] -> [String] -> [String]", + " const segments = (ms, ns) => {", + " const dct = ms.reduce((a, x) => {", + " const wds = a.words,", + " blnFound = wds.indexOf(x) !== -1;", + "", + " return {", + " parts: a.parts.concat(blnFound ? [a.current] : []),", + " current: blnFound ? [] : a.current.concat(x),", + " words: blnFound ? deleteFirst(x, wds) : wds,", + " };", + " }, {", + " words: ns,", + " parts: [],", + " current: []", + " });", + "", + " return dct.parts.concat([dct.current]);", + " };", + "", + " // -----------------------------------------------------------------------", + " // FORMATTING TEST OUTPUT", + "", + " // transpose :: [[a]] -> [[a]]", + " const transpose = xs =>", + " xs[0].map((_, iCol) => xs.map((row) => row[iCol]));", + "", + " // maximumBy :: (a -> a -> Ordering) -> [a] -> a", + " const maximumBy = (f, xs) =>", + " xs.reduce((a, x) => a === undefined ? x : (", + " f(x, a) > 0 ? x : a", + " ), undefined);", + "", + " // 2 or more arguments", + " // curry :: Function -> Function", + " const curry = (f, ...args) => {", + " const intArgs = f.length,", + " go = xs =>", + " xs.length >= intArgs ? (", + " f.apply(null, xs)", + " ) : function () {", + " return go(xs.concat([].slice.apply(arguments)));", + " };", + " return go([].slice.call(args, 1));", + " };", + "", + " // justifyLeft :: Int -> Char -> Text -> Text", + " const justifyLeft = (n, cFiller, strText) =>", + " n > strText.length ? (", + " (strText + replicateS(n, cFiller))", + " .substr(0, n)", + " ) : strText;", + "", + " // replicateS :: Int -> String -> String", + " const replicateS = (n, s) => {", + " let v = s,", + " o = '';", + " if (n < 1) return o;", + " while (n > 1) {", + " if (n & 1) o = o.concat(v);", + " n >>= 1;", + " v = v.concat(v);", + " }", + " return o.concat(v);", + " };", + "", + " // -----------------------------------------------------------------------", + "", + " // TEST", + " return transpose(transpose([{", + " M: 'the cat sat on the mat',", + " N: 'mat cat'", + " }, {", + " M: 'the cat sat on the mat',", + " N: 'cat mat'", + " }, {", + " M: 'A B C A B C A B C',", + " N: 'C A C A'", + " }, {", + " M: 'A B C A B D A B E',", + " N: 'E A D A'", + " }, {", + " M: 'A B',", + " N: 'B'", + " }, {", + " M: 'A B',", + " N: 'B A'", + " }, {", + " M: 'A B B A',", + " N: 'B A'", + " }].map(dct => [", + " dct.M, dct.N,", + " unwords(disjointOrder(words(dct.M), words(dct.N)))", + " ]))", + " .map(col => {", + " const width = maximumBy((a, b) => a.length > b.length, col)", + " .length;", + " return col.map(curry(justifyLeft)(width, ' '));", + " }))", + " .map(", + " ([a, b, c]) => a + ' -> ' + b + ' -> ' + c", + " )", + " .join('\\n');", + "})();", + "", + "{{Out}}", + "
    the cat sat on the mat  ->  mat cat  ->  the mat sat on the cat ",
    +        "the cat sat on the mat  ->  cat mat  ->  the cat sat on the mat ",
    +        "A B C A B C A B C       ->  C A C A  ->  C B A C B A A B C      ",
    +        "A B C A B D A B E       ->  E A D A  ->  E B C A B D A B A      ",
    +        "A B                     ->  B        ->  A B                    ",
    +        "A B                     ->  B A      ->  B A                    ",
    +        "A B B A                 ->  B A      ->  B A B A                
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f4d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n 'use strict';\n\n // GENERIC FUNCTIONS\n\n // concatMap :: (a -> [b]) -> [a] -> [b]\n const concatMap = (f, xs) => [].concat.apply([], xs.map(f));\n\n // deleteFirst :: a -> [a] -> [a]\n const deleteFirst = (x, xs) =>\n xs.length > 0 ? (\n x === xs[0] ? (\n xs.slice(1)\n ) : [xs[0]].concat(deleteFirst(x, xs.slice(1)))\n ) : [];\n\n // flatten :: Tree a -> [a]\n const flatten = t => (t instanceof Array ? concatMap(flatten, t) : [t]);\n\n // unwords :: [String] -> String\n const unwords = xs => xs.join(' ');\n\n // words :: String -> [String]\n const words = s => s.split(/\\s+/);\n\n // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]\n const zipWith = (f, xs, ys) => {\n const ny = ys.length;\n return (xs.length <= ny ? xs : xs.slice(0, ny))\n .map((x, i) => f(x, ys[i]));\n };\n\n //------------------------------------------------------------------------\n\n // ORDER DISJOINT LIST ITEMS\n\n // disjointOrder :: [String] -> [String] -> [String]\n const disjointOrder = (ms, ns) =>\n flatten(\n zipWith(\n (a, b) => a.concat(b),\n segments(ms, ns),\n ns.concat('')\n )\n );\n\n // segments :: [String] -> [String] -> [String]\n const segments = (ms, ns) => {\n const dct = ms.reduce((a, x) => {\n const wds = a.words,\n blnFound = wds.indexOf(x) !== -1;\n\n return {\n parts: a.parts.concat(blnFound ? [a.current] : []),\n current: blnFound ? [] : a.current.concat(x),\n words: blnFound ? deleteFirst(x, wds) : wds,\n };\n }, {\n words: ns,\n parts: [],\n current: []\n });\n\n return dct.parts.concat([dct.current]);\n };\n\n // -----------------------------------------------------------------------\n // FORMATTING TEST OUTPUT\n\n // transpose :: [[a]] -> [[a]]\n const transpose = xs =>\n xs[0].map((_, iCol) => xs.map((row) => row[iCol]));\n\n // maximumBy :: (a -> a -> Ordering) -> [a] -> a\n const maximumBy = (f, xs) =>\n xs.reduce((a, x) => a === undefined ? x : (\n f(x, a) > 0 ? x : a\n ), undefined);\n\n // 2 or more arguments\n // curry :: Function -> Function\n const curry = (f, ...args) => {\n const intArgs = f.length,\n go = xs =>\n xs.length >= intArgs ? (\n f.apply(null, xs)\n ) : function () {\n return go(xs.concat([].slice.apply(arguments)));\n };\n return go([].slice.call(args, 1));\n };\n\n // justifyLeft :: Int -> Char -> Text -> Text\n const justifyLeft = (n, cFiller, strText) =>\n n > strText.length ? (\n (strText + replicateS(n, cFiller))\n .substr(0, n)\n ) : strText;\n\n // replicateS :: Int -> String -> String\n const replicateS = (n, s) => {\n let v = s,\n o = '';\n if (n < 1) return o;\n while (n > 1) {\n if (n & 1) o = o.concat(v);\n n >>= 1;\n v = v.concat(v);\n }\n return o.concat(v);\n };\n\n // -----------------------------------------------------------------------\n\n // TEST\n return transpose(transpose([{\n M: 'the cat sat on the mat',\n N: 'mat cat'\n }, {\n M: 'the cat sat on the mat',\n N: 'cat mat'\n }, {\n M: 'A B C A B C A B C',\n N: 'C A C A'\n }, {\n M: 'A B C A B D A B E',\n N: 'E A D A'\n }, {\n M: 'A B',\n N: 'B'\n }, {\n M: 'A B',\n N: 'B A'\n }, {\n M: 'A B B A',\n N: 'B A'\n }].map(dct => [\n dct.M, dct.N,\n unwords(disjointOrder(words(dct.M), words(dct.N)))\n ]))\n .map(col => {\n const width = maximumBy((a, b) => a.length > b.length, col)\n .length;\n return col.map(curry(justifyLeft)(width, ' '));\n }))\n .map(\n ([a, b, c]) => a + ' -> ' + b + ' -> ' + c\n )\n .join('\\n');\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Ordered Partitions", + "type": "Waypoint", + "description": [ + "

    In this task we want to find the ordered partitions into fixed-size blocks. This task is related to Combinations in that it has to do with discrete mathematics and moreover a helper function to compute combinations is (probably) needed to solve this task.

    $partitions(\\mathit{arg}_1,\\mathit{arg}_2,...,\\mathit{arg}_n)$ should generate all distributions of the elements in $\\{1,...,\\Sigma_{i=1}^n\\mathit{arg}_i\\}$ into $n$ blocks of respective size $\\mathit{arg}_1,\\mathit{arg}_2,...,\\mathit{arg}_n$.

    Example 1: $partitions(2,0,2)$ would create:

    ",
    +        "{({1, 2}, {}, {3, 4}), ",
    +        " ({1, 3}, {}, {2, 4}), ",
    +        " ({1, 4}, {}, {2, 3}), ",
    +        " ({2, 3}, {}, {1, 4}), ",
    +        " ({2, 4}, {}, {1, 3}), ",
    +        " ({3, 4}, {}, {1, 2})}",
    +        "

    Example 2: $partitions(1,1,1)$ would create:

    ",
    +        "{({1}, {2}, {3}), ",
    +        " ({1}, {3}, {2}), ",
    +        " ({2}, {1}, {3}), ",
    +        " ({2}, {3}, {1}), ",
    +        " ({3}, {1}, {2}), ",
    +        " ({3}, {2}, {1})}",
    +        "

    Note that the number of elements in the list is

    ", + "

    ${\\mathit{arg}_1+\\mathit{arg}_2+...+\\mathit{arg}_n \\choose \\mathit{arg}_1} \\cdot {\\mathit{arg}_2+\\mathit{arg}_3+...+\\mathit{arg}_n \\choose \\mathit{arg}_2} \\cdot \\ldots \\cdot {\\mathit{arg}_n \\choose \\mathit{arg}_n}$

    ", + "

    (see the definition of the binomial coefficient if you are not familiar with this notation) and the number of elements remains the same regardless of how the argument is permuted

    ", + "

    (i.e. the multinomial coefficient). Also, $partitions(1,1,1)$ creates the permutations of $\\{1,2,3\\}$ and thus there would be $3! = 6$ elements in the list.

    Note: Do not use functions that are not in the standard library of the programming language you use. Your file should be written so that it can be executed on the command line and by default outputs the result of $partitions(2,0,2)$. If the programming language does not support polyvariadic functions pass a list as an argument.

    Notation

    Here are some explanatory remarks on the notation used in the task description:

    $\\{1, \\ldots, n\\}$ denotes the set of consecutive numbers from $1$ to $n$, e.g. $\\{1,2,3\\}$ if $n = 3$. $\\Sigma$ is the mathematical notation for summation, e.g. $\\Sigma_{i=1}^3 i = 6$ (see also [http://en.wikipedia.org/wiki/Summation#Capital-sigma_notation]). $\\mathit{arg}_1,\\mathit{arg}_2,...,\\mathit{arg}_n$ are the arguments — natural numbers — that the sought function receives.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Functional (ES 5)===", + "", + "{{trans|Haskell}}", + "", + "(function () {", + " 'use strict';", + "", + " // [n] -> [[[n]]]", + " function partitions(a1, a2, a3) {", + " var n = a1 + a2 + a3;", + "", + " return combos(range(1, n), n, [a1, a2, a3]);", + " }", + "", + " function combos(s, n, xxs) {", + " if (!xxs.length) return [[]];", + "", + " var x = xxs[0],", + " xs = xxs.slice(1);", + "", + " return mb( choose(s, n, x), function (l_rest) {", + " return mb( combos(l_rest[1], (n - x), xs), function (r) {", + " // monadic return/injection requires 1 additional", + " // layer of list nesting:", + " return [ [l_rest[0]].concat(r) ];", + " ", + " })});", + " }", + "", + " function choose(aa, n, m) {", + " if (!m) return [[[], aa]];", + "", + " var a = aa[0],", + " as = aa.slice(1);", + "", + " return n === m ? (", + " [[aa, []]]", + " ) : (", + " choose(as, n - 1, m - 1).map(function (xy) {", + " return [[a].concat(xy[0]), xy[1]];", + " }).concat(choose(as, n - 1, m).map(function (xy) {", + " return [xy[0], [a].concat(xy[1])];", + " }))", + " );", + " }", + " ", + " // GENERIC", + "", + " // Monadic bind (chain) for lists", + " function mb(xs, f) {", + " return [].concat.apply([], xs.map(f));", + " }", + "", + " // [m..n]", + " function range(m, n) {", + " return Array.apply(null, Array(n - m + 1)).map(function (x, i) {", + " return m + i;", + " });", + " }", + " ", + " // EXAMPLE", + "", + " return partitions(2, 0, 2);", + "", + "})();", + "", + "{{Out}}", + "", + "[[[1, 2], [], [3, 4]], ", + " [[1, 3], [], [2, 4]],", + " [[1, 4], [], [2, 3]],", + " [[2, 3], [], [1, 4]],", + " [[2, 4], [], [1, 3]],", + " [[3, 4], [], [1, 2]]]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f4e", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function () {\n 'use strict';\n\n // [n] -> [[[n]]]\n function partitions(a1, a2, a3) {\n var n = a1 + a2 + a3;\n\n return combos(range(1, n), n, [a1, a2, a3]);\n }\n\n function combos(s, n, xxs) {\n if (!xxs.length) return [[]];\n\n var x = xxs[0],\n xs = xxs.slice(1);\n\n return mb( choose(s, n, x), function (l_rest) {\n return mb( combos(l_rest[1], (n - x), xs), function (r) {\n // monadic return/injection requires 1 additional\n // layer of list nesting:\n return [ [l_rest[0]].concat(r) ];\n \n })});\n }\n\n function choose(aa, n, m) {\n if (!m) return [[[], aa]];\n\n var a = aa[0],\n as = aa.slice(1);\n\n return n === m ? (\n [[aa, []]]\n ) : (\n choose(as, n - 1, m - 1).map(function (xy) {\n return [[a].concat(xy[0]), xy[1]];\n }).concat(choose(as, n - 1, m).map(function (xy) {\n return [xy[0], [a].concat(xy[1])];\n }))\n );\n }\n \n // GENERIC\n\n // Monadic bind (chain) for lists\n function mb(xs, f) {\n return [].concat.apply([], xs.map(f));\n }\n\n // [m..n]\n function range(m, n) {\n return Array.apply(null, Array(n - m + 1)).map(function (x, i) {\n return m + i;\n });\n }\n \n // EXAMPLE\n\n return partitions(2, 0, 2);\n\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Ordered words", + "type": "Waypoint", + "description": [ + "

    An ordered word is a word in which the letters appear in alphabetic order.

    Examples include abbey and dirt.

    ", + "

    Find and display all the ordered words in the dictionary unixdict.txt that have the longest word length.

    (Examples that access the dictionary file locally assume that you have downloaded this file yourself.)

    The display needs to be shown on this page.

    ", + "


    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Using [http://nodejs.org/ node.js]:", + "", + "var fs = require('fs'), print = require('sys').print;", + "fs.readFile('./unixdict.txt', 'ascii', function (err, data) {", + " var is_ordered = function(word){return word.split('').sort().join('') === word;},", + " ordered_words = data.split('\\n').filter(is_ordered).sort(function(a, b){return a.length - b.length}).reverse(),", + " longest = [], curr = len = ordered_words[0].length, lcv = 0;", + " while (curr === len){", + " longest.push(ordered_words[lcv]);", + " curr = ordered_words[++lcv].length;", + " };", + " print(longest.sort().join(', ') + '\\n');", + "});", + "", + "Output:", + "
    abbott, accent, accept, access, accost, almost, bellow, billow, biopsy, chilly, choosy, choppy, effort, floppy, glossy, knotty
    ", + "", + "Alternative version (also using Node.js):", + "", + "var http = require('http');", + "", + "http.get({", + " host: 'www.puzzlers.org',", + " path: '/pub/wordlists/unixdict.txt'", + "}, function(res) {", + " var data = '';", + " res.on('data', function(chunk) {", + " data += chunk;", + " });", + " res.on('end', function() {", + " var words = data.split('\\n');", + " var max = 0;", + " var ordered = [];", + " words.forEach(function(word) {", + " if (word.split('').sort().join('') != word) return;", + " if (word.length == max) {", + " ordered.push(word);", + " } else if (word.length > max) {", + " ordered = [word];", + " max = word.length;", + " }", + " });", + " console.log(ordered.join(', '));", + " });", + "});", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f4f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var fs = require('fs'), print = require('sys').print;\nfs.readFile('./unixdict.txt', 'ascii', function (err, data) {\n var is_ordered = function(word){return word.split('').sort().join('') === word;},\n ordered_words = data.split('\\n').filter(is_ordered).sort(function(a, b){return a.length - b.length}).reverse(),\n longest = [], curr = len = ordered_words[0].length, lcv = 0;\n while (curr === len){\n longest.push(ordered_words[lcv]);\n curr = ordered_words[++lcv].length;\n };\n print(longest.sort().join(', ') + '\\n');\n});\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Order two numerical lists", + "type": "Waypoint", + "description": [ + "

    Write a function that orders two lists or arrays filled with numbers.

    ", + "

    The function should accept two lists as arguments and return true if the first list should be ordered before the second, and false otherwise.

    The order is determined by lexicographic order: Comparing the first element of each list.

    ", + "

    If the first elements are equal, then the second elements should be compared, and so on, until one of the list has no more elements.

    ", + "

    If the first list runs out of elements the result is true.

    ", + "

    If the second list or both run out of elements the result is false.

    Note: further clarification of lexicographical ordering is expounded on the talk page here and here.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES6===", + "", + "<= is already defined for numeric lists in JavaScript", + "", + "(() => {", + " 'use strict';", + "", + " // <= is already defined for lists in JS", + "", + " // compare :: [a] -> [a] -> Bool", + " const compare = (xs, ys) => xs <= ys;", + "", + "", + " // TEST", + " return [", + " compare([1, 2, 1, 3, 2], [1, 2, 0, 4, 4, 0, 0, 0]),", + " compare([1, 2, 0, 4, 4, 0, 0, 0], [1, 2, 1, 3, 2])", + " ];", + "", + " // --> [false, true]", + "})()", + "", + "", + "{{Out}}", + "[false, true]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f50", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n 'use strict';\n\n // <= is already defined for lists in JS\n\n // compare :: [a] -> [a] -> Bool\n const compare = (xs, ys) => xs <= ys;\n\n\n // TEST\n return [\n compare([1, 2, 1, 3, 2], [1, 2, 0, 4, 4, 0, 0, 0]),\n compare([1, 2, 0, 4, 4, 0, 0, 0], [1, 2, 1, 3, 2])\n ];\n\n // --> [false, true]\n})()\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Palindrome detection", + "type": "Waypoint", + "description": [ + "

    A palindrome is a phrase which reads the same backward and forward.

    ", + "

    Write a function or program that checks whether a given sequence of characters (or, if you prefer, bytes)

    ", + "

    is a palindrome.

    For extra credit:

    ", + "Support Unicode characters.", + "Write a second function (possibly as a wrapper to the first) which detects inexact palindromes, i.e. phrases that are palindromes if white-space and punctuation is ignored and case-insensitive comparison is used.It might be useful for this task to know how to reverse a string.", + "This task's entries might also form the subjects of the task Test a function.", + "


    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function isPalindrome(str) {", + " return str === str.split(\"\").reverse().join(\"\");", + "}", + "", + "console.log(isPalindrome(\"ingirumimusnocteetconsumimurigni\"));", + "", + "ES6 implementation", + "var isPal = str => str === str.split(\"\").reverse().join(\"\");", + "", + "", + "Or, adding a wrapper function to prepare the test data:", + "", + "(function (strSample) {", + "", + " // isPalindrome :: String -> Bool", + " let isPalindrome = s =>", + " s.split('')", + " .reverse()", + " .join('') === s;", + "", + "", + "", + " // TESTING ", + "", + " // lowerCaseNoSpace :: String -> String", + " let lowerCaseNoSpace = s =>", + " concatMap(c => c !== ' ' ? [c.toLowerCase()] : [],", + " s.split(''))", + " .join(''),", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " concatMap = (f, xs) => [].concat.apply([], xs.map(f));", + "", + "", + " return isPalindrome(", + " lowerCaseNoSpace(strSample)", + " );", + "", + "", + "})(\"In girum imus nocte et consumimur igni\");", + "", + "", + "{{Out}}", + "
    true
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f51", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function isPalindrome(str) {\n return str === str.split(\"\").reverse().join(\"\");\n}\n\nconsole.log(isPalindrome(\"ingirumimusnocteetconsumimurigni\"));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Pangram checker", + "type": "Waypoint", + "description": [ + "

    A pangram is a sentence that contains all the letters of the English alphabet at least once.

    For example: The quick brown fox jumps over the lazy dog.

    ", + "Task:", + "

    Write a function or method to check a sentence to see if it is a pangram (or not) and show its use.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "====Iterative====", + "", + "function isPangram(s) {", + " var letters = \"zqxjkvbpygfwmucldrhsnioate\"", + " // sorted by frequency ascending (http://en.wikipedia.org/wiki/Letter_frequency)", + " s = s.toLowerCase().replace(/[^a-z]/g,'')", + " for (var i = 0; i < 26; i++)", + " if (s.indexOf(letters[i]) < 0) return false", + " return true", + "}", + "", + "console.log(isPangram(\"is this a pangram\")) // false", + "console.log(isPangram(\"The quick brown fox jumps over the lazy dog\")) // true", + "", + "===ES6===", + "====Functional====", + "", + "(() => {", + " 'use strict';", + "", + " // isPangram :: String -> Bool", + " let isPangram = s => {", + " let lc = s.toLowerCase();", + "", + " return 'abcdefghijklmnopqrstuvwxyz'", + " .split('')", + " .filter(c => lc.indexOf(c) === -1)", + " .length === 0;", + " };", + "", + " // TEST", + " return [", + " 'is this a pangram',", + " 'The quick brown fox jumps over the lazy dog'", + " ].map(isPangram);", + "", + "})();", + "", + "{{Out}}", + "
    [false, true]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f52", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function isPangram(s) {\n var letters = \"zqxjkvbpygfwmucldrhsnioate\"\n // sorted by frequency ascending (http://en.wikipedia.org/wiki/Letter_frequency)\n s = s.toLowerCase().replace(/[^a-z]/g,'')\n for (var i = 0; i < 26; i++)\n if (s.indexOf(letters[i]) < 0) return false\n return true\n}\n\nconsole.log(isPangram(\"is this a pangram\")) // false\nconsole.log(isPangram(\"The quick brown fox jumps over the lazy dog\")) // true\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Paraffins", + "type": "Waypoint", + "description": [ + "

    This organic chemistry task is essentially to implement a tree enumeration algorithm.

    ", + "Task:", + "

    Enumerate, without repetitions and in order of increasing size, all possible paraffin molecules (also known as alkanes).

    ", + "

    Paraffins are built up using only carbon atoms, which has four bonds, and hydrogen, which has one bond. All bonds for each atom must be used, so it is easiest to think of an alkane as linked carbon atoms forming the \"backbone\" structure, with adding hydrogen atoms linking the remaining unused bonds.

    In a paraffin, one is allowed neither double bonds (two bonds between the same pair of atoms), nor cycles of linked carbons. So all paraffins with n carbon atoms share the empirical formula CnH2n+2

    But for all n ≥ 4 there are several distinct molecules (\"isomers\") with the same formula but different structures.

    The number of isomers rises rather rapidly when n increases.

    In counting isomers it should be borne in mind that the four bond positions on a given carbon atom can be freely interchanged and bonds rotated (including 3-D \"out of the paper\" rotations when it's being observed on a flat diagram), so rotations or re-orientations of parts of the molecule (without breaking bonds) do not give different isomers. So what seem at first to be different molecules may in fact turn out to be different orientations of the same molecule.

    ", + "Example:", + "

    With n = 3 there is only one way of linking the carbons despite the different orientations the molecule can be drawn; and with n = 4 there are two configurations:

    ", + "

    ::* a straight chain: (CH3)(CH2)(CH2)(CH3)

    ", + "

    ::* a branched chain: (CH3)(CH(CH3))(CH3)

    ", + "

    Due to bond rotations, it doesn't matter which direction the branch points in.

    The phenomenon of \"stereo-isomerism\" (a molecule being different from its mirror image due to the actual 3-D arrangement of bonds) is ignored for the purpose of this task.

    The input is the number n of carbon atoms of a molecule (for instance 17).

    The output is how many different different paraffins there are with n carbon atoms (for instance 24,894 if n = 17).

    The sequence of those results is visible in the Sloane encyclopedia. The sequence is (the index starts from zero, and represents the number of carbon atoms):

    1, 1, 1, 1, 2, 3, 5, 9, 18, 35, 75, 159, 355, 802, 1858, 4347, 10359,

    ", + "

    24894, 60523, 148284, 366319, 910726, 2278658, 5731580, 14490245,

    ", + "

    36797588, 93839412, 240215803, 617105614, 1590507121, 4111846763,

    ", + "

    10660307791, 27711253769, ...

    ", + "Extra credit:", + "

    Show the paraffins in some way.

    A flat 1D representation, with arrays or lists is enough, for instance:

    *Main> all_paraffins 1

    ", + "

    [CCP H H H H]

    ", + "Main> all_paraffins 2 [BCP (C H H H) (C H H H)]", + "Main> all_paraffins 3 [CCP H H (C H H H) (C H H H)]", + "Main> all_paraffins 4 [BCP (C H H (C H H H)) (C H H (C H H H)),CCP H (C H H H) (C H H H)", + "

    (C H H H)]

    ", + "Main> all_paraffins 5 [CCP H H (C H H (C H H H)) (C H H (C H H H)),CCP H (C H H H)", + "

    (C H H H) (C H H (C H H H)),CCP (C H H H) (C H H H) (C H H H)

    ", + "

    (C H H H)]

    ", + "Main> all_paraffins 6 [BCP (C H H (C H H (C H H H))) (C H H (C H H (C H H H))),BCP", + "

    (C H H (C H H (C H H H))) (C H (C H H H) (C H H H)),BCP (C H

    ", + "

    (C H H H) (C H H H)) (C H (C H H H) (C H H H)),CCP H (C H H H)

    ", + "

    (C H H (C H H H)) (C H H (C H H H)),CCP (C H H H) (C H H H)

    ", + "

    (C H H H) (C H H (C H H H))]

    Showing a basic 2D ASCII-art representation of the paraffins is better; for instance (molecule names aren't necessary):

    ", + "
     Methane         Ethane              Propane              Isobutane"
    +      ],
    +      "null": [
    +        "    H             H   H             H   H   H             H   H   H",
    +        "    |             |   |             |   |   |             |   |   |",
    +        "H - C - H     H - C - C - H     H - C - C - C - H     H - C - C - C - H",
    +        "    |             |   |             |   |   |             |   |   |",
    +        "    H             H   H             H   H   H             H   |   H",
    +        "                                                              |",
    +        "                                                          H - C - H",
    +        "                                                              |",
    +        "                                                              H
  • ", + "
    Links:
    ", + "
    • A paper that explains the problem and its solution in a functional language:
    http://www.cs.wright.edu/~tkprasad/courses/cs776/paraffins-turner.pdf
    • A Haskell implementation:
    https://github.com/ghc/nofib/blob/master/imaginary/paraffins/Main.hs
    • A Scheme implementation:
    http://www.ccs.neu.edu/home/will/Twobit/src/paraffins.scm
    • A Fortress implementation:
    http://java.net/projects/projectfortress/sources/sources/content/ProjectFortress/demos/turnersParaffins0.fss?rev=3005", + "

    ", + "

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f53", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Parallel Brute Force", + "type": "Waypoint", + "description": [ + "Task:

    Find, through brute force, the five-letter passwords corresponding with the following SHA-256 hashes:

    1. 1115dd800feaacefdf481f1f9070374a2a81e27880f187396db67958b207cbad

    ", + "

    2. 3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b

    ", + "

    3. 74e1bb62f8dabb8125a58852b63bdf6eaef667cb56ac7f7cdba6d7305c50a22f

    Your program should naively iterate through all possible passwords consisting only of five lower-case ASCII English letters. It should use concurrent or parallel processing, if your language supports that feature. You may calculate SHA-256 hashes by calling a library or through a custom implementation. Print each matching password, along with its SHA-256 hash.

    Related task: SHA-256

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f54", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Parallel calculations", + "type": "Waypoint", + "description": [ + "

    Many programming languages allow you to specify computations to be run in parallel.

    ", + "

    While Concurrent computing is focused on concurrency,

    ", + "

    the purpose of this task is to distribute time-consuming calculations

    ", + "

    on as many CPUs as possible.

    Assume we have a collection of numbers, and want to find the one

    ", + "

    with the largest minimal prime factor

    ", + "

    (that is, the one that contains relatively large factors).

    ", + "

    To speed up the search, the factorization should be done

    ", + "

    in parallel using separate threads or processes,

    ", + "

    to take advantage of multi-core CPUs.

    Show how this can be formulated in your language.

    ", + "

    Parallelize the factorization of those numbers,

    ", + "

    then search the returned list of numbers and factors

    ", + "

    for the largest minimal factor,

    ", + "

    and return that number and its prime factors.

    For the prime number decomposition

    ", + "

    you may use the solution of the Prime decomposition task.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "This code demonstrates Web Workers. This should work on current versions of Firefox, Safari, Chrome and Opera.", + "", + "This first portion should be placed in a file called \"parallel_worker.js\". This file contains the logic used by every worker created.", + "", + "var onmessage = function(event) { ", + " postMessage({\"n\" : event.data.n,", + " \"factors\" : factor(event.data.n),", + " \"id\" : event.data.id});", + "};", + "", + "function factor(n) {", + " var factors = [];", + " for(p = 2; p <= n; p++) {", + " if((n % p) == 0) {", + " factors[factors.length] = p;", + " n /= p;", + " }", + " }", + " return factors;", + "}", + "", + "", + "For each number a worker is spawned. Once the final worker completes its task (worker_count is reduced to 0), the reduce function is called to determine which number is the answer.", + "", + "var numbers = [12757923, 12878611, 12757923, 15808973, 15780709, 197622519];", + "var workers = [];", + "var worker_count = 0;", + "", + "var results = [];", + "", + "for(var i = 0; i < numbers.length; i++) {", + " worker_count++;", + " workers[i] = new Worker(\"parallel_worker.js\");", + " workers[i].onmessage = accumulate;", + " workers[i].postMessage({n: numbers[i], id: i});", + "}", + "", + "function accumulate(event) {", + " n = event.data.n;", + " factors = event.data.factors;", + " id = event.data.id;", + " console.log(n + \" : \" + factors);", + " results[id] = {n:n, factors:factors};", + " // Cleanup - kill the worker and countdown until all work is done", + " workers[id].terminate();", + " worker_count--;", + " if(worker_count == 0)", + "\treduce();", + "}", + "", + "function reduce() {", + " answer = 0;", + " for(i = 1; i < results.length; i++) {", + "\tmin = results[i].factors[0];", + "\tlargest_min = results[answer].factors[0];", + "\tif(min > largest_min)", + "\t answer = i;", + " }", + " n = results[answer].n;", + " factors = results[answer].factors;", + " console.log(\"The number with the relatively largest factors is: \" + n + \" : \" + factors);", + "}", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f55", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nvar onmessage = function(event) { \n postMessage({\"n\" : event.data.n,\n \"factors\" : factor(event.data.n),\n \"id\" : event.data.id});\n};\n\nfunction factor(n) {\n var factors = [];\n for(p = 2; p <= n; p++) {\n if((n % p) == 0) {\n factors[factors.length] = p;\n n /= p;\n }\n }\n return factors;\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Parse an IP Address", + "type": "Waypoint", + "description": [ + "

    The purpose of this task is to demonstrate parsing of text-format IP addresses, using IPv4 and IPv6.

    Taking the following as inputs:

    ", + "

    {| border=\"1\" cellspacing=\"0\" cellpadding=2

    ", + "

    |-

    ", + "

    |127.0.0.1

    ", + "

    |The \"localhost\" IPv4 address

    ", + "

    |-

    ", + "

    |127.0.0.1:80

    ", + "

    |The \"localhost\" IPv4 address, with a specified port (80)

    ", + "

    |-

    ", + "

    |::1

    ", + "

    |The \"localhost\" IPv6 address

    ", + "

    |-

    ", + "

    |[::1]:80

    ", + "

    |The \"localhost\" IPv6 address, with a specified port (80)

    ", + "

    |-

    ", + "

    |2605:2700:0:3::4713:93e3

    ", + "

    |Rosetta Code's primary server's public IPv6 address

    ", + "

    |-

    ", + "

    |[2605:2700:0:3::4713:93e3]:80

    ", + "

    |Rosetta Code's primary server's public IPv6 address, with a specified port (80)

    ", + "

    |}

    Emit each described IP address as a hexadecimal integer representing the address, the address space, and the port number specified, if any. In languages where variant result types are clumsy, the result should be ipv4 or ipv6 address number, something which says which address space was represented, port number and something that says if the port was specified.

    For example 127.0.0.1 has the address number 7F000001 (2130706433 decimal) in the ipv4 address space. ::ffff:127.0.0.1 represents the same address in the ipv6 address space where it has the address number FFFF7F000001 (281472812449793 decimal). Meanwhile ::1 has address number 1 and serves the same purpose in the ipv6 address space that 127.0.0.1 serves in the ipv4 address space.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f58", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Parsing/RPN calculator algorithm", + "type": "Waypoint", + "description": [ + "Task:", + "

    Create a stack-based evaluator for an expression in reverse Polish notation (RPN) that also shows the changes in the stack as each individual token is processed as a table.

    ", + "Assume an input of a correct, space separated, string of tokens of an RPN expression", + "Test with the RPN expression generated from the Parsing/Shunting-yard algorithm task: 3 4 2 * 1 5 - 2 3 ^ ^ / + ", + "Print or display the output hereNotes:", + " ^ means exponentiation in the expression above.", + " / means division.See also:", + " Parsing/Shunting-yard algorithm for a method of generating an RPN from an infix expression.", + " Several solutions to 24 game/Solve make use of RPN evaluators (although tracing how they work is not a part of that task).", + " Parsing/RPN to infix conversion.", + " Arithmetic evaluation." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "var e = '3 4 2 * 1 5 - 2 3 ^ ^ / +'", + "var s=[], e=e.split(' ')", + "for (var i in e) {", + "\tvar t=e[i], n=+t", + "\tif (n == t)", + "\t\ts.push(n)", + "\telse {", + "\t\tvar o2=s.pop(), o1=s.pop()", + "\t\tswitch (t) {", + "\t\t\tcase '+': s.push(o1+o2); break;", + "\t\t\tcase '-': s.push(o1-o2); break;", + "\t\t\tcase '*': s.push(o1*o2); break;", + "\t\t\tcase '/': s.push(o1/o2); break;", + "\t\t\tcase '^': s.push(Math.pow(o1,o2)); break;", + "\t\t}", + "\t}", + "\tdocument.write(t, ': ', s, '
    ')", + "}
    ", + "{{out}}", + "
    ",
    +        "3: 3",
    +        "4: 3,4",
    +        "2: 3,4,2",
    +        "*: 3,8",
    +        "1: 3,8,1",
    +        "5: 3,8,1,5",
    +        "-: 3,8,-4",
    +        "2: 3,8,-4,2",
    +        "3: 3,8,-4,2,3",
    +        "^: 3,8,-4,8",
    +        "^: 3,8,65536",
    +        "/: 3,0.0001220703125",
    +        "+: 3.0001220703125",
    +        "
    ", + "==== With checks and messages ====", + "var e = '3 4 2 * 1 5 - 2 3 ^ ^ / +'", + "eval: {", + "\tdocument.write(e, '
    ')", + "\tvar s=[], e=e.split(' ')", + "\tfor (var i in e) {", + "\t\tvar t=e[i], n=+t", + "\t\tif (!t) continue", + "\t\tif (n == t)", + "\t\t\ts.push(n)", + "\t\telse {", + "\t\t\tif ('+-*/^'.indexOf(t) == -1) {", + "\t\t\t\tdocument.write(t, ': ', s, '
    ', 'Unknown operator!
    ')", + "\t\t\t\tbreak eval", + "\t\t\t}", + "\t\t\tif (s.length<2) {", + "\t\t\t\tdocument.write(t, ': ', s, '
    ', 'Insufficient operands!
    ')", + "\t\t\t\tbreak eval", + "\t\t\t}", + "\t\t\tvar o2=s.pop(), o1=s.pop()", + "\t\t\tswitch (t) {", + "\t\t\t\tcase '+': s.push(o1+o2); break", + "\t\t\t\tcase '-': s.push(o1-o2); break", + "\t\t\t\tcase '*': s.push(o1*o2); break", + "\t\t\t\tcase '/': s.push(o1/o2); break", + "\t\t\t\tcase '^': s.push(Math.pow(o1,o2))", + "\t\t\t}", + "\t\t}", + "\t\tdocument.write(t, ': ', s, '
    ')", + "\t}", + "\tif (s.length>1) {", + "\t\tdocument.write('Insufficient operators!
    ')", + "\t}", + "}
    ", + "{{out}}", + "
    ",
    +        "3 4 2 * 1 5 - 2 3 ^ ^ / +",
    +        "3: 3",
    +        "4: 3,4",
    +        "2: 3,4,2",
    +        "*: 3,8",
    +        "1: 3,8,1",
    +        "5: 3,8,1,5",
    +        "-: 3,8,-4",
    +        "2: 3,8,-4,2",
    +        "3: 3,8,-4,2,3",
    +        "^: 3,8,-4,8",
    +        "^: 3,8,65536",
    +        "/: 3,0.0001220703125",
    +        "+: 3.0001220703125",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f59", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var e = '3 4 2 * 1 5 - 2 3 ^ ^ / +'\nvar s=[], e=e.split(' ')\nfor (var i in e) {\n\tvar t=e[i], n=+t\n\tif (n == t)\n\t\ts.push(n)\n\telse {\n\t\tvar o2=s.pop(), o1=s.pop()\n\t\tswitch (t) {\n\t\t\tcase '+': s.push(o1+o2); break;\n\t\t\tcase '-': s.push(o1-o2); break;\n\t\t\tcase '*': s.push(o1*o2); break;\n\t\t\tcase '/': s.push(o1/o2); break;\n\t\t\tcase '^': s.push(Math.pow(o1,o2)); break;\n\t\t}\n\t}\n\tdocument.write(t, ': ', s, '
    ')\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Parsing/RPN to infix conversion", + "type": "Waypoint", + "description": [ + "Task:", + "

    Create a program that takes an RPN representation of an expression formatted as a space separated sequence of tokens and generates the equivalent expression in infix notation.

    Assume an input of a correct, space separated, string of tokens", + "Generate a space separated output string representing the same expression in infix notation", + "Show how the major datastructure of your algorithm changes with each new token parsed.", + "Test with the following input RPN strings then print and display the output here.{|", + "

    ! RPN input !! sample output

    ", + "

    |- || align=\"center\"

    ", + "

    | 3 4 2 * 1 5 - 2 3 ^ ^ / +|| 3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3

    ", + "

    |- || align=\"center\"

    ", + "

    | 1 2 + 3 4 + ^ 5 6 + ^|| ( ( 1 + 2 ) ^ ( 3 + 4 ) ) ^ ( 5 + 6 )

    ", + "

    |}

    Operator precedence and operator associativity is given in this table:{|

    ! operator !! precedence !! associativity !! operation

    ", + "

    |- || align=\"center\"

    ", + "

    | ^ || 4 || right || exponentiation

    ", + "

    |- || align=\"center\"

    ", + "

    | * || 3 || left || multiplication

    ", + "

    |- || align=\"center\"

    ", + "

    | / || 3 || left || division

    ", + "

    |- || align=\"center\"

    ", + "

    | + || 2 || left || addition

    ", + "

    |- || align=\"center\"

    ", + "

    | - || 2 || left || subtraction

    ", + "

    |}

    ", + "See also:", + " Parsing/Shunting-yard algorithm for a method of generating an RPN from an infix expression.", + " Parsing/RPN calculator algorithm for a method of calculating a final value from this output RPN expression.", + " Postfix to infix from the RubyQuiz site." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Needs EcmaScript 6 support (e.g. Chrome).", + "", + "const Associativity = {", + " /** a / b / c = (a / b) / c */", + " left: 0,", + " /** a ^ b ^ c = a ^ (b ^ c) */", + " right: 1,", + " /** a + b + c = (a + b) + c = a + (b + c) */", + " both: 2,", + "};", + "const operators = {", + " '+': { precedence: 2, associativity: Associativity.both },", + " '-': { precedence: 2, associativity: Associativity.left },", + " '*': { precedence: 3, associativity: Associativity.both },", + " '/': { precedence: 3, associativity: Associativity.left },", + " '^': { precedence: 4, associativity: Associativity.right },", + "};", + "class NumberNode {", + " constructor(text) { this.text = text; }", + " toString() { return this.text; }", + "}", + "class InfixNode {", + " constructor(fnname, operands) {", + " this.fnname = fnname;", + " this.operands = operands;", + " }", + " toString(parentPrecedence = 0) {", + " const op = operators[this.fnname];", + " const leftAdd = op.associativity === Associativity.right ? 0.01 : 0;", + " const rightAdd = op.associativity === Associativity.left ? 0.01 : 0;", + " if (this.operands.length !== 2) throw Error(\"invalid operand count\");", + " const result = this.operands[0].toString(op.precedence + leftAdd)", + " +` ${this.fnname} ${this.operands[1].toString(op.precedence + rightAdd)}`;", + " if (parentPrecedence > op.precedence) return `( ${result} )`;", + " else return result;", + " }", + "}", + "function rpnToTree(tokens) {", + " const stack = [];", + " console.log(`input = ${tokens}`);", + " for (const token of tokens.split(\" \")) {", + " if (token in operators) {", + " const op = operators[token], arity = 2; // all of these operators take 2 arguments", + " if (stack.length < arity) throw Error(\"stack error\");", + " stack.push(new InfixNode(token, stack.splice(stack.length - arity)));", + " }", + " else stack.push(new NumberNode(token));", + " console.log(`read ${token}, stack = [${stack.join(\", \")}]`);", + " }", + " if (stack.length !== 1) throw Error(\"stack error \" + stack);", + " return stack[0];", + "}", + "const tests = [", + " [\"3 4 2 * 1 5 - 2 3 ^ ^ / +\", \"3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3\"],", + " [\"1 2 + 3 4 + ^ 5 6 + ^\", \"( ( 1 + 2 ) ^ ( 3 + 4 ) ) ^ ( 5 + 6 )\"],", + " [\"1 2 3 + +\", \"1 + 2 + 3\"] // test associativity (1+(2+3)) == (1+2+3)", + "];", + "for (const [inp, oup] of tests) {", + " const realOup = rpnToTree(inp).toString();", + " console.log(realOup === oup ? \"Correct!\" : \"Incorrect!\");", + "}", + "", + "Output:", + "
    input = 3 4 2 * 1 5 - 2 3 ^ ^ / +",
    +        "read 3, stack = [3]",
    +        "read 4, stack = [3, 4]",
    +        "read 2, stack = [3, 4, 2]",
    +        "read *, stack = [3, 4 * 2]",
    +        "read 1, stack = [3, 4 * 2, 1]",
    +        "read 5, stack = [3, 4 * 2, 1, 5]",
    +        "read -, stack = [3, 4 * 2, 1 - 5]",
    +        "read 2, stack = [3, 4 * 2, 1 - 5, 2]",
    +        "read 3, stack = [3, 4 * 2, 1 - 5, 2, 3]",
    +        "read ^, stack = [3, 4 * 2, 1 - 5, 2 ^ 3]",
    +        "read ^, stack = [3, 4 * 2, ( 1 - 5 ) ^ 2 ^ 3]",
    +        "read /, stack = [3, 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3]",
    +        "read +, stack = [3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3]",
    +        "Correct!",
    +        "input = 1 2 + 3 4 + ^ 5 6 + ^",
    +        "read 1, stack = [1]",
    +        "read 2, stack = [1, 2]",
    +        "read +, stack = [1 + 2]",
    +        "read 3, stack = [1 + 2, 3]",
    +        "read 4, stack = [1 + 2, 3, 4]",
    +        "read +, stack = [1 + 2, 3 + 4]",
    +        "read ^, stack = [( 1 + 2 ) ^ ( 3 + 4 )]",
    +        "read 5, stack = [( 1 + 2 ) ^ ( 3 + 4 ), 5]",
    +        "read 6, stack = [( 1 + 2 ) ^ ( 3 + 4 ), 5, 6]",
    +        "read +, stack = [( 1 + 2 ) ^ ( 3 + 4 ), 5 + 6]",
    +        "read ^, stack = [( ( 1 + 2 ) ^ ( 3 + 4 ) ) ^ ( 5 + 6 )]",
    +        "Correct!",
    +        "input = 1 2 3 + +",
    +        "read 1, stack = [1]",
    +        "read 2, stack = [1, 2]",
    +        "read 3, stack = [1, 2, 3]",
    +        "read +, stack = [1, 2 + 3]",
    +        "read +, stack = [1 + 2 + 3]",
    +        "Correct!
    ", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f5a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "const Associativity = {\n /** a / b / c = (a / b) / c */\n left: 0,\n /** a ^ b ^ c = a ^ (b ^ c) */\n right: 1,\n /** a + b + c = (a + b) + c = a + (b + c) */\n both: 2,\n};\nconst operators = {\n '+': { precedence: 2, associativity: Associativity.both },\n '-': { precedence: 2, associativity: Associativity.left },\n '*': { precedence: 3, associativity: Associativity.both },\n '/': { precedence: 3, associativity: Associativity.left },\n '^': { precedence: 4, associativity: Associativity.right },\n};\nclass NumberNode {\n constructor(text) { this.text = text; }\n toString() { return this.text; }\n}\nclass InfixNode {\n constructor(fnname, operands) {\n this.fnname = fnname;\n this.operands = operands;\n }\n toString(parentPrecedence = 0) {\n const op = operators[this.fnname];\n const leftAdd = op.associativity === Associativity.right ? 0.01 : 0;\n const rightAdd = op.associativity === Associativity.left ? 0.01 : 0;\n if (this.operands.length !== 2) throw Error(\"invalid operand count\");\n const result = this.operands[0].toString(op.precedence + leftAdd)\n +` ${this.fnname} ${this.operands[1].toString(op.precedence + rightAdd)}`;\n if (parentPrecedence > op.precedence) return `( ${result} )`;\n else return result;\n }\n}\nfunction rpnToTree(tokens) {\n const stack = [];\n console.log(`input = ${tokens}`);\n for (const token of tokens.split(\" \")) {\n if (token in operators) {\n const op = operators[token], arity = 2; // all of these operators take 2 arguments\n if (stack.length < arity) throw Error(\"stack error\");\n stack.push(new InfixNode(token, stack.splice(stack.length - arity)));\n }\n else stack.push(new NumberNode(token));\n console.log(`read ${token}, stack = [${stack.join(\", \")}]`);\n }\n if (stack.length !== 1) throw Error(\"stack error \" + stack);\n return stack[0];\n}\nconst tests = [\n [\"3 4 2 * 1 5 - 2 3 ^ ^ / +\", \"3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3\"],\n [\"1 2 + 3 4 + ^ 5 6 + ^\", \"( ( 1 + 2 ) ^ ( 3 + 4 ) ) ^ ( 5 + 6 )\"],\n [\"1 2 3 + +\", \"1 + 2 + 3\"] // test associativity (1+(2+3)) == (1+2+3)\n];\nfor (const [inp, oup] of tests) {\n const realOup = rpnToTree(inp).toString();\n console.log(realOup === oup ? \"Correct!\" : \"Incorrect!\");\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Parsing/Shunting-yard algorithm", + "type": "Waypoint", + "description": [ + "Task:", + "

    Given the operator characteristics and input from the Shunting-yard algorithm page and tables, use the algorithm to show the changes in the operator stack and RPN output

    ", + "

    as each individual token is processed.

    Assume an input of a correct, space separated, string of tokens representing an infix expression", + "Generate a space separated output string representing the RPN", + "Test with the input string:::: 3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3 ", + "print and display the output here.", + "Operator precedence is given in this table:{|

    ! operator !! precedence !! associativity !! operation

    ", + "

    |- || align=\"center\"

    ", + "

    | ^ || 4 || right || exponentiation

    ", + "

    |- || align=\"center\"

    ", + "

    | * || 3 || left || multiplication

    ", + "

    |- || align=\"center\"

    ", + "

    | / || 3 || left || division

    ", + "

    |- || align=\"center\"

    ", + "

    | + || 2 || left || addition

    ", + "

    |- || align=\"center\"

    ", + "

    | - || 2 || left || subtraction

    ", + "

    |}

    ", + "Extra credit", + "

    Add extra text explaining the actions and an optional comment for the action on receipt of each token.

    ", + "Note", + "

    The handling of functions and arguments is not required.

    ", + "See also:", + "Parsing/RPN calculator algorithm for a method of calculating a final value from this output RPN expression.", + "Parsing/RPN to infix conversion." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function Stack() {", + " this.dataStore = [];", + " this.top = 0;", + " this.push = push;", + " this.pop = pop;", + " this.peek = peek;", + " this.length = length;", + "}", + " ", + "function push(element) {", + " this.dataStore[this.top++] = element;", + "}", + " ", + "function pop() {", + " return this.dataStore[--this.top];", + "}", + " ", + "function peek() {", + " return this.dataStore[this.top-1];", + "}", + " ", + "function length() {", + " return this.top;", + "}", + " ", + "var infix = \"3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3\";", + "infix = infix.replace(/\\s+/g, ''); // remove spaces, so infix[i]!=\" \"", + "", + "var s = new Stack();", + "var ops = \"-+/*^\";", + "var precedence = {\"^\":4, \"*\":3, \"/\":3, \"+\":2, \"-\":2};", + "var associativity = {\"^\":\"Right\", \"*\":\"Left\", \"/\":\"Left\", \"+\":\"Left\", \"-\":\"Left\"};", + "var token;", + "var postfix = \"\";", + "var o1, o2;", + "", + "for (var i = 0; i < infix.length; i++) {", + " token = infix[i];", + " if (token >= \"0\" && token <= \"9\") { // if token is operand (here limited to 0 <= x <= 9)", + " postfix += token + \" \";", + " }", + " else if (ops.indexOf(token) != -1) { // if token is an operator", + " o1 = token;", + " o2 = s.peek();", + " while (ops.indexOf(o2)!=-1 && ( // while operator token, o2, on top of the stack", + " // and o1 is left-associative and its precedence is less than or equal to that of o2", + " (associativity[o1] == \"Left\" && (precedence[o1] <= precedence[o2]) ) || ", + " // the algorithm on wikipedia says: or o1 precedence < o2 precedence, but I think it should be", + " // or o1 is right-associative and its precedence is less than that of o2", + " (associativity[o1] == \"Right\" && (precedence[o1] < precedence[o2])) ", + " )){", + " postfix += o2 + \" \"; // add o2 to output queue", + " s.pop(); // pop o2 of the stack", + " o2 = s.peek(); // next round", + " }", + " s.push(o1); // push o1 onto the stack", + " }", + " else if (token == \"(\") { // if token is left parenthesis", + " s.push(token); // then push it onto the stack", + " }", + " else if (token == \")\") { // if token is right parenthesis ", + " while (s.peek() != \"(\"){ // until token at top is (", + " postfix += s.pop() + \" \";", + " }", + " s.pop(); // pop (, but not onto the output queue", + " }", + "}", + "while (s.length()>0){", + " postfix += s.pop() + \" \";", + "}", + "print(postfix);", + "", + "Output:", + "", + "
    infix:   3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3",
    +        "postfix: 3 4 2 * 1 5 - 2 3 ^ ^ / + 
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f5b", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function Stack() {\n this.dataStore = [];\n this.top = 0;\n this.push = push;\n this.pop = pop;\n this.peek = peek;\n this.length = length;\n}\n \nfunction push(element) {\n this.dataStore[this.top++] = element;\n}\n \nfunction pop() {\n return this.dataStore[--this.top];\n}\n \nfunction peek() {\n return this.dataStore[this.top-1];\n}\n \nfunction length() {\n return this.top;\n}\n \nvar infix = \"3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3\";\ninfix = infix.replace(/\\s+/g, ''); // remove spaces, so infix[i]!=\" \"\n\nvar s = new Stack();\nvar ops = \"-+/*^\";\nvar precedence = {\"^\":4, \"*\":3, \"/\":3, \"+\":2, \"-\":2};\nvar associativity = {\"^\":\"Right\", \"*\":\"Left\", \"/\":\"Left\", \"+\":\"Left\", \"-\":\"Left\"};\nvar token;\nvar postfix = \"\";\nvar o1, o2;\n\nfor (var i = 0; i < infix.length; i++) {\n token = infix[i];\n if (token >= \"0\" && token <= \"9\") { // if token is operand (here limited to 0 <= x <= 9)\n postfix += token + \" \";\n }\n else if (ops.indexOf(token) != -1) { // if token is an operator\n o1 = token;\n o2 = s.peek();\n while (ops.indexOf(o2)!=-1 && ( // while operator token, o2, on top of the stack\n // and o1 is left-associative and its precedence is less than or equal to that of o2\n (associativity[o1] == \"Left\" && (precedence[o1] <= precedence[o2]) ) || \n // the algorithm on wikipedia says: or o1 precedence < o2 precedence, but I think it should be\n // or o1 is right-associative and its precedence is less than that of o2\n (associativity[o1] == \"Right\" && (precedence[o1] < precedence[o2])) \n )){\n postfix += o2 + \" \"; // add o2 to output queue\n s.pop(); // pop o2 of the stack\n o2 = s.peek(); // next round\n }\n s.push(o1); // push o1 onto the stack\n }\n else if (token == \"(\") { // if token is left parenthesis\n s.push(token); // then push it onto the stack\n }\n else if (token == \")\") { // if token is right parenthesis \n while (s.peek() != \"(\"){ // until token at top is (\n postfix += s.pop() + \" \";\n }\n s.pop(); // pop (, but not onto the output queue\n }\n}\nwhile (s.length()>0){\n postfix += s.pop() + \" \";\n}\nprint(postfix);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Pascal matrix generation", + "type": "Waypoint", + "description": [ + "

    A pascal matrix is a two-dimensional square matrix holding numbers from Pascal's triangle, also known as binomial coefficients and which can be shown as nCr.

    Shown below are truncated 5-by-5 matrices M[i, j] for i,j in range 0..4.

    A Pascal upper-triangular matrix that is populated with jCi:

    ", + "
    ",
    +        "[[1, 1, 1, 1, 1],",
    +        " [0, 1, 2, 3, 4],",
    +        " [0, 0, 1, 3, 6],",
    +        " [0, 0, 0, 1, 4],",
    +        " [0, 0, 0, 0, 1]]",
    +        "

    A Pascal lower-triangular matrix that is populated with iCj (the transpose of the upper-triangular matrix):

    ", + "
    ",
    +        "[[1, 0, 0, 0, 0],",
    +        " [1, 1, 0, 0, 0],",
    +        " [1, 2, 1, 0, 0],",
    +        " [1, 3, 3, 1, 0],",
    +        " [1, 4, 6, 4, 1]]",
    +        "

    A Pascal symmetric matrix that is populated with i+jCi:

    ", + "
    ",
    +        "[[1, 1, 1, 1, 1],",
    +        " [1, 2, 3, 4, 5],",
    +        " [1, 3, 6, 10, 15],",
    +        " [1, 4, 10, 20, 35],",
    +        " [1, 5, 15, 35, 70]]",
    +        "
    ", + "Task:", + "

    Write functions capable of generating each of the three forms of n-by-n matrices.

    Use those functions to display upper, lower, and symmetric Pascal 5-by-5 matrices on this page.

    The output should distinguish between different matrices and the rows of each matrix (no showing a list of 25 numbers assuming the reader should split it into rows).

    ", + "Note: ", + "

    The Cholesky decomposition of a Pascal symmetric matrix is the Pascal lower-triangle matrix of the same size.

    ", + " " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "In terms of a binomial coefficient, and a function on a coordinate pair.", + "{{Trans|Haskell}}", + "===ES6===", + "(() => {", + " 'use strict';", + "", + " // PASCAL MATRIX ---------------------------------------------------------", + "", + " // (Function on a coordinate pair) -> Matrix size -> Matrix rows", + " // pascalMatrix :: ((Int, Int) -> (Int, Int)) -> Int -> [[Int]]", + " const pascalMatrix = (f, n) =>", + " chunksOf(n, map(compose(bc, f), range([", + " [0, 0],", + " [n - 1, n - 1]", + " ])));", + "", + " // Binomial coefficient", + " // bc :: (Int, Int) -> Int", + " const bc = ([n, k]) => enumFromTo(1, k)", + " .reduce((a, x) => Math.floor((a * (n - x + 1)) / x), 1);", + "", + "", + " // GENERIC FUNCTIONS -----------------------------------------------------", + "", + " // chunksOf :: Int -> [a] -> [[a]]", + " const chunksOf = (n, xs) =>", + " xs.reduce((a, _, i, xs) =>", + " i % n ? a : a.concat([xs.slice(i, i + n)]), []);", + "", + " // show ::", + " // (a -> String) f, Num n =>", + " // a -> maybe f -> maybe n -> String", + " const show = JSON.stringify;", + "", + " // swap :: (a, b) -> (b, a)", + " const swap = ([a, b]) => [b, a];", + "", + " // compose :: (b -> c) -> (a -> b) -> (a -> c)", + " const compose = (f, g) => x => f(g(x));", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " const curry = f => a => b => f(a, b);", + "", + " // cons :: a -> [a] -> [a]", + " const cons = (x, xs) => [x].concat(xs);", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = (f, xs) => xs.map(f);", + "", + " // id :: a -> a", + " const id = x => x;", + "", + " // A list of functions applied to a list of arguments", + " // <*> :: [(a -> b)] -> [a] -> [b]", + " const ap = (fs, xs) => //", + " [].concat.apply([], fs.map(f => //", + " [].concat.apply([], xs.map(x => [f(x)]))));", + "", + " // Map each element of a structure to an action,", + " // evaluate these actions from left to right,", + " // and collect the results.", + " // traverse :: (a -> [b]) -> [a] -> [[b]]", + " const traverse = (f, xs) => {", + " const cons_f = (a, x) => ap(f(x)", + " .map(curry(cons)), a);", + " return xs.reduceRight(cons_f, [", + " []", + " ]);", + " };", + "", + " // Evaluate left to right, and collect the results", + " // sequence :: Monad m => [m a] -> m [a]", + " const sequence = xs => traverse(id, xs);", + "", + " // enumFromTo :: Int -> Int -> [Int]", + " const enumFromTo = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // range :: Ix a => (a, a) -> [a]", + " const range = ([a, b]) => {", + " const [as, bs] = a instanceof Array ? [a, b] : [", + " [a],", + " [b]", + " ],", + " an = as.length;", + " return (an === bs.length) ? (", + " an > 1 ? (", + " sequence(as.map((_, i) => enumFromTo(as[i], bs[i])))", + " ) : enumFromTo(a, b)", + " ) : undefined;", + " };", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " const zipWith = (f, xs, ys) => {", + " const ny = ys.length;", + " return (xs.length <= ny ? xs : xs.slice(0, ny))", + " .map((x, i) => f(x, ys[i]));", + " };", + "", + " // concat :: [[a]] -> [a] | [String] -> String", + " const concat = xs => {", + " if (xs.length > 0) {", + " const unit = typeof xs[0] === 'string' ? '' : [];", + " return unit.concat.apply(unit, xs);", + " } else return [];", + " };", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + "", + " // TEST ------------------------------------------------------------------", + " const matrixSize = 5;", + "", + " return unlines(", + " zipWith(", + " (s, xs) => unlines(concat([", + " [s], xs.map(show), ['']", + " ])), [\"Lower\", \"Upper\", \"Symmetric\"],", + " ap(", + " map(", + " f => curry(pascalMatrix)(f), [", + " id, // Lower", + " swap, // Upper", + " ([a, b]) => [a + b, a] // Symmetric", + " ]", + " ), [matrixSize]", + " )", + " )", + " );", + "})();", + "{{Out}}", + "
    Lower",
    +        "[1,0,0,0,0]",
    +        "[1,1,0,0,0]",
    +        "[1,2,1,0,0]",
    +        "[1,3,3,1,0]",
    +        "[1,4,6,4,1]",
    +        "",
    +        "Upper",
    +        "[1,1,1,1,1]",
    +        "[0,1,2,3,4]",
    +        "[0,0,1,3,6]",
    +        "[0,0,0,1,4]",
    +        "[0,0,0,0,1]",
    +        "",
    +        "Symmetric",
    +        "[1,1,1,1,1]",
    +        "[1,2,3,4,5]",
    +        "[1,3,6,10,15]",
    +        "[1,4,10,20,35]",
    +        "[1,5,15,35,70]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f5d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n 'use strict';\n\n // PASCAL MATRIX ---------------------------------------------------------\n\n // (Function on a coordinate pair) -> Matrix size -> Matrix rows\n // pascalMatrix :: ((Int, Int) -> (Int, Int)) -> Int -> [[Int]]\n const pascalMatrix = (f, n) =>\n chunksOf(n, map(compose(bc, f), range([\n [0, 0],\n [n - 1, n - 1]\n ])));\n\n // Binomial coefficient\n // bc :: (Int, Int) -> Int\n const bc = ([n, k]) => enumFromTo(1, k)\n .reduce((a, x) => Math.floor((a * (n - x + 1)) / x), 1);\n\n\n // GENERIC FUNCTIONS -----------------------------------------------------\n\n // chunksOf :: Int -> [a] -> [[a]]\n const chunksOf = (n, xs) =>\n xs.reduce((a, _, i, xs) =>\n i % n ? a : a.concat([xs.slice(i, i + n)]), []);\n\n // show ::\n // (a -> String) f, Num n =>\n // a -> maybe f -> maybe n -> String\n const show = JSON.stringify;\n\n // swap :: (a, b) -> (b, a)\n const swap = ([a, b]) => [b, a];\n\n // compose :: (b -> c) -> (a -> b) -> (a -> c)\n const compose = (f, g) => x => f(g(x));\n\n // curry :: ((a, b) -> c) -> a -> b -> c\n const curry = f => a => b => f(a, b);\n\n // cons :: a -> [a] -> [a]\n const cons = (x, xs) => [x].concat(xs);\n\n // map :: (a -> b) -> [a] -> [b]\n const map = (f, xs) => xs.map(f);\n\n // id :: a -> a\n const id = x => x;\n\n // A list of functions applied to a list of arguments\n // <*> :: [(a -> b)] -> [a] -> [b]\n const ap = (fs, xs) => //\n [].concat.apply([], fs.map(f => //\n [].concat.apply([], xs.map(x => [f(x)]))));\n\n // Map each element of a structure to an action,\n // evaluate these actions from left to right,\n // and collect the results.\n // traverse :: (a -> [b]) -> [a] -> [[b]]\n const traverse = (f, xs) => {\n const cons_f = (a, x) => ap(f(x)\n .map(curry(cons)), a);\n return xs.reduceRight(cons_f, [\n []\n ]);\n };\n\n // Evaluate left to right, and collect the results\n // sequence :: Monad m => [m a] -> m [a]\n const sequence = xs => traverse(id, xs);\n\n // enumFromTo :: Int -> Int -> [Int]\n const enumFromTo = (m, n) =>\n Array.from({\n length: Math.floor(n - m) + 1\n }, (_, i) => m + i);\n\n // range :: Ix a => (a, a) -> [a]\n const range = ([a, b]) => {\n const [as, bs] = a instanceof Array ? [a, b] : [\n [a],\n [b]\n ],\n an = as.length;\n return (an === bs.length) ? (\n an > 1 ? (\n sequence(as.map((_, i) => enumFromTo(as[i], bs[i])))\n ) : enumFromTo(a, b)\n ) : undefined;\n };\n\n // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]\n const zipWith = (f, xs, ys) => {\n const ny = ys.length;\n return (xs.length <= ny ? xs : xs.slice(0, ny))\n .map((x, i) => f(x, ys[i]));\n };\n\n // concat :: [[a]] -> [a] | [String] -> String\n const concat = xs => {\n if (xs.length > 0) {\n const unit = typeof xs[0] === 'string' ? '' : [];\n return unit.concat.apply(unit, xs);\n } else return [];\n };\n\n // unlines :: [String] -> String\n const unlines = xs => xs.join('\\n');\n\n\n // TEST ------------------------------------------------------------------\n const matrixSize = 5;\n\n return unlines(\n zipWith(\n (s, xs) => unlines(concat([\n [s], xs.map(show), ['']\n ])), [\"Lower\", \"Upper\", \"Symmetric\"],\n ap(\n map(\n f => curry(pascalMatrix)(f), [\n id, // Lower\n swap, // Upper\n ([a, b]) => [a + b, a] // Symmetric\n ]\n ), [matrixSize]\n )\n )\n );\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Pascal's triangle/Puzzle", + "type": "Waypoint", + "description": [ + "

    This puzzle involves a Pascals Triangle, also known as a Pyramid of Numbers.

    ", + "
    ",
    +        "           [ 151]",
    +        "          [  ][  ]",
    +        "        [40][  ][  ]",
    +        "      [  ][  ][  ][  ]",
    +        "    [ X][11][ Y][ 4][ Z]",
    +        "
    ", + "

    Each brick of the pyramid is the sum of the two bricks situated below it.

    ", + "

    Of the three missing numbers at the base of the pyramid,

    ", + "

    the middle one is the sum of the other two (that is, Y = X + Z).

    ", + "Task:", + "

    Write a program to find a solution to this puzzle.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f5e", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Pascal's triangle", + "type": "Waypoint", + "description": [ + "

    Pascal's triangle is an arithmetic and geometric figure first imagined by Blaise Pascal.

    Its first few rows look like this:

    ", + "

    1

    ", + "

    1 1

    ", + "

    1 2 1

    ", + "

    1 3 3 1

    ", + "

    where each element of each row is either 1 or the sum of the two elements right above it.

    For example, the next row of the triangle would be:

    ", + "

    :: 1 (since the first element of each row doesn't have two elements above it)

    ", + "

    :: 4 (1 + 3)

    ", + "

    :: 6 (3 + 3)

    ", + "

    :: 4 (3 + 1)

    ", + "

    :: 1 (since the last element of each row doesn't have two elements above it)

    So the triangle now looks like this:

    ", + "

    1

    ", + "

    1 1

    ", + "

    1 2 1

    ", + "

    1 3 3 1

    ", + "

    1 4 6 4 1

    Each row n (starting with row 0 at the top) shows the coefficients of the binomial expansion of (x + y)n.

    ", + "Task:", + "

    Write a function that prints out the first n rows of the triangle (with f(1) yielding the row consisting of only the element 1).

    This can be done either by summing elements from the previous rows or using a binary coefficient or combination function.

    Behavior for n ≤ 0 does not need to be uniform, but should be noted.

    ", + "See also:", + "Evaluate binomial coefficients" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "====Imperative====", + "{{works with|SpiderMonkey}}", + "{{works with|V8}}", + "// Pascal's triangle object", + "function pascalTriangle (rows) {", + "", + "\t// Number of rows the triangle contains", + "\tthis.rows = rows;", + "", + "\t// The 2D array holding the rows of the triangle", + "\tthis.triangle = new Array();", + "\tfor (var r = 0; r < rows; r++) {", + "\t\tthis.triangle[r] = new Array();", + "\t\tfor (var i = 0; i <= r; i++) {", + "\t\t\tif (i == 0 || i == r)", + "\t\t\t\tthis.triangle[r][i] = 1;", + "\t\t\telse", + "\t\t\t\tthis.triangle[r][i] = this.triangle[r-1][i-1]+this.triangle[r-1][i];", + "\t\t}", + "\t}", + "", + "\t// Method to print the triangle", + "\tthis.print = function(base) {", + "\t\tif (!base)", + "\t\t\tbase = 10;", + "", + "\t\t// Private method to calculate digits in number", + "\t\tvar digits = function(n,b) {", + "\t\t\tvar d = 0;", + "\t\t\twhile (n >= 1) {", + "\t\t\t\td++;", + "\t\t\t\tn /= b;", + "\t\t\t}", + "\t\t\treturn d;", + "\t\t}", + "", + "\t\t// Calculate max spaces needed", + "\t\tvar spacing = digits(this.triangle[this.rows-1][Math.round(this.rows/2)],base);", + "", + "\t\t// Private method to add spacing between numbers", + "\t\tvar insertSpaces = function(s) {", + "\t\t\tvar buf = \"\";", + "\t\t\twhile (s > 0) {", + "\t\t\t\ts--;", + "\t\t\t\tbuf += \" \";", + "\t\t\t}", + "\t\t\treturn buf;", + "\t\t}", + "", + "\t\t// Print the triangle line by line", + "\t\tfor (var r = 0; r < this.triangle.length; r++) {", + "\t\t\tvar l = \"\";", + "\t\t\tfor (var s = 0; s < Math.round(this.rows-1-r); s++) {", + "\t\t\t\tl += insertSpaces(spacing);", + "\t\t\t}", + "\t\t\tfor (var i = 0; i < this.triangle[r].length; i++) {", + "\t\t\t\tif (i != 0)", + "\t\t\t\t\tl += insertSpaces(spacing-Math.ceil(digits(this.triangle[r][i],base)/2));", + "\t\t\t\tl += this.triangle[r][i].toString(base);", + "\t\t\t\tif (i < this.triangle[r].length-1)", + "\t\t\t\t\tl += insertSpaces(spacing-Math.floor(digits(this.triangle[r][i],base)/2));", + "\t\t\t}", + "\t\t\tprint(l);", + "\t\t}", + "\t}", + "", + "}", + "", + "// Display 4 row triangle in base 10", + "var tri = new pascalTriangle(4);", + "tri.print();", + "// Display 8 row triangle in base 16", + "tri = new pascalTriangle(8);", + "tri.print(16);", + "Output:", + "
    $ d8 pascal.js ",
    +        "   1",
    +        "  1 1",
    +        " 1 2 1",
    +        "1 3 3 1",
    +        "              1",
    +        "            1   1",
    +        "          1   2   1",
    +        "        1   3   3   1",
    +        "      1   4   6   4   1",
    +        "    1   5   a   a   5   1",
    +        "  1   6   f   14  f   6   1",
    +        "1   7   15  23  23  15  7   1
    ", + "", + "====Functional====", + "{{Trans|Haskell}} ", + "(function (n) {", + " 'use strict';", + "", + " // PASCAL TRIANGLE --------------------------------------------------------", + "", + " // pascal :: Int -> [[Int]]", + " function pascal(n) {", + " return foldl(function (a) {", + " var xs = a.slice(-1)[0]; // Previous row", + " return append(a, [zipWith(", + " function (a, b) {", + " return a + b;", + " },", + " append([0], xs),", + " append(xs, [0])", + " )]);", + " }, [", + " [1] // Initial seed row", + " ], enumFromTo(1, n - 1));", + " };", + "", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // (++) :: [a] -> [a] -> [a]", + " function append(xs, ys) {", + " return xs.concat(ys);", + " };", + "", + " // enumFromTo :: Int -> Int -> [Int]", + " function enumFromTo(m, n) {", + " return Array.from({", + " length: Math.floor(n - m) + 1", + " }, function (_, i) {", + " return m + i;", + " });", + " };", + "", + " // foldl :: (b -> a -> b) -> b -> [a] -> b", + " function foldl(f, a, xs) {", + " return xs.reduce(f, a);", + " };", + "", + " // foldr (a -> b -> b) -> b -> [a] -> b", + " function foldr(f, a, xs) {", + " return xs.reduceRight(f, a);", + " };", + "", + " // map :: (a -> b) -> [a] -> [b]", + " function map(f, xs) {", + " return xs.map(f);", + " };", + "", + " // min :: Ord a => a -> a -> a", + " function min(a, b) {", + " return b < a ? b : a;", + " };", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " function zipWith(f, xs, ys) {", + " return Array.from({", + " length: min(xs.length, ys.length)", + " }, function (_, i) {", + " return f(xs[i], ys[i]);", + " });", + " };", + "", + " // TEST and FORMAT --------------------------------------------------------", + " var lstTriangle = pascal(n);", + "", + " // [[a]] -> bool -> s -> s", + " function wikiTable(lstRows, blnHeaderRow, strStyle) {", + " return '{| class=\"wikitable\" ' + (strStyle ? 'style=\"' + strStyle +", + " '\"' : '') + lstRows.map(function (lstRow, iRow) {", + " var strDelim = blnHeaderRow && !iRow ? '!' : '|';", + " return '\\n|-\\n' + strDelim + ' ' + lstRow.map(function (v) {", + " return typeof v === 'undefined' ? ' ' : v;", + " })", + " .join(' ' + strDelim + strDelim + ' ');", + " })", + " .join('') + '\\n|}';", + " }", + "", + " var lstLastLine = lstTriangle.slice(-1)[0],", + " lngBase = lstLastLine.length * 2 - 1,", + " nWidth = lstLastLine.reduce(function (a, x) {", + " var d = x.toString()", + " .length;", + " return d > a ? d : a;", + " }, 1) * lngBase;", + "", + " return [wikiTable(lstTriangle.map(function (lst) {", + " return lst.join(';;')", + " .split(';');", + " })", + " .map(function (line, i) {", + " var lstPad = Array((lngBase - line.length) / 2);", + " return lstPad.concat(line)", + " .concat(lstPad);", + " }), false, 'text-align:center;width:' + nWidth + 'em;height:' + nWidth +", + " 'em;table-layout:fixed;'), JSON.stringify(lstTriangle)].join('\\n\\n');", + "})(7);", + "{{Out}}", + "{| class=\"wikitable\" style=\"text-align:center;width:26em;height:26em;table-layout:fixed;\"", + "|-", + "| || || || || || || 1 || || || || || || ", + "|-", + "| || || || || || 1 || || 1 || || || || || ", + "|-", + "| || || || || 1 || || 2 || || 1 || || || || ", + "|-", + "| || || || 1 || || 3 || || 3 || || 1 || || || ", + "|-", + "| || || 1 || || 4 || || 6 || || 4 || || 1 || || ", + "|-", + "| || 1 || || 5 || || 10 || || 10 || || 5 || || 1 || ", + "|-", + "| 1 || || 6 || || 15 || || 20 || || 15 || || 6 || || 1", + "|}", + "", + "[[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1],[1,5,10,10,5,1],[1,6,15,20,15,6,1]]", + "", + "===ES6===", + "(() => {", + " 'use strict';", + "", + " // PASCAL'S TRIANGLE ------------------------------------------------------", + "", + " // pascal :: Int -> [[Int]]", + " const pascal = n =>", + " foldl(a => {", + " const xs = a.slice(-1)[0]; // Previous row", + " return append(a, [", + " zipWith(", + " (a, b) => a + b,", + " append([0], xs),", + " append(xs, [0])", + " )", + " ]);", + " }, [", + " [1] // Initial seed row", + " ], enumFromTo(1, n - 1));", + "", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // (++) :: [a] -> [a] -> [a]", + " const append = (xs, ys) => xs.concat(ys);", + "", + " // enumFromTo :: Int -> Int -> [Int]", + " const enumFromTo = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // foldl :: (b -> a -> b) -> b -> [a] -> b", + " const foldl = (f, a, xs) => xs.reduce(f, a);", + "", + " // foldr (a -> b -> b) -> b -> [a] -> b", + " const foldr = (f, a, xs) => xs.reduceRight(f, a);", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = (f, xs) => xs.map(f);", + "", + " // min :: Ord a => a -> a -> a", + " const min = (a, b) => b < a ? b : a;", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " const zipWith = (f, xs, ys) =>", + " Array.from({", + " length: min(xs.length, ys.length)", + " }, (_, i) => f(xs[i], ys[i]));", + "", + " // TEST -------------------------------------------------------------------", + " return foldr((a, x) => {", + " const strIndent = a.indent;", + " return {", + " rows: strIndent + map(n => (' ' + n)", + " .slice(-4), x)", + " .join('') + '\\n' + a.rows,", + " indent: strIndent + ' '", + " };", + " }, {", + " rows: '',", + " indent: ''", + " }, pascal(7))", + " .rows;", + "})();", + "{{Out}}", + "
                   1",
    +        "             1   1",
    +        "           1   2   1",
    +        "         1   3   3   1",
    +        "       1   4   6   4   1",
    +        "     1   5  10  10   5   1",
    +        "   1   6  15  20  15   6   1",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f5f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// Pascal's triangle object\nfunction pascalTriangle (rows) {\n\n\t// Number of rows the triangle contains\n\tthis.rows = rows;\n\n\t// The 2D array holding the rows of the triangle\n\tthis.triangle = new Array();\n\tfor (var r = 0; r < rows; r++) {\n\t\tthis.triangle[r] = new Array();\n\t\tfor (var i = 0; i <= r; i++) {\n\t\t\tif (i == 0 || i == r)\n\t\t\t\tthis.triangle[r][i] = 1;\n\t\t\telse\n\t\t\t\tthis.triangle[r][i] = this.triangle[r-1][i-1]+this.triangle[r-1][i];\n\t\t}\n\t}\n\n\t// Method to print the triangle\n\tthis.print = function(base) {\n\t\tif (!base)\n\t\t\tbase = 10;\n\n\t\t// Private method to calculate digits in number\n\t\tvar digits = function(n,b) {\n\t\t\tvar d = 0;\n\t\t\twhile (n >= 1) {\n\t\t\t\td++;\n\t\t\t\tn /= b;\n\t\t\t}\n\t\t\treturn d;\n\t\t}\n\n\t\t// Calculate max spaces needed\n\t\tvar spacing = digits(this.triangle[this.rows-1][Math.round(this.rows/2)],base);\n\n\t\t// Private method to add spacing between numbers\n\t\tvar insertSpaces = function(s) {\n\t\t\tvar buf = \"\";\n\t\t\twhile (s > 0) {\n\t\t\t\ts--;\n\t\t\t\tbuf += \" \";\n\t\t\t}\n\t\t\treturn buf;\n\t\t}\n\n\t\t// Print the triangle line by line\n\t\tfor (var r = 0; r < this.triangle.length; r++) {\n\t\t\tvar l = \"\";\n\t\t\tfor (var s = 0; s < Math.round(this.rows-1-r); s++) {\n\t\t\t\tl += insertSpaces(spacing);\n\t\t\t}\n\t\t\tfor (var i = 0; i < this.triangle[r].length; i++) {\n\t\t\t\tif (i != 0)\n\t\t\t\t\tl += insertSpaces(spacing-Math.ceil(digits(this.triangle[r][i],base)/2));\n\t\t\t\tl += this.triangle[r][i].toString(base);\n\t\t\t\tif (i < this.triangle[r].length-1)\n\t\t\t\t\tl += insertSpaces(spacing-Math.floor(digits(this.triangle[r][i],base)/2));\n\t\t\t}\n\t\t\tprint(l);\n\t\t}\n\t}\n\n}\n\n// Display 4 row triangle in base 10\nvar tri = new pascalTriangle(4);\ntri.print();\n// Display 8 row triangle in base 16\ntri = new pascalTriangle(8);\ntri.print(16);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Pathological floating point problems", + "type": "Waypoint", + "description": [ + "

    Most programmers are familiar with the inexactness of floating point calculations in a binary processor.

    The classic example being:

    ", + "
    ",
    +        "0.1 + 0.2 =  0.30000000000000004",
    +        "

    In many situations the amount of error in such calculations is very small and can be overlooked or eliminated with rounding.

    There are pathological problems however, where seemingly simple, straight-forward calculations are extremely sensitive to even tiny amounts of imprecision.

    This task's purpose is to show how your language deals with such classes of problems.

    ", + "

    A sequence that seems to converge to a wrong limit.

    Consider the sequence:

    ", + "

    ::::: v1 = 2

    ", + "

    ::::: v2 = -4

    ", + "

    ::::: vn = 111 - 1130 / vn-1 + 3000 / (vn-1 * vn-2)

    ", + "

    As n grows larger, the series should converge to 6 but small amounts of error will cause it to approach 100.

    ", + "Task 1:", + "

    Display the values of the sequence where n = 3, 4, 5, 6, 7, 8, 20, 30, 50 & 100 to at least 16 decimal places.

    ", + "
    ",
    +        "    n = 3     18.5",
    +        "    n = 4      9.378378",
    +        "    n = 5      7.801153",
    +        "    n = 6      7.154414",
    +        "    n = 7      6.806785",
    +        "    n = 8      6.5926328",
    +        "    n = 20     6.0435521101892689",
    +        "    n = 30     6.006786093031205758530554",
    +        "    n = 50     6.0001758466271871889456140207471954695237",
    +        "    n = 100    6.000000019319477929104086803403585715024350675436952458072592750856521767230266",
    +        "
    ", + "Task 2:", + "

    The Chaotic Bank Society is offering a new investment account to their customers.

    You first deposit $e - 1 where e is 2.7182818... the base of natural logarithms.

    After each year, your account balance will be multiplied by the number of years that have passed, and $1 in service charges will be removed.

    So ...

    ", + "

    :* after 1 year, your balance will be multiplied by 1 and $1 will be removed for service charges.

    ", + "

    :* after 2 years your balance will be doubled and $1 removed.

    ", + "

    :* after 3 years your balance will be tripled and $1 removed.

    ", + "

    :* ...

    ", + "

    :* after 10 years, multiplied by 10 and $1 removed, and so on.

    ", + "

    What will your balance be after 25 years?

    ", + "

    Starting balance: $e-1

    ", + "

    Balance = (Balance * year) - 1 for 25 years

    ", + "

    Balance after 25 years: $0.0399387296732302

    ", + "Task 3, extra credit:", + "

    Siegfried Rump's example. Consider the following function, designed by Siegfried Rump in 1988.

    ", + "

    ::::: f(a,b) = 333.75b6 + a2( 11a2b2 - b6 - 121b4 - 2 ) + 5.5b8 + a/(2b)

    ", + "

    ::::: compute f(a,b) where a=77617.0 and b=33096.0

    ", + "

    ::::: f(77617.0, 33096.0) = -0.827396059946821

    ", + "

    Demonstrate how to solve at least one of the first two problems, or both, and the third if you're feeling particularly jaunty.

    ", + "See also;", + " Floating-Point Arithmetic Section 1.3.2 Difficult problems." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f61", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Pattern matching", + "type": "Waypoint", + "description": [ + "

    Some languages offer direct support for algebraic data types and pattern matching on them. While this of course can always be simulated with manual tagging and conditionals, it allows for terse code which is easy to read, and can represent the algorithm directly.

    As an example, implement insertion in a red-black-tree. A red-black-tree is a binary tree where each internal node has a color attribute red or black. Moreover, no red node can have a red child, and every path from the root to an empty node must contain the same number of black nodes. As a consequence, the tree is balanced, and must be re-balanced after an insertion.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f62", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Penney's game", + "type": "Waypoint", + "description": [ + "

    Penney's game is a game where two players bet on being the first to see a particular sequence of heads or tails in consecutive tosses of a fair coin.

    It is common to agree on a sequence length of three then one player will openly choose a sequence, for example:

    ", + "

    Heads, Tails, Heads, or HTH for short.

    ", + "

    The other player on seeing the first players choice will choose his sequence. The coin is tossed and the first player to see his sequence in the sequence of coin tosses wins.

    ", + "Example:", + "

    One player might choose the sequence HHT and the other THT.

    Successive coin tosses of HTTHT gives the win to the second player as the last three coin tosses are his sequence.

    ", + "Task", + "

    Create a program that tosses the coin, keeps score and plays Penney's game against a human opponent.

    ", + "Who chooses and shows their sequence of three should be chosen randomly.", + "If going first, the computer should randomly choose its sequence of three.", + "If going second, the computer should automatically play the optimum sequence.", + "Successive coin tosses should be shown.", + "

    Show output of a game where the computer chooses first and a game where the user goes first here on this page.

    ", + "See also", + "The Penney Ante Part 1 (Video).", + "The Penney Ante Part 2 (Video)." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f63", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Pentagram", + "type": "Waypoint", + "description": [ + "

    A pentagram is a star polygon, consisting of a central pentagon of which each side forms the base of an isosceles triangle. The vertex of each triangle, a point of the star, is 36 degrees.

    ", + "Task:", + "

    Draw (or print) a regular pentagram, in any orientation. Use a different color (or token) for stroke and fill, and background. For the fill it should be assumed that all points inside the triangles and the pentagon are inside the pentagram.

    ", + "See also", + "Angle sum of a pentagram" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f64", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Percolation/Bond percolation", + "type": "Waypoint", + "description": [ + "

    Given an $M \\times N$ rectangular array of cells numbered $\\mathrm{cell}[0..M-1, 0..N-1]$, assume $M$ is horizontal and $N$ is downwards. Each $\\mathrm{cell}[m, n]$ is bounded by (horizontal) walls $\\mathrm{hwall}[m, n]$ and $\\mathrm{hwall}[m+1, n]$; (vertical) walls $\\mathrm{vwall}[m, n]$ and $\\mathrm{vwall}[m, n+1]$

    Assume that the probability of any wall being present is a constant $p$ where

    ", + "

    $0.0 \\le p \\le 1.0$

    ", + "

    Except for the outer horizontal walls at $m = 0$ and $m = M$ which are always present.

    The task:", + "

    Simulate pouring a fluid onto the top surface ($n = 0$) where the fluid will enter any empty cell it is adjacent to if there is no wall between where it currently is and the cell on the other side of the (missing) wall.

    The fluid does not move beyond the horizontal constraints of the grid.

    The fluid may move “up” within the confines of the grid of cells. If the fluid reaches a bottom cell that has a missing bottom wall then the fluid can be said to 'drip' out the bottom at that point.

    Given $p$ repeat the percolation $t$ times to estimate the proportion of times that the fluid can percolate to the bottom for any given $p$.

    Show how the probability of percolating through the random grid changes with $p$ going from $0.0$ to $1.0$ in $0.1$ increments and with the number of repetitions to estimate the fraction at any given $p$ as $t = 100$.

    Use an $M=10, N=10$ grid of cells for all cases.

    Optionally depict fluid successfully percolating through a grid graphically.

    Show all output on this page.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f66", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Percolation/Mean cluster density", + "type": "Waypoint", + "description": [ + "

    Let $c$ be a 2D boolean square matrix of $n \\times n$ values of either 1 or 0 where the

    ", + "

    probability of any value being 1 is $p$, (and of 0 is therefore $1-p$).

    ", + "

    We define a cluster of 1's as being a group of 1's connected vertically or

    ", + "

    horizontally (i.e., using the Von Neumann neighborhood rule) and bounded by either $0$ or by the limits of the matrix.

    ", + "

    Let the number of such clusters in such a randomly constructed matrix be $C_n$.

    Percolation theory states that $K(p)$ (the mean cluster density) will satisfy $K(p) = C_n / n^2$ as $n$ tends to infinity. For $p = 0.5$, $K(p)$ is found numerically to approximate $0.065770$...

    Task

    Show the effect of varying $n$ on the accuracy of simulated $K(p)$ for $p = 0.5$ and

    ", + "

    for values of $n$ up to at least $1000$.

    ", + "

    Any calculation of $C_n$ for finite $n$ is subject to randomness, so an approximation should be

    ", + "

    computed as the average of $t$ runs, where $t$ ≥ $5$.

    For extra credit, graphically show clusters in a $15\\times 15$, $p=0.5$ grid.

    Show your output here.

    See also", + "s-Cluster on Wolfram mathworld." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f67", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Percolation/Mean run density", + "type": "Waypoint", + "description": [ + "

    Let $v$ be a vector of $n$ values of either 1 or 0 where the probability of any

    ", + "

    value being 1 is $p$; the probability of a value being 0 is therefore $1-p$.

    ", + "

    Define a run of 1s as being a group of consecutive 1s in the vector bounded

    ", + "

    either by the limits of the vector or by a 0. Let the number of such runs in a given

    ", + "

    vector of length $n$ be $R_n$.

    For example, the following vector has $R_{10} = 3$

    ", + "
    ",
    +        "[1 1 0 0 0 1 0 1 1 1]",
    +        " ^^^       ^   ^^^^^",
    +        "
    ", + "

    Percolation theory states that

    $K(p) = \\lim_{n\\to\\infty} R_n / n = p(1 - p)$

    Task

    Any calculation of $R_n / n$ for finite $n$ is subject to randomness so should be

    ", + "

    computed as the average of $t$ runs, where $t \\ge 100$.

    For values of $p$ of 0.1, 0.3, 0.5, 0.7, and 0.9, show the effect of varying $n$

    ", + "

    on the accuracy of simulated $K(p)$.

    Show your output here.

    See also", + "s-Run on Wolfram mathworld." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f68", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Percolation/Site percolation", + "type": "Waypoint", + "description": [ + "

    Given an $M \\times N$ rectangular array of cells numbered $\\mathrm{cell}[0..M-1, 0..N-1]$assume $M$ is horizontal and $N$ is downwards.

    Assume that the probability of any cell being filled is a constant $p$ where

    ", + "

    $0.0 \\le p \\le 1.0$

    The task:", + "

    Simulate creating the array of cells with probability $p$ and then

    ", + "

    testing if there is a route through adjacent filled cells from any on row $0$ to any on row $N$, i.e. testing for site percolation.

    Given $p$ repeat the percolation $t$ times to estimate the proportion of times that the fluid can percolate to the bottom for any given $p$.

    Show how the probability of percolating through the random grid changes with $p$ going from $0.0$ to $1.0$ in $0.1$ increments and with the number of repetitions to estimate the fraction at any given $p$ as $t >= 100$.

    Use an $M=15, N=15$ grid of cells for all cases.

    Optionally depict a percolation through a cell grid graphically.

    Show all output on this page.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f69", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Perfect numbers", + "type": "Waypoint", + "description": [ + "

    Write a function which says whether a number is perfect.

    ", + "

    A perfect number is a positive integer that is the sum of its proper positive divisors excluding the number itself.

    Equivalently, a perfect number is a number that is half the sum of all of its positive divisors (including itself).

    ", + "

    Note: The faster Lucas-Lehmer test is used to find primes of the form 2n-1, all known perfect numbers can be derived from these primes

    ", + "

    using the formula (2n - 1) × 2n - 1.

    It is not known if there are any odd perfect numbers (any that exist are larger than 102000).

    ", + "See also:", + "Rational Arithmetic", + "Perfect numbers on OEIS", + "Odd Perfect showing the current status of bounds on odd perfect numbers." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Imperative===", + "", + "{{trans|Java}}", + "function is_perfect(n)", + "{", + " var sum = 1, i, sqrt=Math.floor(Math.sqrt(n));", + " for (i = sqrt-1; i>1; i--)", + " {", + " if (n % i == 0) {", + " sum += i + n/i;", + " }", + " }", + " if(n % sqrt == 0)", + " sum += sqrt + (sqrt*sqrt == n ? 0 : n/sqrt);", + " return sum === n;", + "}", + "", + "", + "var i;", + "for (i = 1; i < 10000; i++)", + "{", + " if (is_perfect(i))", + " print(i);", + "}", + "", + "{{Out}}", + "
    6",
    +        "28",
    +        "496",
    +        "8128
    ", + "", + "===Functional===", + "", + "====ES5====", + "", + "Naive version (brute force)", + "", + "(function (nFrom, nTo) {", + "", + " function perfect(n) {", + " return n === range(1, n - 1).reduce(", + " function (a, x) {", + " return n % x ? a : a + x;", + " }, 0", + " );", + " }", + "", + " function range(m, n) {", + " return Array.apply(null, Array(n - m + 1)).map(function (x, i) {", + " return m + i;", + " });", + " }", + "", + " return range(nFrom, nTo).filter(perfect);", + "", + "})(1, 10000);", + "", + "Output:", + "", + "[6, 28, 496, 8128]", + "", + "Much faster (more efficient factorisation)", + "", + "(function (nFrom, nTo) {", + "", + " function perfect(n) {", + " var lows = range(1, Math.floor(Math.sqrt(n))).filter(function (x) {", + " return (n % x) === 0;", + " });", + "", + " return n > 1 && lows.concat(lows.map(function (x) {", + " return n / x;", + " })).reduce(function (a, x) {", + " return a + x;", + " }, 0) / 2 === n;", + " }", + "", + " function range(m, n) {", + " return Array.apply(null, Array(n - m + 1)).map(function (x, i) {", + " return m + i;", + " });", + " }", + "", + " return range(nFrom, nTo).filter(perfect)", + "", + "})(1, 10000);", + "", + "Output:", + "", + "[6, 28, 496, 8128]", + "", + "Note that the filter function, though convenient and well optimised, is not strictly necessary.", + "We can always replace it with a more general monadic bind (chain) function, which is essentially just concat map", + "(Monadic return/inject for lists is simply lambda x --> [x], inlined here, and fail is [].)", + "", + "(function (nFrom, nTo) {", + "", + " // MONADIC CHAIN (bind) IN LIEU OF FILTER", + " // ( monadic return for lists is just lambda x -> [x] )", + "", + " return chain(", + " rng(nFrom, nTo),", + " ", + " function mPerfect(n) {", + " return (chain(", + " rng(1, Math.floor(Math.sqrt(n))),", + " function (y) {", + " return (n % y) === 0 && n > 1 ? [y, n / y] : [];", + " }", + " ).reduce(function (a, x) {", + " return a + x;", + " }, 0) / 2 === n) ? [n] : [];", + " }", + " ", + " );", + "", + " /******************************************************************/", + "", + " // Monadic bind (chain) for lists", + " function chain(xs, f) {", + " return [].concat.apply([], xs.map(f));", + " }", + "", + " function rng(m, n) {", + " return Array.apply(null, Array(n - m + 1)).map(function (x, i) {", + " return m + i;", + " });", + " }", + "", + "})(1, 10000);", + "", + "Output:", + "[6, 28, 496, 8128]", + "", + "", + "====ES6====", + "", + "((nFrom, nTo) => {", + "", + " // perfect :: Int -> Bool", + " let perfect = n => {", + " let lows = range(1, Math.floor(Math.sqrt(n)))", + " .filter(x => (n % x) === 0);", + "", + " return n > 1 && lows.concat(lows.map(x => n / x))", + " .reduce((a, x) => (a + x), 0) / 2 === n;", + " },", + "", + " // range :: Int -> Int -> Maybe Int -> [Int]", + " range = (m, n, step) => {", + " let d = (step || 1) * (n >= m ? 1 : -1);", + "", + " return Array.from({", + " length: Math.floor((n - m) / d) + 1", + " }, (_, i) => m + (i * d));", + " };", + "", + " return range(nFrom, nTo)", + " .filter(perfect);", + "", + "})(1, 10000);", + "", + "{{Out}}", + "[6, 28, 496, 8128]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f6a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function is_perfect(n)\n{\n var sum = 1, i, sqrt=Math.floor(Math.sqrt(n));\n for (i = sqrt-1; i>1; i--)\n {\n if (n % i == 0) {\n sum += i + n/i;\n }\n }\n if(n % sqrt == 0)\n sum += sqrt + (sqrt*sqrt == n ? 0 : n/sqrt);\n return sum === n;\n}\n\n\nvar i;\nfor (i = 1; i < 10000; i++)\n{\n if (is_perfect(i))\n print(i);\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Perfect shuffle", + "type": "Waypoint", + "description": [ + "

    A perfect shuffle (or faro/weave shuffle) means splitting a deck of cards into equal halves, and perfectly interleaving them - so that you end up with the first card from the left half, followed by the first card from the right half, and so on:

    ", + "7♠ 8♠ 9♠ J♠ Q♠ K♠7♠ 8♠ 9♠J♠ Q♠ K♠7♠ J♠ 8♠ Q♠ 9♠ K♠", + "

    When you repeatedly perform perfect shuffles on an even-sized deck of unique cards, it will at some point arrive back at its original order. How many shuffles this takes, depends solely on the number of cards in the deck - for example for a deck of eight cards it takes three shuffles:

    ", + "

    {| style=\"border-spacing:0.5em 0;border-collapse:separate;margin:0 1em;text-align:right\"

    ", + "

    |-

    ", + "

    | original: ||

    ", + "

    1

    ", + "

    2

    ", + "

    3

    ", + "

    4

    ", + "

    5

    ", + "

    6

    ", + "

    7

    ", + "

    8

    ", + "

    |-

    ", + "

    | after 1st shuffle: ||

    ", + "

    1

    ", + "

    5

    ", + "

    2

    ", + "

    6

    ", + "

    3

    ", + "

    7

    ", + "

    4

    ", + "

    8

    ", + "

    |-

    ", + "

    | after 2nd shuffle: ||

    ", + "

    1

    ", + "

    3

    ", + "

    5

    ", + "

    7

    ", + "

    2

    ", + "

    4

    ", + "

    6

    ", + "

    8

    ", + "

    |-

    ", + "

    | after 3rd shuffle: ||

    ", + "

    1

    ", + "

    2

    ", + "

    3

    ", + "

    4

    ", + "

    5

    ", + "

    6

    ", + "

    7

    ", + "

    8

    ", + "

    |}

    ", + "

    The Task

    Write a function that can perform a perfect shuffle on an even-sized list of values.", + "Call this function repeatedly to count how many shuffles are needed to get a deck back to its original order, for each of the deck sizes listed under \"Test Cases\" below.", + "* You can use a list of numbers (or anything else that's convenient) to represent a deck; just make sure that all \"cards\" are unique within each deck.", + "* Print out the resulting shuffle counts, to demonstrate that your program passes the test-cases.", + "

    Test Cases

    {|

    ", + "

    |-

    ", + "

    ! input (deck size) !! output (number of shuffles required)

    ", + "

    |-

    ", + "

    | 8 || 3

    ", + "

    |-

    ", + "

    | 24 || 11

    ", + "

    |-

    ", + "

    | 52 || 8

    ", + "

    |-

    ", + "

    | 100 || 30

    ", + "

    |-

    ", + "

    | 1020 || 1018

    ", + "

    |-

    ", + "

    | 1024 || 10

    ", + "

    |-

    ", + "

    | 10000 || 300

    ", + "

    |}

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES6===", + "(() => {", + " 'use strict';", + "", + " // shuffleCycleLength :: Int -> Int", + " const shuffleCycleLength = deckSize =>", + " firstCycle(shuffle, range(1, deckSize))", + " .all.length;", + "", + " // shuffle :: [a] -> [a]", + " const shuffle = xs =>", + " concat(zip.apply(null, splitAt(div(length(xs), 2), xs)));", + "", + " // firstycle :: Eq a => (a -> a) -> a -> [a]", + " const firstCycle = (f, x) =>", + " until(", + " m => EqArray(x, m.current),", + " m => {", + " const fx = f(m.current);", + " return {", + " current: fx,", + " all: m.all.concat([fx])", + " };", + " }, {", + " current: f(x),", + " all: [x]", + " }", + " );", + "", + " // Two arrays equal ?", + " // EqArray :: [a] -> [b] -> Bool", + " const EqArray = (xs, ys) => {", + " const [nx, ny] = [xs.length, ys.length];", + " return nx === ny ? (", + " nx > 0 ? (", + " xs[0] === ys[0] && EqArray(xs.slice(1), ys.slice(1))", + " ) : true", + " ) : false;", + " };", + "", + " // GENERIC FUNCTIONS", + "", + " // zip :: [a] -> [b] -> [(a,b)]", + " const zip = (xs, ys) =>", + " xs.slice(0, Math.min(xs.length, ys.length))", + " .map((x, i) => [x, ys[i]]);", + "", + " // concat :: [[a]] -> [a]", + " const concat = xs => [].concat.apply([], xs);", + "", + " // splitAt :: Int -> [a] -> ([a],[a])", + " const splitAt = (n, xs) => [xs.slice(0, n), xs.slice(n)];", + "", + " // div :: Num -> Num -> Int", + " const div = (x, y) => Math.floor(x / y);", + "", + " // until :: (a -> Bool) -> (a -> a) -> a -> a", + " const until = (p, f, x) => {", + " const go = x => p(x) ? x : go(f(x));", + " return go(x);", + " }", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // length :: [a] -> Int", + " // length :: Text -> Int", + " const length = xs => xs.length;", + "", + " // maximumBy :: (a -> a -> Ordering) -> [a] -> a", + " const maximumBy = (f, xs) =>", + " xs.reduce((a, x) => a === undefined ? x : (", + " f(x, a) > 0 ? x : a", + " ), undefined);", + "", + " // transpose :: [[a]] -> [[a]]", + " const transpose = xs =>", + " xs[0].map((_, iCol) => xs.map((row) => row[iCol]));", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x, null, 2);", + "", + " // replicateS :: Int -> String -> String", + " const replicateS = (n, s) => {", + " let v = s,", + " o = '';", + " if (n < 1) return o;", + " while (n > 1) {", + " if (n & 1) o = o.concat(v);", + " n >>= 1;", + " v = v.concat(v);", + " }", + " return o.concat(v);", + " };", + "", + " // justifyRight :: Int -> Char -> Text -> Text", + " const justifyRight = (n, cFiller, strText) =>", + " n > strText.length ? (", + " (replicateS(n, cFiller) + strText)", + " .slice(-n)", + " ) : strText;", + "", + " // TEST", + " return transpose(transpose([", + " ['Deck', 'Shuffles']", + " ].concat(", + " [8, 24, 52, 100, 1020, 1024, 10000]", + " .map(n => [n.toString(), shuffleCycleLength(n)", + " .toString()", + " ])))", + " .map(col => { // Right-justified number columns", + " const width = length(", + " maximumBy((a, b) => length(a) - length(b), col)", + " ) + 2;", + "", + " return col.map(x => justifyRight(width, ' ', x));", + " }))", + " .map(row => row.join(''))", + " .join('\\n');", + "})();", + "", + "{{Out}}", + "
       Deck  Shuffles",
    +        "      8         3",
    +        "     24        11",
    +        "     52         8",
    +        "    100        30",
    +        "   1020      1018",
    +        "   1024        10",
    +        "  10000       300
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f6b", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n 'use strict';\n\n // shuffleCycleLength :: Int -> Int\n const shuffleCycleLength = deckSize =>\n firstCycle(shuffle, range(1, deckSize))\n .all.length;\n\n // shuffle :: [a] -> [a]\n const shuffle = xs =>\n concat(zip.apply(null, splitAt(div(length(xs), 2), xs)));\n\n // firstycle :: Eq a => (a -> a) -> a -> [a]\n const firstCycle = (f, x) =>\n until(\n m => EqArray(x, m.current),\n m => {\n const fx = f(m.current);\n return {\n current: fx,\n all: m.all.concat([fx])\n };\n }, {\n current: f(x),\n all: [x]\n }\n );\n\n // Two arrays equal ?\n // EqArray :: [a] -> [b] -> Bool\n const EqArray = (xs, ys) => {\n const [nx, ny] = [xs.length, ys.length];\n return nx === ny ? (\n nx > 0 ? (\n xs[0] === ys[0] && EqArray(xs.slice(1), ys.slice(1))\n ) : true\n ) : false;\n };\n\n // GENERIC FUNCTIONS\n\n // zip :: [a] -> [b] -> [(a,b)]\n const zip = (xs, ys) =>\n xs.slice(0, Math.min(xs.length, ys.length))\n .map((x, i) => [x, ys[i]]);\n\n // concat :: [[a]] -> [a]\n const concat = xs => [].concat.apply([], xs);\n\n // splitAt :: Int -> [a] -> ([a],[a])\n const splitAt = (n, xs) => [xs.slice(0, n), xs.slice(n)];\n\n // div :: Num -> Num -> Int\n const div = (x, y) => Math.floor(x / y);\n\n // until :: (a -> Bool) -> (a -> a) -> a -> a\n const until = (p, f, x) => {\n const go = x => p(x) ? x : go(f(x));\n return go(x);\n }\n\n // range :: Int -> Int -> [Int]\n const range = (m, n) =>\n Array.from({\n length: Math.floor(n - m) + 1\n }, (_, i) => m + i);\n\n // length :: [a] -> Int\n // length :: Text -> Int\n const length = xs => xs.length;\n\n // maximumBy :: (a -> a -> Ordering) -> [a] -> a\n const maximumBy = (f, xs) =>\n xs.reduce((a, x) => a === undefined ? x : (\n f(x, a) > 0 ? x : a\n ), undefined);\n\n // transpose :: [[a]] -> [[a]]\n const transpose = xs =>\n xs[0].map((_, iCol) => xs.map((row) => row[iCol]));\n\n // show :: a -> String\n const show = x => JSON.stringify(x, null, 2);\n\n // replicateS :: Int -> String -> String\n const replicateS = (n, s) => {\n let v = s,\n o = '';\n if (n < 1) return o;\n while (n > 1) {\n if (n & 1) o = o.concat(v);\n n >>= 1;\n v = v.concat(v);\n }\n return o.concat(v);\n };\n\n // justifyRight :: Int -> Char -> Text -> Text\n const justifyRight = (n, cFiller, strText) =>\n n > strText.length ? (\n (replicateS(n, cFiller) + strText)\n .slice(-n)\n ) : strText;\n\n // TEST\n return transpose(transpose([\n ['Deck', 'Shuffles']\n ].concat(\n [8, 24, 52, 100, 1020, 1024, 10000]\n .map(n => [n.toString(), shuffleCycleLength(n)\n .toString()\n ])))\n .map(col => { // Right-justified number columns\n const width = length(\n maximumBy((a, b) => length(a) - length(b), col)\n ) + 2;\n\n return col.map(x => justifyRight(width, ' ', x));\n }))\n .map(row => row.join(''))\n .join('\\n');\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Permutations by swapping", + "type": "Waypoint", + "description": [ + "Task:", + "

    Generate permutations of n items in which successive permutations differ from each other by the swapping of any two items.

    Also generate the sign of the permutation which is +1 when the permutation is generated from an even number of swaps from the initial state, and -1 for odd.

    Show the permutations and signs of three items, in order of generation here.

    Such data are of use in generating the determinant of a square matrix and any functions created should bear this in mind.

    Note: The Steinhaus–Johnson–Trotter algorithm generates successive permutations where adjacent items are swapped, but from this discussion adjacency is not a requirement.

    ", + "References:", + "Steinhaus–Johnson–Trotter algorithm", + "Johnson-Trotter Algorithm Listing All Permutations", + "Correction to Heap's algorithm as presented in Wikipedia and widely distributed.", + "[http://www.gutenberg.org/files/18567/18567-h/18567-h.htm#ch7] TintinnalogiaRelated task:", + " Matrix arithmetic", + " Gray code" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f6c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Permutations/Derangements", + "type": "Waypoint", + "description": [ + "

    A derangement is a permutation of the order of distinct items in which no item appears in its original place.

    For example, the only two derangements of the three items (0, 1, 2) are (1, 2, 0), and (2, 0, 1).

    The number of derangements of n distinct items is known as the subfactorial of n, sometimes written as !n.

    ", + "

    There are various ways to calculate !n.

    ", + "Task:", + "Create a named function/method/subroutine/... to generate derangements of the integers 0..n-1, (or 1..n if you prefer). ", + "Generate and show all the derangements of 4 integers using the above routine.", + "Create a function that calculates the subfactorial of n, !n.", + "Print and show a table of the counted number of derangements of n vs. the calculated !n for n from 0..9 inclusive.Optional stretch goal:", + " Calculate !20 Related tasks:", + " Anagrams/Deranged anagrams", + " Best shuffle", + " Left_factorials" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f6d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Permutations/Rank of a permutation", + "type": "Waypoint", + "description": [ + "

    A particular ranking of a permutation associates an integer with a particular ordering of all the permutations of a set of distinct items.

    ", + "

    For our purposes the ranking will assign integers $0 .. (n! - 1)$ to an ordering of all the permutations of the integers $0 .. (n - 1)$.

    For example, the permutations of the digits zero to 3 arranged lexicographically have the following rank:

      PERMUTATION      RANK",
    +        "  (0, 1, 2, 3) ->  0",
    +        "  (0, 1, 3, 2) ->  1",
    +        "  (0, 2, 1, 3) ->  2",
    +        "  (0, 2, 3, 1) ->  3",
    +        "  (0, 3, 1, 2) ->  4",
    +        "  (0, 3, 2, 1) ->  5",
    +        "  (1, 0, 2, 3) ->  6",
    +        "  (1, 0, 3, 2) ->  7",
    +        "  (1, 2, 0, 3) ->  8",
    +        "  (1, 2, 3, 0) ->  9",
    +        "  (1, 3, 0, 2) -> 10",
    +        "  (1, 3, 2, 0) -> 11",
    +        "  (2, 0, 1, 3) -> 12",
    +        "  (2, 0, 3, 1) -> 13",
    +        "  (2, 1, 0, 3) -> 14",
    +        "  (2, 1, 3, 0) -> 15",
    +        "  (2, 3, 0, 1) -> 16",
    +        "  (2, 3, 1, 0) -> 17",
    +        "  (3, 0, 1, 2) -> 18",
    +        "  (3, 0, 2, 1) -> 19",
    +        "  (3, 1, 0, 2) -> 20",
    +        "  (3, 1, 2, 0) -> 21",
    +        "  (3, 2, 0, 1) -> 22",
    +        "  (3, 2, 1, 0) -> 23

    Algorithms exist that can generate a rank from a permutation for some particular ordering of permutations, and that can generate the same rank from the given individual permutation (i.e. given a rank of 17 produce (2, 3, 1, 0) in the example above).

    One use of such algorithms could be in generating a small, random, sample of permutations of $n$ items without duplicates when the total number of permutations is large. Remember that the total number of permutations of $n$ items is given by $n!$ which grows large very quickly: A 32 bit integer can only hold $12!$, a 64 bit integer only $20!$. It becomes difficult to take the straight-forward approach of generating all permutations then taking a random sample of them.

    A question on the Stack Overflow site asked how to generate one million random and indivudual permutations of 144 items.

    ", + "Task:", + "Create a function to generate a permutation from a rank.", + "Create the inverse function that given the permutation generates its rank.", + "Show that for $n=3$ the two functions are indeed inverses of each other.", + "Compute and show here 4 random, individual, samples of permutations of 12 objects.Stretch goal:", + "State how reasonable it would be to use your program to address the limits of the Stack Overflow question.References:", + "Ranking and Unranking Permutations in Linear Time by Myrvold & Ruskey. (Also available via Google here).", + "Ranks on the DevData site.", + "Another answer on Stack Overflow to a different question that explains its algorithm in detail." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f6e", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Permutations", + "type": "Waypoint", + "description": [ + "Task:", + "

    Write a program that generates all permutations of n different objects. (Practically numerals!)

    ", + "Related tasks: ", + " Find the missing permutation", + " Permutations/Derangements" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "====Iteration====", + "", + "Copy the following as an HTML file and load in a browser.", + "Permutations", + "
    ",
    +        "
    ", + "", + "Alternatively: 'Genuine' js code, assuming no duplicate.", + "", + "", + "function perm(a) {", + " if (a.length < 2) return [a];", + " var c, d, b = [];", + " for (c = 0; c < a.length; c++) {", + " var e = a.splice(c, 1),", + " f = perm(a);", + " for (d = 0; d < f.length; d++) b.push([e].concat(f[d]));", + " a.splice(c, 0, e[0])", + " } return b", + "}", + "", + "console.log(perm(['Aardvarks', 'eat', 'ants']).join(\"\\n\"));", + "", + "", + "{{Out}}", + "Aardvarks,eat,ants", + "Aardvarks,ants,eat", + "eat,Aardvarks,ants", + "eat,ants,Aardvarks", + "ants,Aardvarks,eat", + "ants,eat,Aardvarks", + "", + "====Functional composition====", + "", + "{{trans|Haskell}}", + "", + "(Simple version – assuming a unique list of objects comparable by the JS === operator)", + "", + "(function () {", + " 'use strict';", + "", + " // permutations :: [a] -> [[a]]", + " var permutations = function (xs) {", + " return xs.length ? concatMap(function (x) {", + " return concatMap(function (ys) {", + " return [[x].concat(ys)];", + " }, permutations(delete_(x, xs)));", + " }, xs) : [[]];", + " };", + "", + " // GENERIC FUNCTIONS", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " var concatMap = function (f, xs) {", + " return [].concat.apply([], xs.map(f));", + " };", + "", + " // delete :: Eq a => a -> [a] -> [a]", + " var delete_ = function (x, xs) {", + " return deleteBy(function (a, b) {", + " return a === b;", + " }, x, xs);", + " };", + "", + " // deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]", + " var deleteBy = function (f, x, xs) {", + " return xs.length > 0 ? f(x, xs[0]) ? xs.slice(1) : ", + " [xs[0]].concat(deleteBy(f, x, xs.slice(1))) : [];", + " };", + "", + " // TEST", + " return permutations(['Aardvarks', 'eat', 'ants']);", + "})(); ", + "", + "{{Out}}", + "[[\"Aardvarks\", \"eat\", \"ants\"], [\"Aardvarks\", \"ants\", \"eat\"],", + " [\"eat\", \"Aardvarks\", \"ants\"], [\"eat\", \"ants\", \"Aardvarks\"], ", + "[\"ants\", \"Aardvarks\", \"eat\"], [\"ants\", \"eat\", \"Aardvarks\"]]", + "", + "===ES6===", + "", + "(() => {", + " 'use strict';", + "", + " // permutations :: [a] -> [[a]]", + " const permutations = xs =>", + " xs.length ? concatMap(x => concatMap(ys => [", + " [x].concat(ys)", + " ],", + " permutations(delete_(x, xs))), xs) : [", + " []", + " ];", + "", + " // GENERIC FUNCTIONS", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " const concatMap = (f, xs) => [].concat.apply([], xs.map(f));", + " //", + " // // delete :: Eq a => a -> [a] -> [a]", + " // const delete_ = (x, xs) =>", + " // deleteBy((a, b) => a === b, x, xs);", + "", + " // delete_ :: Eq a => a -> [a] -> [a]", + " const delete_ = (x, xs) =>", + " xs.length > 0 ? (", + " (x === xs[0]) ? (", + " xs.slice(1)", + " ) : [xs[0]].concat(delete_(x, xs.slice(1)))", + " ) : [];", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // TEST", + " return permutations(['Aardvarks', 'eat', 'ants']);", + "})();", + "", + "", + "{{Out}}", + "[[\"Aardvarks\", \"eat\", \"ants\"], [\"Aardvarks\", \"ants\", \"eat\"],", + " [\"eat\", \"Aardvarks\", \"ants\"], [\"eat\", \"ants\", \"Aardvarks\"], ", + "[\"ants\", \"Aardvarks\", \"eat\"], [\"ants\", \"eat\", \"Aardvarks\"]]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f6f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "Permutations\n
    \n\n"
    +      ],
    +      "betaTests": [
    +        "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');"
    +      ]
    +    },
    +    {
    +      "title": "Permutation test",
    +      "type": "Waypoint",
    +      "description": [
    +        "

    A new medical treatment was tested on a population of $n + m$

    ", + "

    volunteers, with each volunteer randomly assigned either to a group of

    ", + "

    $n$ treatment subjects, or to a group of $m$ control subjects.

    Members of the treatment group were given the treatment,

    ", + "

    and members of the control group were given a placebo.

    ", + "

    The effect of the treatment or placebo on each volunteer

    ", + "

    was measured and reported in this table.

    {| style=\"text-align: left; width: 50%;\" border=\"4\" cellpadding=\"2\" cellspacing=\"2\"

    ", + "

    |+ Table of experimental results

    ", + "

    |- style=\"background-color: rgb(255, 204, 255);\"

    ", + "

    ! Treatment group !! Control group

    ", + "

    |-

    ", + "

    | 85 || 68

    ", + "

    |-

    ", + "

    | 88 || 41

    ", + "

    |-

    ", + "

    | 75 || 10

    ", + "

    |-

    ", + "

    | 66 || 49

    ", + "

    |-

    ", + "

    | 25 || 16

    ", + "

    |-

    ", + "

    | 29 || 65

    ", + "

    |-

    ", + "

    | 83 || 32

    ", + "

    |-

    ", + "

    | 39 || 92

    ", + "

    |-

    ", + "

    | 97 || 28

    ", + "

    |-

    ", + "

    | || 98

    ", + "

    |}

    ", + "

    Write a program that performs a

    ", + "

    permutation test to judge

    ", + "

    whether the treatment had a significantly stronger effect than the

    ", + "

    placebo.

    Do this by considering every possible alternative assignment from the same pool of volunteers to a treatment group of size $n$ and a control group of size $m$ (i.e., the same group sizes used in the actual experiment but with the group members chosen differently), while assuming that each volunteer's effect remains constant regardless.", + "Note that the number of alternatives will be the binomial coefficient $\\tbinom{n+m}{n}$.", + "Compute the mean effect for each group and the difference in means between the groups in every case by subtracting the mean of the control group from the mean of the treatment group.", + "Report the percentage of alternative groupings for which the difference in means is less or equal to the actual experimentally observed difference in means, and the percentage for which it is greater.", + "Note that they should sum to 100%.", + "

    Extremely dissimilar values are evidence of an effect not entirely due

    ", + "

    to chance, but your program need not draw any conclusions.

    You may assume the experimental data are known at compile time if

    ", + "

    that's easier than loading them at run time. Test your solution on the

    ", + "

    data given above.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f70", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Pernicious numbers", + "type": "Waypoint", + "description": [ + "

    A pernicious number is a positive integer whose population count is a prime. The population count is the number of ones in the binary representation of a non-negative integer.

    ", + "Example", + "

    22 (which is 10110 in binary) has a population count of 3, which is prime, and therefore 22 is a pernicious number.

    ", + "Task", + "display the first 25 pernicious numbers.", + "display all pernicious numbers between 888,888,877 and 888,888,888 (inclusive).", + "display each list of integers on one line (which may or may not include a title).See also", + "Sequence A052294 pernicious numbers on The On-Line Encyclopedia of Integer Sequences.", + "Rosetta Code entry population count, evil numbers, odious numbers." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f71", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Phrase reversals", + "type": "Waypoint", + "description": [ + "Task:", + "

    Given a string of space separated words containing the following phrase:

    ", + "

    rosetta code phrase reversal

    # Reverse the string.

    ", + "

    # Reverse each individual word in the string, maintaining original string order.

    ", + "

    # Reverse the order of each word of the phrase, maintaining the order of characters in each word.

    ", + "

    Show your output here.

    ", + "See also: ", + "Reverse a string", + "Reverse words in a string" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "(function (p) {", + " return [", + " p.split('').reverse().join(''),", + "", + " p.split(' ').map(function (x) {", + " return x.split('').reverse().join('');", + " }).join(' '),", + "", + " p.split(' ').reverse().join(' ')", + "", + " ].join('\\n');", + "", + "})('rosetta code phrase reversal');", + "{{out}}", + "
    lasrever esarhp edoc attesor",
    +        "attesor edoc esarhp lasrever",
    +        "reversal phrase code rosetta
    ", + "", + "===ES6===", + "(() => {", + " 'use strict'", + "", + " // reverseString, reverseEachWord, reverseWordOrder :: String -> String", + " const", + " reverseString = s => reverse(s),", + "", + " reverseEachWord = s => wordLevel(map(reverse))(s),", + "", + " reverseWordOrder = s => wordLevel(reverse)(s);", + "", + " // wordLevel :: ([String] -> [String]) -> String -> String", + " const wordLevel = f =>", + " x => unwords(f(words(x)));", + "", + "", + " // GENERIC FUNCTIONS -----------------------------------------------------", + "", + " // A list of functions applied to a list of arguments", + " // <*> :: [(a -> b)] -> [a] -> [b]", + " const ap = (fs, xs) => //", + " [].concat.apply([], fs.map(f => //", + " [].concat.apply([], xs.map(x => [f(x)]))));", + "", + " // 2 or more arguments", + " // curry :: Function -> Function", + " const curry = (f, ...args) => {", + " const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :", + " function () {", + " return go(xs.concat(Array.from(arguments)));", + " };", + " return go([].slice.call(args, 1));", + " };", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = curry((f, xs) => xs.map(f));", + "", + " // reverse :: [a] -> [a]", + " const reverse = curry(xs =>", + " typeof xs === 'string' ? (", + " xs.split('')", + " .reverse()", + " .join('')", + " ) : xs.slice(0)", + " .reverse());", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + " // unwords :: [String] -> String", + " const unwords = xs => xs.join(' ');", + "", + " // words :: String -> [String]", + " const words = s => s.split(/\\s+/);", + "", + "", + " // TEST ------------------------------------------------------------------", + " return unlines(", + " ap([", + " reverseString,", + " reverseEachWord,", + " reverseWordOrder", + " ], [\"rosetta code phrase reversal\"])", + " );", + "})();", + "{{Out}}", + "
    lasrever esarhp edoc attesor",
    +        "attesor edoc esarhp lasrever",
    +        "reversal phrase code rosetta
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f72", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function (p) {\n return [\n p.split('').reverse().join(''),\n\n p.split(' ').map(function (x) {\n return x.split('').reverse().join('');\n }).join(' '),\n\n p.split(' ').reverse().join(' ')\n\n ].join('\\n');\n\n})('rosetta code phrase reversal');\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Polynomial long division", + "type": "Waypoint", + "description": [ + "

    In algebra, polynomial long division is an algorithm for dividing a polynomial by another polynomial of the same or lower degree.

    Let us suppose a polynomial is represented by a vector, $x$ (i.e., an ordered collection of coefficients) so that the $i$th element keeps the coefficient of $x^i$, and the multiplication by a monomial is a shift of the vector's elements \"towards right\" (injecting ones from left) followed by a multiplication of each element by the coefficient of the monomial.

    Then a pseudocode for the polynomial long division using the conventions described above could be:

    degree(P):

    ", + "

    return the index of the last non-zero element of P;

    ", + "

    if all elements are 0, return -∞

    polynomial_long_division(N, D) returns (q, r):

    ", + "

    // N, D, q, r are vectors

    ", + "

    if degree(D) < 0 then error

    ", + "

    q ← 0

    ", + "

    while degree(N) ≥ degree(D)

    ", + "

    d ← D shifted right by (degree(N) - degree(D))

    ", + "

    q(degree(N) - degree(D)) ← N(degree(N)) / d(degree(d))

    ", + "

    // by construction, degree(d) = degree(N) of course

    ", + "

    d ← d * q(degree(N) - degree(D))

    ", + "

    N ← N - d

    ", + "

    endwhile

    ", + "

    r ← N

    ", + "

    return (q, r)

    Note: vector * scalar multiplies each element of the vector by the scalar; vectorA - vectorB subtracts each element of the vectorB from the element of the vectorA with \"the same index\". The vectors in the pseudocode are zero-based.

    Error handling (for allocations or for wrong inputs) is not mandatory.", + "Conventions can be different; in particular, note that if the first coefficient in the vector is the highest power of x for the polynomial represented by the vector, then the algorithm becomes simpler.", + "

    Example for clarification

    ", + "

    This example is from Wikipedia, but changed to show how the given pseudocode works.

    0 1 2 3

    ", + "

    ----------------------

    ", + "

    N: -42 0 -12 1 degree = 3

    ", + "

    D: -3 1 0 0 degree = 1

    d(N) - d(D) = 2, so let's shift D towards right by 2:

    N: -42 0 -12 1

    ", + "

    d: 0 0 -3 1

    N(3)/d(3) = 1, so d is unchanged. Now remember that \"shifting by 2\"

    ", + "

    is like multiplying by x2, and the final multiplication

    ", + "

    (here by 1) is the coefficient of this monomial. Let's store this

    ", + "

    into q:

    ", + "

    0 1 2

    ", + "

    ---------------

    ", + "

    q: 0 0 1

    now compute N - d, and let it be the \"new\" N, and let's loop

    N: -42 0 -9 0 degree = 2

    ", + "

    D: -3 1 0 0 degree = 1

    d(N) - d(D) = 1, right shift D by 1 and let it be d

    N: -42 0 -9 0

    ", + "

    d: 0 -3 1 0 * -9/1 = -9

    q: 0 -9 1

    d: 0 27 -9 0

    N ← N - d

    N: -42 -27 0 0 degree = 1

    ", + "

    D: -3 1 0 0 degree = 1

    looping again... d(N)-d(D)=0, so no shift is needed; we

    ", + "

    multiply D by -27 (= -27/1) storing the result in d, then

    q: -27 -9 1

    and

    N: -42 -27 0 0 -

    ", + "

    d: 81 -27 0 0 =

    ", + "

    N: -123 0 0 0 (last N)

    d(N) < d(D), so now r ← N, and the result is:

    0 1 2

    ", + "

    -------------

    ", + "

    q: -27 -9 1 → x2 - 9x - 27

    ", + "

    r: -123 0 0 → -123

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f80", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Polynomial regression", + "type": "Waypoint", + "description": [ + "

    Find an approximating polynomial of known degree for a given data.

    Example:

    ", + "

    For input data:

    ", + "

    x = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    ", + "

    y = {1, 6, 17, 34, 57, 86, 121, 162, 209, 262, 321};

    ", + "

    The approximating polynomial is:

    ", + "

    3 x2 + 2 x + 1

    ", + "

    Here, the polynomial's coefficients are (3, 2, 1).

    This task is intended as a subtask for Measure relative performance of sorting algorithms implementations.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f81", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Polyspiral", + "type": "Waypoint", + "description": [ + "

    A Polyspiral is a spiral made of multiple line segments, whereby each segment is larger (or smaller) than the previous one by a given amount. Each segment also changes direction at a given angle.

    ", + "Task", + "

    Animate a series of polyspirals, by drawing a complete spiral then incrementing the angle, and (after clearing the background) drawing the next, and so on. Every spiral will be a frame of the animation. The animation may stop as it goes full circle or continue indefinitely. The given input values may be varied.

    If animation is not practical in your programming environment, you may show a single frame instead.

    ", + "Pseudo code", + "
    ",
    +        "    set incr to 0.0    // animation loop",
    +        "    WHILE true         incr = (incr + 0.05) MOD 360",
    +        "        x = width / 2",
    +        "        y = height / 2",
    +        "        length = 5",
    +        "        angle = incr        // spiral loop",
    +        "        FOR 1 TO 150",
    +        "            drawline",
    +        "            change direction by angle",
    +        "            length = length + 3",
    +        "            angle = (angle + incr) MOD 360",
    +        "        ENDFOR"
    +      ],
    +      "null": [
    +        "




    ", + "" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f82", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Population count", + "type": "Waypoint", + "description": [ + "

    The population count is the number of 1s (ones) in the binary representation of a non-negative integer.

    Population count is also known as pop count, popcount, sideways sum, and Hamming weight.

    For example, 5 (which is 101 in binary) has a population count of 2.

    ", + "

    Evil numbers are non-negative integers that have an even population count.

    Odious numbers are positive integers that have an odd population count.

    ", + "Task:", + "write a function (or routine) to return the population count of a non-negative integer.", + "all computation of the lists below should start with 0 (zero indexed).* display the pop count of the 1st thirty powers of 3 (30, 31, 32, 33, 34, ∙∙∙ 329).", + "

    * display the 1st thirty evil numbers.

    ", + "

    * display the 1st thirty odious numbers.

    ", + "display each list of integers on one line (which may or may not include a title), each set of integers being shown should be properly identified.See also", + "The On-Line Encyclopedia of Integer Sequences: A000069 odious numbers.", + "The On-Line Encyclopedia of Integer Sequences: A001969 evil numbers." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f83", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Power set", + "type": "Waypoint", + "description": [ + "

    A set is a collection (container) of certain values,

    ", + "

    without any particular order, and no repeated values.

    It corresponds with a finite set in mathematics.

    A set can be implemented as an associative array (partial mapping)

    ", + "

    in which the value of each key-value pair is ignored.

    Given a set S, the power set (or powerset) of S, written P(S), or 2S, is the set of all subsets of S.

    ", + "Task:", + "

    By using a library or built-in set type, or by defining a set type with necessary operations, write a function with a set S as input that yields the power set 2S of S.

    ", + "

    For example, the power set of {1,2,3,4} is

    ", + "

    :: .

    For a set which contains n elements, the corresponding power set has 2n elements, including the edge cases of empty set.

    The power set of the empty set is the set which contains itself (20 = 1):

    ", + "

    :: $\\mathcal{P}$($\\varnothing$) = { $\\varnothing$ }

    And the power set of the set which contains only the empty set, has two subsets, the empty set and the set which contains the empty set (21 = 2):

    ", + "

    :: $\\mathcal{P}$({$\\varnothing$}) = { $\\varnothing$, { $\\varnothing$ } }

    ", + "

    Extra credit: Demonstrate that your language supports these last two powersets.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "====Iteration====", + "Uses a JSON stringifier from http://www.json.org/js.html", + "", + "{{works with|SpiderMonkey}}", + "function powerset(ary) {", + " var ps = [[]];", + " for (var i=0; i < ary.length; i++) {", + " for (var j = 0, len = ps.length; j < len; j++) {", + " ps.push(ps[j].concat(ary[i]));", + " }", + " }", + " return ps;", + "}", + "", + "var res = powerset([1,2,3,4]);", + "", + "load('json2.js');", + "print(JSON.stringify(res));", + "", + "{{out}}", + "
    [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3],[4],[1,4],[2,4],[1,2,4],[3,4],[1,3,4],[2,3,4],[1,2,3,4]]
    ", + "", + "", + "====Functional composition====", + "", + "{{trans|Haskell}}", + "", + "(function () {", + "", + " // translating: powerset = foldr (\\x acc -> acc ++ map (x:) acc) [[]]", + "", + " function powerset(xs) {", + " return xs.reduceRight(function (a, x) {", + " return a.concat(a.map(function (y) {", + " return [x].concat(y);", + " }));", + " }, [[]]);", + " }", + "", + "", + " // TEST", + " return {", + " '[1,2,3] ->': powerset([1, 2, 3]),", + " 'empty set ->': powerset([]),", + " 'set which contains only the empty set ->': powerset([[]])", + " }", + "", + "})();", + "", + "{{Out}}", + "", + "{", + " \"[1,2,3] ->\":[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]],", + " \"empty set ->\":[[]],", + " \"set which contains only the empty set ->\":[[], [[]]]", + "}", + "", + "===ES6===", + "", + "(() => {", + " 'use strict';", + "", + " // powerset :: [a] -> [[a]]", + " const powerset = xs =>", + " xs.reduceRight((a, x) => a.concat(a.map(y => [x].concat(y))), [", + " []", + " ]);", + "", + "", + " // TEST", + " return {", + " '[1,2,3] ->': powerset([1, 2, 3]),", + " 'empty set ->': powerset([]),", + " 'set which contains only the empty set ->': powerset([", + " []", + " ])", + " };", + "})()", + "", + "{{Out}}", + "{\"[1,2,3] ->\":[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]], ", + "\"empty set ->\":[[]], ", + "\"set which contains only the empty set ->\":[[], [[]]]}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f84", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function powerset(ary) {\n var ps = [[]];\n for (var i=0; i < ary.length; i++) {\n for (var j = 0, len = ps.length; j < len; j++) {\n ps.push(ps[j].concat(ary[i]));\n }\n }\n return ps;\n}\n\nvar res = powerset([1,2,3,4]);\n\nload('json2.js');\nprint(JSON.stringify(res));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Price fraction", + "type": "Waypoint", + "description": [ + "

    A friend of mine runs a pharmacy. He has a specialized function in his Dispensary application which receives a decimal value of currency and replaces it to a standard value. This value is regulated by a government department.

    ", + "Task:", + "

    Given a floating point value between 0.00 and 1.00, rescale according to the following table:

    >= 0.00 < 0.06 := 0.10

    ", + "

    >= 0.06 < 0.11 := 0.18

    ", + "

    >= 0.11 < 0.16 := 0.26

    ", + "

    >= 0.16 < 0.21 := 0.32

    ", + "

    >= 0.21 < 0.26 := 0.38

    ", + "

    >= 0.26 < 0.31 := 0.44

    ", + "

    >= 0.31 < 0.36 := 0.50

    ", + "

    >= 0.36 < 0.41 := 0.54

    ", + "

    >= 0.41 < 0.46 := 0.58

    ", + "

    >= 0.46 < 0.51 := 0.62

    ", + "

    >= 0.51 < 0.56 := 0.66

    ", + "

    >= 0.56 < 0.61 := 0.70

    ", + "

    >= 0.61 < 0.66 := 0.74

    ", + "

    >= 0.66 < 0.71 := 0.78

    ", + "

    >= 0.71 < 0.76 := 0.82

    ", + "

    >= 0.76 < 0.81 := 0.86

    ", + "

    >= 0.81 < 0.86 := 0.90

    ", + "

    >= 0.86 < 0.91 := 0.94

    ", + "

    >= 0.91 < 0.96 := 0.98

    ", + "

    >= 0.96 < 1.01 := 1.00

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "In the task definition, the first step is 0.06, the rest are 0.05 ", + "so a re-factoring can subtract 0.01 from the value and divide by 0.05 to get the step.", + "", + "Working with decimal numbers in JavaScript has issues, e.g. 0.06 - 0.01 = 0.049999999999999996 due to using IEEE 754 double precision numbers that can't accurately represent all decimals. So values are multiplied by 100 and integer arithmetic is used.", + "", + "Note that multiplying a string by a number produces a number, the bitwise OR (|) truncates floating point numbers to integer, making it a concise replacement for ''Math.floor''.", + "", + "Passing a value outside the range 0 <= x < 1.01 will return undefined.", + "", + "function getScaleFactor(v) {", + "", + " var values = ['0.10','0.18','0.26','0.32','0.38','0.44','0.50','0.54',", + " '0.58','0.62','0.66','0.70','0.74','0.78','0.82','0.86',", + " '0.90','0.94','0.98','1.00'];", + "", + " return values[(v * 100 - 1) / 5 | 0];", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f86", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function getScaleFactor(v) {\n\n var values = ['0.10','0.18','0.26','0.32','0.38','0.44','0.50','0.54',\n '0.58','0.62','0.66','0.70','0.74','0.78','0.82','0.86',\n '0.90','0.94','0.98','1.00'];\n\n return values[(v * 100 - 1) / 5 | 0];\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Primality by trial division", + "type": "Waypoint", + "description": [ + "Task:", + "

    Write a boolean function that tells whether a given integer is prime.

    ", + "

    Remember that 1 and all non-positive numbers are not prime.

    Use trial division.

    Even numbers over two may be eliminated right away.

    A loop from 3 to √ will suffice, but other loops are allowed.

    ", + "Related tasks:", + " count in factors", + " prime decomposition", + " AKS test for primes", + " factors of an integer", + " Sieve of Eratosthenes", + " factors of a Mersenne number", + " trial factoring of a Mersenne number", + " partition an integer X into N primes", + " sequence of primes by Trial Division" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function isPrime(n) {", + " if (n == 2 || n == 3 || n == 5 || n == 7) {", + " return true;", + " } else if ((n < 2) || (n % 2 == 0)) {", + " return false;", + " } else {", + " for (var i = 3; i <= Math.sqrt(n); i += 2) {", + " if (n % i == 0)", + " return false;", + " }", + " return true;", + " }", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f87", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function isPrime(n) {\n if (n == 2 || n == 3 || n == 5 || n == 7) {\n return true;\n } else if ((n < 2) || (n % 2 == 0)) {\n return false;\n } else {\n for (var i = 3; i <= Math.sqrt(n); i += 2) {\n if (n % i == 0)\n return false;\n }\n return true;\n }\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Prime decomposition", + "type": "Waypoint", + "description": [ + "

    The prime decomposition of a number is defined as a list of prime numbers

    ", + "

    which when all multiplied together, are equal to that number.

    ", + "Example:", + "

    12 = 2 × 2 × 3, so its prime decomposition is {2, 2, 3}

    ", + "Task:", + "

    Write a function which returns an array or collection which contains the prime decomposition of a given number $n$ greater than 1.

    If your language does not have an isPrime-like function available,

    ", + "

    you may assume that you have a function which determines

    ", + "

    whether a number is prime (note its name before your code).

    If you would like to test code from this task, you may use code from trial division or the Sieve of Eratosthenes.

    Note: The program must not be limited by the word size of your computer or some other artificial limit; it should work for any number regardless of size (ignoring the physical limits of RAM etc).

    ", + "Related tasks:", + " count in factors", + " factors of an integer", + " Sieve of Eratosthenes", + " primality by trial division", + " factors of a Mersenne number", + " trial factoring of a Mersenne number", + " partition an integer X into N primes", + " sequence of primes by Trial Division" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "This code uses the BigInteger Library [http://xenon.stanford.edu/~tjw/jsbn/jsbn.js jsbn] and [http://xenon.stanford.edu/~tjw/jsbn/jsbn2.js jsbn2]", + "function run_factorize(input, output) {", + " var n = new BigInteger(input.value, 10);", + " var TWO = new BigInteger(\"2\", 10);", + " var divisor = new BigInteger(\"3\", 10);", + " var prod = false;", + "", + " if (n.compareTo(TWO) < 0) ", + " return; ", + "", + " output.value = \"\";", + "", + " while (true) {", + " var qr = n.divideAndRemainder(TWO);", + " if (qr[1].equals(BigInteger.ZERO)) {", + " if (prod) ", + " output.value += \"*\"; ", + " else ", + " prod = true; ", + " output.value += \"2\";", + " n = qr[0];", + " }", + " else ", + " break; ", + " }", + "", + " while (!n.equals(BigInteger.ONE)) {", + " var qr = n.divideAndRemainder(divisor);", + " if (qr[1].equals(BigInteger.ZERO)) {", + " if (prod) ", + " output.value += \"*\"; ", + " else ", + " prod = true; ", + " output.value += divisor;", + " n = qr[0];", + " }", + " else ", + " divisor = divisor.add(TWO); ", + " }", + "}", + "", + "Without any library.", + "function run_factorize(n) {", + "\tif (n <= 3)", + "\t\t\treturn [n];", + "", + "\tvar ans = [];", + "\tvar done = false;", + "\twhile (!done)", + "\t{", + "\t\tif (n%2 === 0){", + "\t\t\t\tans.push(2);", + "\t\t\t\tn /= 2;", + "\t\t\t\tcontinue;", + "\t\t}", + "\t\tif (n%3 === 0){", + "\t\t\t\tans.push(3);", + "\t\t\t\tn /= 3;", + "\t\t\t\tcontinue;", + "\t\t}", + "\t\tif ( n === 1)", + "\t\t\treturn ans;", + "\t\tvar sr = Math.sqrt(n);", + "\t\tdone = true;", + "\t\t// try to divide the checked number by all numbers till its square root.", + "\t\tfor (var i=6; i<=sr; i+=6){", + "\t\t\t\tif (n%(i-1) === 0){ // is n divisible by i-1?", + "\t\t\t\t\t\tans.push( (i-1) );", + "\t\t\t\t\t\tn /= (i-1);", + "\t\t\t\t\t\tdone = false;", + "\t\t\t\t\t\tbreak;", + "\t\t\t\t}", + "\t\t\t\tif (n%(i+1) === 0){ // is n divisible by i+1?", + "\t\t\t\t\t\tans.push( (i+1) );", + "\t\t\t\t\t\tn /= (i+1);", + "\t\t\t\t\t\tdone = false;", + "\t\t\t\t\t\tbreak;", + "\t\t\t\t}", + "\t\t}", + "\t}", + "\tans.push( n );", + "\treturn ans;", + "}", + "", + "TDD using Jasmine", + "", + "PrimeFactors.js", + "function factors(n) {", + " if (!n || n < 2)", + " return [];", + "", + " var f = [];", + " for (var i = 2; i <= n; i++){", + " while (n % i === 0){", + " f.push(i);", + " n /= i;", + " }", + " }", + "", + " return f;", + "};", + "", + "", + "SpecPrimeFactors.js (with tag for Chutzpah)", + "/// ", + "", + "describe(\"Prime Factors\", function() {", + " it(\"Given nothing, empty is returned\", function() {", + " expect(factors()).toEqual([]);", + " });", + "", + " it(\"Given 1, empty is returned\", function() {", + " expect(factors(1)).toEqual([]);", + " });", + "", + " it(\"Given 2, 2 is returned\", function() {", + " expect(factors(2)).toEqual([2]);", + " });", + "", + " it(\"Given 3, 3 is returned\", function() {", + " expect(factors(3)).toEqual([3]);", + " });", + "", + " it(\"Given 4, 2 and 2 is returned\", function() {", + " expect(factors(4)).toEqual([2, 2]);", + " });", + "", + " it(\"Given 5, 5 is returned\", function() {", + " expect(factors(5)).toEqual([5]);", + " });", + "", + " it(\"Given 6, 2 and 3 is returned\", function() {", + " expect(factors(6)).toEqual([2, 3]);", + " });", + "", + " it(\"Given 7, 7 is returned\", function() {", + " expect(factors(7)).toEqual([7]);", + " });", + "", + " it(\"Given 8; 2, 2, and 2 is returned\", function() {", + " expect(factors(8)).toEqual([2, 2, 2]);", + " });", + "", + " it(\"Given a large number, many primes factors are returned\", function() {", + " expect(factors(2*2*2*3*3*7*11*17))", + " .toEqual([2, 2, 2, 3, 3, 7, 11, 17]);", + " });", + "", + " it(\"Given a large prime number, that number is returned\", function() {", + " expect(factors(997)).toEqual([997]);", + " });", + "});", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f88", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function run_factorize(input, output) {\n var n = new BigInteger(input.value, 10);\n var TWO = new BigInteger(\"2\", 10);\n var divisor = new BigInteger(\"3\", 10);\n var prod = false;\n\n if (n.compareTo(TWO) < 0) \n return; \n\n output.value = \"\";\n\n while (true) {\n var qr = n.divideAndRemainder(TWO);\n if (qr[1].equals(BigInteger.ZERO)) {\n if (prod) \n output.value += \"*\"; \n else \n prod = true; \n output.value += \"2\";\n n = qr[0];\n }\n else \n break; \n }\n\n while (!n.equals(BigInteger.ONE)) {\n var qr = n.divideAndRemainder(divisor);\n if (qr[1].equals(BigInteger.ZERO)) {\n if (prod) \n output.value += \"*\"; \n else \n prod = true; \n output.value += divisor;\n n = qr[0];\n }\n else \n divisor = divisor.add(TWO); \n }\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Primes - allocate descendants to their ancestors", + "type": "Waypoint", + "description": [ + "

    The concept, rather simple, is to add the decomposition into prime factors of a number to get its 'ancestors'.

    ", + "

    The objective is to demonstrate that the choice of the algorithm can be crucial in term of performance.

    ", + "

    This solution could be compared to the solution that would use the decomposition into primes for all the numbers between 1 and 333.

    ", + "

    The problem is to list, for a delimited set of ancestors (from 1 to 99) :

    - the total of their own ancestors (LEVEL),

    - their own ancestors (ANCESTORS),

    - the total of the direct descendants (DESCENDANTS),

    - all the direct descendants.

    ", + "

    You only have to consider the prime factors < 100.

    A grand total of the descendants has to be printed at the end of the list.

    The task should be accomplished in a reasonable time-frame.

    ", + "

    Example :

    ", + "
    46 = 2*23 --> 2+23 = 25, is the parent of 46.",
    +        "25 = 5*5  --> 5+5  = 10, is the parent of 25.",
    +        "10 = 2*5  --> 2+5  = 7,  is the parent of 10.",
    +        "7 is a prime factor and, as such, has no parent.46 has 3 ancestors (7, 10 and 25).",
    +        "46 has 557 descendants.

    The list layout and the output for Parent [46] :

    ", + "
    [46] Level: 3",
    +        "Ancestors: 7, 10, 25",
    +        "Descendants: 557",
    +        "129, 205, 246, 493, 518, 529, 740, 806, 888, 999, 1364, 1508, 1748, 2552, 2871, 3128, 3255, 3472, 3519, 3875, 3906, 4263, 4650, 4960, 5075, 5415, 5580, 5776, 5952, 6090, 6279, 6496, 6498, 6696, 6783, 7250, 7308, 7475, 7533, 8075, 8151, 8619, 8700, 8855, 8970, 9280, 9568, 9690, 10115, 10336, 10440, 10626, 10764, 11136, 11495, 11628, 11745, 12103, 12138, 12155, 12528, 12650, 13794, 14094, 14399, 14450, 14586, 15180, 15379, 15778, 16192, 17290, 17303, 17340, 18216, 18496, 20482, 20493, 20570, 20748, 20808, 21658, 21970, 22540, 23409, 24684, 24700, 26026, 26364, 27048, 29260, 29282, 29640, 30429, 30940, 31616, 32200, 33345, 35112, 35568, 36225, 36652, 37128, 37180, 38640, 39501, 40014, 41216, 41769, 41800, 43125, 43470, 44044, 44200, 44616, 46000, 46368, 47025, 49725, 50160, 50193, 51750, 52136, 52164, 52360, 53040, 53504, 55200, 56430, 56576, 58653, 58880, 58905, 59670, 60192, 62100, 62832, 62920, 63648, 66240, 66248, 67716, 69825, 70125, 70656, 70686, 70785, 71604, 74480, 74520, 74529, 74536, 74800, 75504, 79488, 83125, 83790, 83835, 83853, 84150, 84942, 87465, 88725, 89376, 89424, 89760, 93296, 94640, 95744, 99750, 99825, 100548, 100602, 100980, 104125, 104958, 105105, 105625, 106400, 106470, 106480, 107712, 112112, 113568, 118750, 119700, 119790, 121176, 124509, 124950, 125125, 126126, 126750, 127680, 127764, 127776, 133280, 135200, 136192, 136323, 142500, 143640, 143748, 148225, 148750, 149940, 150150, 152000, 152100, 153216, 156065, 159936, 160160, 161595, 162240, 171000, 172368, 173056, 177870, 178500, 178750, 179928, 180180, 182400, 182520, 184877, 187278, 189728, 190400, 192192, 192375, 193914, 194560, 194688, 202419, 205200, 205335, 211750, 212500, 213444, 214200, 214500, 216216, 218880, 219024, 222950, 228480, 228800, 230850, 233472, 240975, 243243, 243712, 246240, 246402, 254100, 255000, 257040, 257400, 262656, 264110, 267540, 271040, 272000, 274176, 274560, 277020, 285376, 286875, 289170, 289575, 292864, 295488, 302500, 304920, 306000, 308448, 308880, 316932, 318500, 321048, 325248, 326400, 329472, 332424, 343035, 344250, 347004, 347490, 348160, 361179, 363000, 365904, 367200, 370656, 373977, 377300, 382200, 387200, 391680, 407680, 408375, 411642, 413100, 416988, 417792, 429975, 435600, 440640, 452760, 455000, 458640, 464640, 470016, 470596, 482944, 489216, 490050, 495616, 495720, 509355, 511875, 515970, 522720, 528768, 539000, 543312, 546000, 550368, 557568, 557685, 582400, 588060, 594864, 606375, 609375, 611226, 614250, 619164, 627264, 646800, 650000, 655200, 669222, 672280, 689920, 698880, 705672, 721875, 727650, 731250, 737100, 745472, 756315, 770000, 776160, 780000, 786240, 793881, 806736, 827904, 832000, 838656, 859375, 866250, 873180, 877500, 884520, 900375, 907578, 924000, 931392, 936000, 943488, 960400, 985600, 995085, 998400, 1031250, 1039500, 1047816, 1053000, 1061424, 1064960, 1071875, 1080450, 1100000, 1108800, 1123200, 1152480, 1178793, 1182720, 1184625, 1194102, 1198080, 1229312, 1237500, 1247400, 1261568, 1263600, 1277952, 1286250, 1296540, 1320000, 1330560, 1347840, 1372000, 1382976, 1403325, 1408000, 1419264, 1421550, 1437696, 1485000, 1496880, 1516320, 1531250, 1543500, 1555848, 1584000, 1596672, 1617408, 1646400, 1670625, 1683990, 1689600, 1705860, 1750329, 1756160, 1782000, 1796256, 1802240, 1819584, 1837500, 1852200, 1900800, 1960000, 1975680, 2004750, 2020788, 2027520, 2047032, 2083725, 2107392, 2138400, 2162688, 2187500, 2205000, 2222640, 2280960, 2302911, 2352000, 2370816, 2405700, 2433024, 2480625, 2500470, 2508800, 2566080, 2625000, 2646000, 2667168, 2737152, 2800000, 2822400, 2886840, 2953125, 2976750, 3000564, 3010560, 3079296, 3125000, 3150000, 3175200, 3211264, 3247695, 3360000, 3386880, 3464208, 3515625, 3543750, 3572100, 3584000, 3612672, 3750000, 3780000, 3810240, 3897234, 4000000, 4032000, 4064256, 4218750, 4252500, 4286520, 4300800, 4500000, 4536000, 4572288, 4587520, 4800000, 4822335, 4838400, 5062500, 5103000, 5120000, 5143824, 5160960, 5400000, 5443200, 5505024, 5740875, 5760000, 5786802, 5806080, 6075000, 6123600, 6144000, 6193152, 6480000, 6531840, 6553600, 6834375, 6889050, 6912000, 6967296, 7290000, 7348320, 7372800, 7776000, 7838208, 7864320, 8201250, 8266860, 8294400, 8388608, 8748000, 8817984, 8847360, 9331200, 9437184, 9841500, 9920232, 9953280, 10497600, 10616832, 11160261, 11197440, 11809800, 11943936, 12597120, 13286025, 13436928, 14171760, 15116544, 15943230, 17006112, 19131876

    Some figures :

    ", + "
    The biggest descendant number : 3^33 = 5.559.060.566.555.523 (parent 99)Total Descendants 546.986",
    +        "
    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f89", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Primorial numbers", + "type": "Waypoint", + "description": [ + "

    Primorial numbers are those formed by multiplying successive prime numbers.

    ", + "

    The primorial number series is:

    :* primorial(0) = 1 (by definition)

    ", + "

    :* primorial(1) = 2 (2)

    ", + "

    :* primorial(2) = 6 (2*3)

    ", + "

    :* primorial(3) = 30 (2*3*5)

    ", + "

    :* primorial(4) = 210 (2*3*5*7)

    ", + "

    :* primorial(5) = 2310 (2*3*5*7*11)

    ", + "

    :* primorial(6) = 30030 (2*3*5*7*11*13)

    ", + "

    ;* ∙ ∙ ∙

    To express this mathematically, primorialn is

    ", + "

    the product of the first n (successive) primes:

    ", + "

    ", + "

    $primorial_n = \\prod_{k=1}^n prime_k$

    ", + "
    ", + "

    ::::: ─── where $prime_k$ is the kth'' prime number.

    ", + "
    ", + "

    In some sense, generating primorial numbers is similar to factorials.

    As with factorials, primorial numbers get large quickly.

    ", + "

    task requirements:

    Show the first ten primorial numbers (0 ──► 9, inclusive).", + " Show the length of primorial numbers whose index is: 10 100 1,000 10,000 and 100,000.", + " Show the length of the one millionth primorial number (optional). ", + " Use exact integers, not approximations.

    By length (above), it is meant the number of decimal digits in the numbers.

    ", + "

    links:

    See the MathWorld webpage: primorial

    See the Wikipedia webpage: primorial.

    See the OEIS webpage: A2110.

    ", + "

    Related tasks:

    ", + "Factorial", + "Sequence of primorial primes" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f8a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Problem of Apollonius", + "type": "Waypoint", + "description": [ + "Task:", + "

    Implement a solution to the Problem of Apollonius (description on Wikipedia) which is the problem of finding the circle that is tangent to three specified circles. There is an algebraic solution which is pretty straightforward.

    The solutions to the example in the code are shown in the image (below and right). The red circle is \"internally tangent\" to all three black circles, and the green circle is \"externally tangent\" to all three black circles.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f8d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Pythagoras tree", + "type": "Waypoint", + "description": [ + "

    The Pythagoras tree is a fractal tree constructed from squares. It is named after Pythagoras because each triple of touching squares encloses a right triangle, in a configuration traditionally used to represent the Pythagorean theorem.

    ", + "Task", + "

    Construct a Pythagoras tree of order 7 using only vectors (no rotation or trig functions).

    ", + "Related tasks", + "Fractal tree" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f90", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Pythagorean triples", + "type": "Waypoint", + "description": [ + "

    A Pythagorean triple is defined as three positive integers $(a, b, c)$ where $a < b < c$, and $a^2+b^2=c^2.$

    They are called primitive triples if $a, b, c$ are co-prime, that is, if their pairwise greatest common divisors ${\\rm gcd}(a, b) = {\\rm gcd}(a, c) = {\\rm gcd}(b, c) = 1$.

    Because of their relationship through the Pythagorean theorem, a, b, and c are co-prime if a and b are co-prime (${\\rm gcd}(a, b) = 1$).

    Each triple forms the length of the sides of a right triangle, whose perimeter is $P=a+b+c$.

    ", + "Task:", + "

    The task is to determine how many Pythagorean triples there are with a perimeter no larger than 100 and the number of these that are primitive.

    ", + "Extra credit: ", + "

    Deal with large values. Can your program handle a maximum perimeter of 1,000,000? What about 10,000,000? 100,000,000?

    Note: the extra credit is not for you to demonstrate how fast your language is compared to others; you need a proper algorithm to solve them in a timely manner.

    ", + "Cf:", + "List comprehensions" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES6===", + "Exhaustive search of a full cartesian product. Not scalable.", + "(() => {", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " const concatMap = (f, xs) => [].concat.apply([], xs.map(f));", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // gcd :: Integral a => a -> a -> a", + " const gcd = (x, y) => {", + " const _gcd = (a, b) => (b === 0 ? a : _gcd(b, a % b)),", + " abs = Math.abs;", + " return _gcd(abs(x), abs(y));", + " }", + "", + " // Arguments: predicate, maximum perimeter", + " // pythTripleCount :: ((Int, Int, Int) -> Bool) -> Int -> Int", + " const pythTripleCount = (p, maxPerim) => {", + " const xs = range(1, Math.floor(maxPerim / 2));", + "", + " return concatMap(x =>", + " concatMap(y =>", + " concatMap(z =>", + " ( (x + y + z <= maxPerim ) &&", + " (x * x + y * y === z * z ) &&", + " p(x, y, z) ) ? [", + " [x, y, z]", + " ] : [ ], // concatMap eliminates empty lists", + " xs.slice(y)), xs.slice(x)), xs", + " )", + " .length;", + " };", + "", + " return [10, 100, 1000]", + " .map(n => ({", + " maxPerimeter: n,", + " triples: pythTripleCount(x => true, n),", + " primitives: pythTripleCount((x, y, _) => gcd(x, y) === 1, n)", + " }));", + "})();", + "", + "{{Out}}", + "[{\"maxPerimeter\":10, \"triples\":0, \"primitives\":0}, ", + " {\"maxPerimeter\":100, \"triples\":17, \"primitives\":7}, ", + " {\"maxPerimeter\":1000, \"triples\":325, \"primitives\":70}]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f91", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n\n // concatMap :: (a -> [b]) -> [a] -> [b]\n const concatMap = (f, xs) => [].concat.apply([], xs.map(f));\n\n // range :: Int -> Int -> [Int]\n const range = (m, n) =>\n Array.from({\n length: Math.floor(n - m) + 1\n }, (_, i) => m + i);\n\n // gcd :: Integral a => a -> a -> a\n const gcd = (x, y) => {\n const _gcd = (a, b) => (b === 0 ? a : _gcd(b, a % b)),\n abs = Math.abs;\n return _gcd(abs(x), abs(y));\n }\n\n // Arguments: predicate, maximum perimeter\n // pythTripleCount :: ((Int, Int, Int) -> Bool) -> Int -> Int\n const pythTripleCount = (p, maxPerim) => {\n const xs = range(1, Math.floor(maxPerim / 2));\n\n return concatMap(x =>\n concatMap(y =>\n concatMap(z =>\n ( (x + y + z <= maxPerim ) &&\n (x * x + y * y === z * z ) &&\n p(x, y, z) ) ? [\n [x, y, z]\n ] : [ ], // concatMap eliminates empty lists\n xs.slice(y)), xs.slice(x)), xs\n )\n .length;\n };\n\n return [10, 100, 1000]\n .map(n => ({\n maxPerimeter: n,\n triples: pythTripleCount(x => true, n),\n primitives: pythTripleCount((x, y, _) => gcd(x, y) === 1, n)\n }));\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "QR decomposition", + "type": "Waypoint", + "description": [ + "

    Any rectangular $m \\times n$ matrix $\\mathit A$ can be decomposed to a product of an orthogonal matrix $\\mathit Q$ and an upper (right) triangular matrix $\\mathit R$, as described in QR decomposition.

    Task

    Demonstrate the QR decomposition on the example matrix from the Wikipedia article:

    :$A = \\begin{pmatrix}

    ", + "

    12 & -51 & 4 \\\\

    ", + "

    6 & 167 & -68 \\\\

    ", + "

    -4 & 24 & -41 \\end{pmatrix}$

    and the usage for linear least squares problems on the example from Polynomial_regression. The method of Householder reflections should be used:

    Method

    Multiplying a given vector $\\mathit a$, for example the first column of matrix $\\mathit A$, with the Householder matrix $\\mathit H$, which is given as

    :$H = I - \\frac {2} {u^T u} u u^T$

    reflects $\\mathit a$ about a plane given by its normal vector $\\mathit u$. When the normal vector of the plane $\\mathit u$ is given as

    :$u = a - \\|a\\|_2 \\; e_1$

    then the transformation reflects $\\mathit a$ onto the first standard basis vector

    :$e_1 = [1 \\; 0 \\; 0 \\; ...]^T$

    which means that all entries but the first become zero. To avoid numerical cancellation errors, we should take the opposite sign of $a_1$:

    :$u = a + \\textrm{sign}(a_1)\\|a\\|_2 \\; e_1$

    and normalize with respect to the first element:

    :$v = \\frac{u}{u_1}$

    The equation for $H$ thus becomes:

    :$H = I - \\frac {2} {v^T v} v v^T$

    or, in another form

    :$H = I - \\beta v v^T$

    with

    ", + "

    :$\\beta = \\frac {2} {v^T v}$

    Applying $\\mathit H$ on $\\mathit a$ then gives

    :$H \\; a = -\\textrm{sign}(a_1) \\; \\|a\\|_2 \\; e_1$

    and applying $\\mathit H$ on the matrix $\\mathit A$ zeroes all subdiagonal elements of the first column:

    :$H_1 \\; A = \\begin{pmatrix}

    ", + "

    r_{11} & r_{12} & r_{13} \\\\

    ", + "

    0 & * & * \\\\

    ", + "

    0 & * & * \\end{pmatrix}$

    In the second step, the second column of $\\mathit A$, we want to zero all elements but the first two, which means that we have to calculate $\\mathit H$ with the first column of the submatrix (denoted *), not on the whole second column of $\\mathit A$.

    To get $H_2$, we then embed the new $\\mathit H$ into an $m \\times n$ identity:

    :$H_2 = \\begin{pmatrix}

    ", + "

    1 & 0 & 0 \\\\

    ", + "

    0 & H & \\\\

    ", + "

    0 & & \\end{pmatrix}$

    This is how we can, column by column, remove all subdiagonal elements of $\\mathit A$ and thus transform it into $\\mathit R$.

    :$H_n \\; ... \\; H_3 H_2 H_1 A = R$

    The product of all the Householder matrices $\\mathit H$, for every column, in reverse order, will then yield the orthogonal matrix $\\mathit Q$.

    :$H_1 H_2 H_3 \\; ... \\; H_n = Q$

    The QR decomposition should then be used to solve linear least squares (Multiple regression) problems $\\mathit A x = b$ by solving

    :$R \\; x = Q^T \\; b$

    When $\\mathit R$ is not square, i.e. $m > n$ we have to cut off the $\\mathit m - n$ zero padded bottom rows.

    :$R =

    ", + "

    \\begin{pmatrix}

    ", + "

    R_1 \\\\

    ", + "

    0 \\end{pmatrix}$

    and the same for the RHS:

    :$Q^T \\; b =

    ", + "

    \\begin{pmatrix}

    ", + "

    q_1 \\\\

    ", + "

    q_2 \\end{pmatrix}$

    Finally, solve the square upper triangular system by back substitution:

    :$R_1 \\; x = q_1$

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f92", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Quaternion type", + "type": "Waypoint", + "description": [ + "

    Quaternions are an extension of the idea of complex numbers.

    A complex number has a real and complex part, sometimes written as a + bi,

    ", + "where a and b stand for real numbers, and i stands for the square root of minus 1.

    An example of a complex number might be -3 + 2i,

    ", + "where the real part, a is -3.0 and the complex part, b is +2.0.

    A quaternion has one real part and three imaginary parts, i, j, and k.

    A quaternion might be written as a + bi + cj + dk.

    In the quaternion numbering system:

    ", + "

    ::* i∙i = j∙j = k∙k = i∙j∙k = -1, or more simply,

    ", + "

    ::* ii = jj = kk = ijk = -1.

    The order of multiplication is important, as, in general, for two quaternions:

    ", + "

    ::: q1 and q2: q1q2 ≠ q2q1.

    An example of a quaternion might be 1 +2i +3j +4k

    There is a list form of notation where just the numbers are shown and the imaginary multipliers i, j, and k are assumed by position.

    So the example above would be written as (1, 2, 3, 4)

    ", + "Task:", + "

    Given the three quaternions and their components:

    ", + "

    q = (1, 2, 3, 4) = (a, b, c, d)

    ", + "

    q1 = (2, 3, 4, 5) = (a1, b1, c1, d1)

    ", + "

    q2 = (3, 4, 5, 6) = (a2, b2, c2, d2)

    ", + "

    And a wholly real number r = 7.

    ", + "

    Note: The first formula below is invisible to the majority of browsers, including Chrome, IE/Edge, Safari, Opera etc. It may, subject to the installation of requisite fonts, prove visible in Firefox.

    ", + "

    Create functions (or classes) to perform simple maths with quaternions including computing:

    ", + "The norm of a quaternion: $ = \\sqrt{ a^2 + b^2 + c^2 + d^2 } $ ", + "The negative of a quaternion: = (-a, -b, -c, -d) ", + "The conjugate of a quaternion: = ( a, -b, -c, -d) ", + "Addition of a real number r and a quaternion q: r + q = q + r = (a+r, b, c, d) ", + "Addition of two quaternions: q1 + q2 = (a1+a2, b1+b2, c1+c2, d1+d2) ", + "Multiplication of a real number and a quaternion: qr = rq = (ar, br, cr, dr) ", + "Multiplication of two quaternions q1 and q2 is given by: ( a1a2 − b1b2 − c1c2 − d1d2, a1b2 + b1a2 + c1d2 − d1c2, a1c2 − b1d2 + c1a2 + d1b2, a1d2 + b1c2 − c1b2 + d1a2 ) ", + "Show that, for the two quaternions q1 and q2: q1q2 ≠ q2q1 ", + "

    If a language has built-in support for quaternions, then use it.

    ", + "C.f.:", + " Vector products", + " On Quaternions; or on a new System of Imaginaries in Algebra. By Sir William Rowan Hamilton LL.D, P.R.I.A., F.R.A.S., Hon. M. R. Soc. Ed. and Dub., Hon. or Corr. M. of the Royal or Imperial Academies of St. Petersburgh, Berlin, Turin and Paris, Member of the American Academy of Arts and Sciences, and of other Scientific Societies at Home and Abroad, Andrews' Prof. of Astronomy in the University of Dublin, and Royal Astronomer of Ireland." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Runs on Firefox 3+, limited support in other JS engines. More compatible JavaScript deserves its own entry.", + "", + "var Quaternion = (function() {", + " // The Q() function takes an array argument and changes it", + " // prototype so that it becomes a Quaternion instance. This is", + " // scoped only for prototype member access.", + " function Q(a) {", + "\ta.__proto__ = proto;", + "\treturn a;", + " }", + "", + " // Actual constructor. This constructor converts its arguments to", + " // an array, then that array to a Quaternion instance, then", + " // returns that instance. (using \"new\" with this constructor is", + " // optional)", + " function Quaternion() {", + "\treturn Q(Array.prototype.slice.call(arguments, 0, 4));", + " }", + "", + " // Prototype for all Quaternions", + " const proto = {", + "\t// Inherits from a 4-element Array", + "\t__proto__ : [0,0,0,0],", + "", + "\t// Properties -- In addition to Array[0..3] access, we", + "\t// also define matching a, b, c, and d properties", + "\tget a() this[0],", + "\tget b() this[1],", + "\tget c() this[2],", + "\tget d() this[3],", + "", + "\t// Methods", + "\tnorm : function() Math.sqrt(this.map(function(x) x*x).reduce(function(x,y) x+y)),", + "\tnegate : function() Q(this.map(function(x) -x)),", + "\tconjugate : function() Q([ this[0] ].concat(this.slice(1).map(function(x) -x))),", + "\tadd : function(x) {", + "\t if (\"number\" === typeof x) {", + "\t\treturn Q([ this[0] + x ].concat(this.slice(1)));", + "\t } else {", + "\t\treturn Q(this.map(function(v,i) v+x[i]));", + "\t }", + "\t},", + "\tmul : function(r) {", + "\t var q = this;", + "\t if (\"number\" === typeof r) {", + "\t\treturn Q(q.map(function(e) e*r));", + "\t } else {", + "\t\treturn Q([ q[0] * r[0] - q[1] * r[1] - q[2] * r[2] - q[3] * r[3],", + "\t\t\t q[0] * r[1] + q[1] * r[0] + q[2] * r[3] - q[3] * r[2],", + "\t\t\t q[0] * r[2] - q[1] * r[3] + q[2] * r[0] + q[3] * r[1],", + "\t\t\t q[0] * r[3] + q[1] * r[2] - q[2] * r[1] + q[3] * r[0] ]);", + "\t }", + "\t},", + "\tequals : function(q) this.every(function(v,i) v === q[i]),", + "\ttoString : function() (this[0] + \" + \" + this[1] + \"i + \"+this[2] + \"j + \" + this[3] + \"k\").replace(/\\+ -/g, '- ')", + " };", + "", + " Quaternion.prototype = proto;", + " return Quaternion;", + "})();", + "", + "Task/Example Usage:", + "", + "var q = Quaternion(1,2,3,4);", + "var q1 = Quaternion(2,3,4,5);", + "var q2 = Quaternion(3,4,5,6);", + "var r = 7;", + "", + "console.log(\"q = \"+q);", + "console.log(\"q1 = \"+q1);", + "console.log(\"q2 = \"+q2);", + "console.log(\"r = \"+r);", + "console.log(\"1. q.norm() = \"+q.norm());", + "console.log(\"2. q.negate() = \"+q.negate());", + "console.log(\"3. q.conjugate() = \"+q.conjugate());", + "console.log(\"4. q.add(r) = \"+q.add(r));", + "console.log(\"5. q1.add(q2) = \"+q1.add(q2));", + "console.log(\"6. q.mul(r) = \"+q.mul(r));", + "console.log(\"7.a. q1.mul(q2) = \"+q1.mul(q2));", + "console.log(\"7.b. q2.mul(q1) = \"+q2.mul(q1));", + "console.log(\"8. q1.mul(q2) \" + (q1.mul(q2).equals(q2.mul(q1)) ? \"==\" : \"!=\") + \" q2.mul(q1)\");", + "", + "{{out}}", + "
    q = 1 + 2i + 3j + 4k",
    +        "q1 = 2 + 3i + 4j + 5k",
    +        "q2 = 3 + 4i + 5j + 6k",
    +        "r = 7",
    +        "1. q.norm() = 5.477225575051661",
    +        "2. q.negate() = -1 - 2i - 3j - 4k",
    +        "3. q.conjugate() = 1 - 2i - 3j - 4k",
    +        "4. q.add(r) = 8 + 2i + 3j + 4k",
    +        "5. q1.add(q2) = 5 + 7i + 9j + 11k",
    +        "6. q.mul(r) = 7 + 14i + 21j + 28k",
    +        "7.a. q1.mul(q2) = -56 + 16i + 24j + 26k",
    +        "7.b. q2.mul(q1) = -56 + 18i + 20j + 28k",
    +        "8. q1.mul(q2) != q2.mul(q1)
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f93", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var Quaternion = (function() {\n // The Q() function takes an array argument and changes it\n // prototype so that it becomes a Quaternion instance. This is\n // scoped only for prototype member access.\n function Q(a) {\n\ta.__proto__ = proto;\n\treturn a;\n }\n\n // Actual constructor. This constructor converts its arguments to\n // an array, then that array to a Quaternion instance, then\n // returns that instance. (using \"new\" with this constructor is\n // optional)\n function Quaternion() {\n\treturn Q(Array.prototype.slice.call(arguments, 0, 4));\n }\n\n // Prototype for all Quaternions\n const proto = {\n\t// Inherits from a 4-element Array\n\t__proto__ : [0,0,0,0],\n\n\t// Properties -- In addition to Array[0..3] access, we\n\t// also define matching a, b, c, and d properties\n\tget a() this[0],\n\tget b() this[1],\n\tget c() this[2],\n\tget d() this[3],\n\n\t// Methods\n\tnorm : function() Math.sqrt(this.map(function(x) x*x).reduce(function(x,y) x+y)),\n\tnegate : function() Q(this.map(function(x) -x)),\n\tconjugate : function() Q([ this[0] ].concat(this.slice(1).map(function(x) -x))),\n\tadd : function(x) {\n\t if (\"number\" === typeof x) {\n\t\treturn Q([ this[0] + x ].concat(this.slice(1)));\n\t } else {\n\t\treturn Q(this.map(function(v,i) v+x[i]));\n\t }\n\t},\n\tmul : function(r) {\n\t var q = this;\n\t if (\"number\" === typeof r) {\n\t\treturn Q(q.map(function(e) e*r));\n\t } else {\n\t\treturn Q([ q[0] * r[0] - q[1] * r[1] - q[2] * r[2] - q[3] * r[3],\n\t\t\t q[0] * r[1] + q[1] * r[0] + q[2] * r[3] - q[3] * r[2],\n\t\t\t q[0] * r[2] - q[1] * r[3] + q[2] * r[0] + q[3] * r[1],\n\t\t\t q[0] * r[3] + q[1] * r[2] - q[2] * r[1] + q[3] * r[0] ]);\n\t }\n\t},\n\tequals : function(q) this.every(function(v,i) v === q[i]),\n\ttoString : function() (this[0] + \" + \" + this[1] + \"i + \"+this[2] + \"j + \" + this[3] + \"k\").replace(/\\+ -/g, '- ')\n };\n\n Quaternion.prototype = proto;\n return Quaternion;\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Queue/Definition", + "type": "Waypoint", + "description": [ + "Task:", + "

    Implement a FIFO queue.

    Elements are added at one side and popped from the other in the order of insertion.

    ", + "

    Operations:

    ", + " push (aka enqueue) - add element", + " pop (aka dequeue) - pop first element", + " empty - return truth value when empty

    Errors:

    ", + " handle the error of trying to pop from an empty queue (behavior depends on the language and platform)See:", + " Queue/Usage for the built-in FIFO or queue of your language or standard library." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Most of the time, the built-in Array suffices. However, if you explicitly want to limit the usage to FIFO operations, it's easy to implement such a constructor.", + "", + "=== Using built-in Array ===", + "var fifo = [];", + "fifo.push(42); // Enqueue.", + "fifo.push(43);", + "var x = fifo.shift(); // Dequeue.", + "alert(x); // 42", + "", + "=== Custom constructor function ===", + "function FIFO() {", + " this.data = new Array();", + "", + " this.push = function(element) {this.data.push(element)}", + " this.pop = function() {return this.data.shift()}", + " this.empty = function() {return this.data.length == 0}", + "", + " this.enqueue = this.push;", + " this.dequeue = this.pop;", + "}", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f94", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var fifo = [];\nfifo.push(42); // Enqueue.\nfifo.push(43);\nvar x = fifo.shift(); // Dequeue.\nalert(x); // 42\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Queue/Usage", + "type": "Waypoint", + "description": [ + "Task:", + "

    Create a queue data structure and demonstrate its operations.

    (For implementations of queues, see the FIFO task.)

    ", + "

    Operations:

    ", + "

    :* push (aka enqueue) - add element

    ", + "

    :* pop (aka dequeue) - pop first element

    ", + "

    :* empty - return truth value when empty

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "JavaScript arrays can be used as FIFOs.", + "var f = new Array();", + "print(f.length);", + "f.push(1,2); // can take multiple arguments", + "f.push(3);", + "f.shift();", + "f.shift();", + "print(f.length);", + "print(f.shift())", + "print(f.length == 0);", + "print(f.shift());", + "", + "outputs:", + "
    0",
    +        "1",
    +        "3",
    +        "true",
    +        "undefined
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f95", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var f = new Array();\nprint(f.length);\nf.push(1,2); // can take multiple arguments\nf.push(3);\nf.shift();\nf.shift();\nprint(f.length);\nprint(f.shift())\nprint(f.length == 0);\nprint(f.shift());\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Quickselect algorithm", + "type": "Waypoint", + "description": [ + "

    Use the quickselect algorithm on the vector

    ", + "

    [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]

    ", + "

    To show the first, second, third, ... up to the tenth largest member of the vector, in order, here on this page.

    Note: Quicksort has a separate task. " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f96", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Quine", + "type": "Waypoint", + "description": [ + "

    A Quine is a self-referential program that can,

    ", + "

    without any external access, output its own source.

    It is named after the philosopher and logician

    ", + "

    who studied self-reference and quoting in natural language,

    ", + "

    as for example in the paradox \"'Yields falsehood when preceded by its quotation' yields falsehood when preceded by its quotation.\"

    \"Source\" has one of two meanings. It can refer to the text-based program source.

    ", + "

    For languages in which program source is represented as a data structure, \"source\" may refer to the data structure: quines in these languages fall into two categories: programs which print a textual representation of themselves, or expressions which evaluate to a data structure which is equivalent to that expression.

    The usual way to code a Quine works similarly to this paradox: The program consists of two identical parts, once as plain code and once quoted in some way (for example, as a character string, or a literal data structure). The plain code then accesses the quoted code and prints it out twice, once unquoted and once with the proper quotation marks added. Often, the plain code and the quoted code have to be nested.

    ", + "Task:", + "

    Write a program that outputs its own source code in this way. If the language allows it, you may add a variant that accesses the code directly. You are not allowed to read any external files with the source code. The program should also contain some sort of self-reference, so constant expressions which return their own value which some top-level interpreter will print out. Empty programs producing no output are not allowed.

    There are several difficulties that one runs into when writing a quine, mostly dealing with quoting:

    ", + "Part of the code usually needs to be stored as a string or structural literal in the language, which needs to be quoted somehow. However, including quotation marks in the string literal itself would be troublesome because it requires them to be escaped, which then necessitates the escaping character (e.g. a backslash) in the string, which itself usually needs to be escaped, and so on.", + "* Some languages have a function for getting the \"source code representation\" of a string (i.e. adds quotation marks, etc.); in these languages, this can be used to circumvent the quoting problem.", + "* Another solution is to construct the quote character from its character code, without having to write the quote character itself. Then the character is inserted into the string at the appropriate places. The ASCII code for double-quote is 34, and for single-quote is 39.", + "Newlines in the program may have to be reproduced as newlines in the string, which usually requires some kind of escape sequence (e.g. \"\\n\"). This causes the same problem as above, where the escaping character needs to itself be escaped, etc.", + "* If the language has a way of getting the \"source code representation\", it usually handles the escaping of characters, so this is not a problem.", + "* Some languages allow you to have a string literal that spans multiple lines, which embeds the newlines into the string without escaping.", + "* Write the entire program on one line, for free-form languages (as you can see for some of the solutions here, they run off the edge of the screen), thus removing the need for newlines. However, this may be unacceptable as some languages require a newline at the end of the file; and otherwise it is still generally good style to have a newline at the end of a file. (The task is not clear on whether a newline is required at the end of the file.) Some languages have a print statement that appends a newline; which solves the newline-at-the-end issue; but others do not.", + "

    Next to the Quines presented here, many other versions can be found on the Quine page.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|SpiderMonkey}} 1.7.0", + "(function(){print(\"(\"+arguments.callee.toString().replace(/\\s/g,'')+\")()\");})()", + "", + "=== Using eval ===", + "{{works with|SpiderMonkey}} 1.7.0", + "This version doesn't use arguments.callee.toString() to return the string representation of itself. Instead, it relies on eval().", + "var code='var q=String.fromCharCode(39);print(\"var code=\"+q+code+q+\";eval(code)\")';eval(code)", + "", + "=== Replacing String ===", + "(function(){str=[\"(function(){str=[F].join(String.fromCharCode(34));str=str.replace(/F/,String.fromCharCode(34)+str+String.fromCharCode(34));console.log(str)})()\"].join(String.fromCharCode(34));str=str.replace(/F/,String.fromCharCode(34)+str+String.fromCharCode(34));console.log(str)})()", + "", + "===Another Method===", + "var a=function () {var b=\"var a=\"+a.toString()+\"\\;a()\";alert(b)};a()", + "", + "===A simple module which simply evaluates to itself===", + "", + "(function f() {", + " ", + " return '(' + f.toString() + ')();';", + " ", + "})();", + "", + "{{Out}}", + "", + "(function f() {", + "", + " return '(' + f.toString() + ')();';", + " ", + "})();", + "", + "===Or logs itself to the console===", + "(function f() {", + "", + " console.log('(' + f.toString() + ')();');", + "", + "})();", + "", + "{{Out}}", + "
    (function f() {",
    +        "",
    +        "    console.log('(' + f.toString() + ')();');",
    +        "",
    +        "})();
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f97", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function(){print(\"(\"+arguments.callee.toString().replace(/\\s/g,'')+\")()\");})()\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Random number generator (device)", + "type": "Waypoint", + "description": [ + "Task:", + "

    If your system has a means to generate random numbers involving not only a software algorithm (like the /dev/urandom devices in Unix), then:

    show how to obtain a random 32-bit number from that mechanism.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f98", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Random number generator (included)", + "type": "Waypoint", + "description": [ + "

    The task is to:

    ", + "

    State the type of random number generator algorithm used in a language's built-in random number generator. If the language or its immediate libraries don't provide a random number generator, skip this task.

    ", + "

    If possible, give a link to a wider explanation of the algorithm used.

    Note: the task is not to create an RNG, but to report on the languages in-built RNG that would be the most likely RNG used.

    The main types of pseudo-random number generator (PRNG) that are in use are the Linear Congruential Generator (LCG), and the Generalized Feedback Shift Register (GFSR), (of which the Mersenne twister generator is a subclass). The last main type is where the output of one of the previous ones (typically a Mersenne twister) is fed through a cryptographic hash function to maximize unpredictability of individual bits.

    Note that neither LCGs nor GFSRs should be used for the most demanding applications (cryptography) without additional steps.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "The only built-in random number generation facility is Math.random(), which returns a floating-point number greater than or equal to 0 and less than 1, with approximately uniform distribution. The standard (ECMA-262) does not specify what algorithm is to be used.", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f99", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "null\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Range expansion", + "type": "Waypoint", + "description": [ + "Task:", + "

    Expand the range description:

    ", + "

    -6,-3--1,3-5,7-11,14,15,17-20

    Note that the second element above,

    ", + "

    is the range from minus 3 to minus 1.

    ", + "Related task:", + " Range extraction" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Imperative (Spidermonkey)===", + "", + "#!/usr/bin/env js", + "", + "function main() {", + " print(rangeExpand('-6,-3--1,3-5,7-11,14,15,17-20'));", + "}", + "", + "function rangeExpand(rangeExpr) {", + " ", + " function getFactors(term) {", + " var matches = term.match(/(-?[0-9]+)-(-?[0-9]+)/);", + " if (!matches) return {first:Number(term)};", + " return {first:Number(matches[1]), last:Number(matches[2])};", + " }", + " ", + " function expandTerm(term) {", + " var factors = getFactors(term);", + " if (factors.length < 2) return [factors.first];", + " var range = [];", + " for (var n = factors.first; n <= factors.last; n++) {", + " range.push(n);", + " }", + " return range;", + " }", + " ", + " var result = [];", + " var terms = rangeExpr.split(/,/);", + " for (var t in terms) {", + " result = result.concat(expandTerm(terms[t]));", + " }", + " ", + " return result;", + "}", + "", + "main();", + "", + "", + "{{out}}", + " -6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20", + "", + "===Functional===", + "", + "====ES5====", + "", + "(function (strTest) {", + " 'use strict';", + "", + " // s -> [n]", + " function expansion(strExpr) {", + "", + " // concat map yields flattened output list", + " return [].concat.apply([], strExpr.split(',')", + " .map(function (x) {", + " return x.split('-')", + " .reduce(function (a, s, i, l) {", + "", + " // negative (after item 0) if preceded by an empty string", + " // (i.e. a hyphen-split artefact, otherwise ignored)", + " return s.length ? i ? a.concat(", + " parseInt(l[i - 1].length ? s :", + " '-' + s, 10)", + " ) : [+s] : a;", + " }, []);", + "", + " // two-number lists are interpreted as ranges", + " })", + " .map(function (r) {", + " return r.length > 1 ? range.apply(null, r) : r;", + " }));", + " }", + "", + "", + " // [m..n]", + " function range(m, n) {", + " return Array.apply(null, Array(n - m + 1))", + " .map(function (x, i) {", + " return m + i;", + " });", + " }", + "", + " return expansion(strTest);", + "", + "})('-6,-3--1,3-5,7-11,14,15,17-20');", + "", + "{{Out}}", + "", + "[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]", + "", + "", + "====ES6====", + "", + "(strTest => {", + " ", + " // expansion :: String -> [Int]", + " let expansion = strExpr =>", + "", + " // concat map yields flattened output list", + " [].concat.apply([], strExpr.split(',')", + " .map(x => x.split('-')", + " .reduce((a, s, i, l) =>", + "", + " // negative (after item 0) if preceded by an empty string", + " // (i.e. a hyphen-split artefact, otherwise ignored)", + " s.length ? i ? a.concat(", + " parseInt(l[i - 1].length ? s :", + " '-' + s, 10)", + " ) : [+s] : a, [])", + "", + " // two-number lists are interpreted as ranges", + " )", + " .map(r => r.length > 1 ? range.apply(null, r) : r)),", + "", + "", + "", + " // range :: Int -> Int -> Maybe Int -> [Int]", + " range = (m, n, step) => {", + " let d = (step || 1) * (n >= m ? 1 : -1);", + "", + " return Array.from({", + " length: Math.floor((n - m) / d) + 1", + " }, (_, i) => m + (i * d));", + " };", + "", + "", + "", + " return expansion(strTest);", + "", + "})('-6,-3--1,3-5,7-11,14,15,17-20');", + "", + "{{Out}}", + "[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f9b", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "#!/usr/bin/env js\n\nfunction main() {\n print(rangeExpand('-6,-3--1,3-5,7-11,14,15,17-20'));\n}\n\nfunction rangeExpand(rangeExpr) {\n \n function getFactors(term) {\n var matches = term.match(/(-?[0-9]+)-(-?[0-9]+)/);\n if (!matches) return {first:Number(term)};\n return {first:Number(matches[1]), last:Number(matches[2])};\n }\n \n function expandTerm(term) {\n var factors = getFactors(term);\n if (factors.length < 2) return [factors.first];\n var range = [];\n for (var n = factors.first; n <= factors.last; n++) {\n range.push(n);\n }\n return range;\n }\n \n var result = [];\n var terms = rangeExpr.split(/,/);\n for (var t in terms) {\n result = result.concat(expandTerm(terms[t]));\n }\n \n return result;\n}\n\nmain();\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Range extraction", + "type": "Waypoint", + "description": [ + "Task:", + "Create a function that takes a list of integers in increasing order and returns a correctly formatted string in the range format. ", + "Use the function to compute and print the range formatted version of the following ordered list of integers. (The correct answer is: 0-2,4,6-8,11,12,14-25,27-33,35-39.)", + "

    0, 1, 2, 4, 6, 7, 8, 11, 12, 14,

    ", + "

    15, 16, 17, 18, 19, 20, 21, 22, 23, 24,

    ", + "

    25, 27, 28, 29, 30, 31, 32, 33, 35, 36,

    ", + "

    37, 38, 39

    ", + "Show the output of your program.Related task:", + " Range expansion" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "====Imperative====", + "function rangeExtraction(list) {", + " var len = list.length;", + " var out = [];", + " var i, j;", + "", + " for (i = 0; i < len; i = j + 1) {", + " // beginning of range or single", + " out.push(list[i]);", + " ", + " // find end of range", + " for (var j = i + 1; j < len && list[j] == list[j-1] + 1; j++);", + " j--;", + " ", + " if (i == j) {", + " // single number", + " out.push(\",\");", + " } else if (i + 1 == j) {", + " // two numbers", + " out.push(\",\", list[j], \",\");", + " } else { ", + " // range", + " out.push(\"-\", list[j], \",\");", + " }", + " }", + " out.pop(); // remove trailing comma", + " return out.join(\"\");", + "}", + "", + "// using print function as supplied by Rhino standalone", + "print(rangeExtraction([", + " 0, 1, 2, 4, 6, 7, 8, 11, 12, 14,", + " 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,", + " 25, 27, 28, 29, 30, 31, 32, 33, 35, 36,", + " 37, 38, 39", + "]));", + "", + "====Functional====", + "{{Trans|ES6}}", + "{{Trans|Haskell}}", + "(function () {", + " 'use strict';", + "", + " // rangeFormat :: [Int] -> String", + " var rangeFormat = function (xs) {", + " return splitBy(function (a, b) {", + " return b - a > 1;", + " }, xs)", + " .map(rangeString)", + " .join(',');", + " };", + "", + " // rangeString :: [Int] -> String", + " var rangeString = function (xs) {", + " return xs.length > 2 ? [head(xs), last(xs)].map(show)", + " .join('-') : xs.join(',');", + " };", + "", + " // GENERIC FUNCTIONS", + "", + " // Splitting not on a delimiter, but whenever the relationship between", + " // two consecutive items matches a supplied predicate function", + "", + " // splitBy :: (a -> a -> Bool) -> [a] -> [[a]]", + " var splitBy = function (f, xs) {", + " if (xs.length < 2) return [xs];", + " var h = head(xs),", + " lstParts = xs.slice(1)", + " .reduce(function (a, x) {", + " var acc = a[0],", + " active = a[1],", + " prev = a[2];", + "", + " return f(prev, x) ? (", + " [acc.concat([active]), [x], x]", + " ) : [acc, active.concat(x), x];", + " }, [", + " [],", + " [h], h", + " ]);", + " return lstParts[0].concat([lstParts[1]]);", + " };", + "", + " // head :: [a] -> a", + " var head = function (xs) {", + " return xs.length ? xs[0] : undefined;", + " };", + "", + " // last :: [a] -> a", + " var last = function (xs) {", + " return xs.length ? xs.slice(-1)[0] : undefined;", + " };", + "", + " // show :: a -> String", + " var show = function (x) {", + " return JSON.stringify(x);", + " };", + "", + " // TEST", + " return rangeFormat([0, 1, 2, 4, 6, 7, 8, 11, 12, 14, 15, 16,", + " 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32,", + " 33, 35, 36, 37, 38, 39", + " ]);", + "})();", + "", + "{{Out}}", + "
    \"0-2,4,6-8,11,12,14-25,27-33,35-39\"
    ", + "", + "===ES6===", + "{{Trans|Haskell}}", + "Defining the range format in terms of a reusable '''splitBy''' function:", + "(() => {", + " 'use strict';", + "", + " // rangeFormat :: [Int] -> String", + " const rangeFormat = xs =>", + " splitBy((a, b) => b - a > 1, xs)", + " .map(rangeString)", + " .join(',');", + "", + " // rangeString :: [Int] -> String", + " const rangeString = xs =>", + " xs.length > 2 ? (", + " [head(xs), last(xs)].map(show)", + " .join('-')", + " ) : xs.join(',')", + "", + "", + " // GENERIC FUNCTIONS", + "", + " // Splitting not on a delimiter, but whenever the relationship between", + " // two consecutive items matches a supplied predicate function", + "", + " // splitBy :: (a -> a -> Bool) -> [a] -> [[a]]", + " const splitBy = (f, xs) => {", + " if (xs.length < 2) return [xs];", + " const", + " h = head(xs),", + " lstParts = xs.slice(1)", + " .reduce(([acc, active, prev], x) =>", + " f(prev, x) ? (", + " [acc.concat([active]), [x], x]", + " ) : [acc, active.concat(x), x], [", + " [],", + " [h],", + " h", + " ]);", + " return lstParts[0].concat([lstParts[1]]);", + " };", + "", + " // head :: [a] -> a", + " const head = xs => xs.length ? xs[0] : undefined;", + "", + " // last :: [a] -> a", + " const last = xs => xs.length ? xs.slice(-1)[0] : undefined;", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x);", + "", + " // TEST", + " return rangeFormat([0, 1, 2, 4, 6, 7, 8, 11, 12, 14,", + " 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,", + " 25, 27, 28, 29, 30, 31, 32, 33, 35, 36,", + " 37, 38, 39", + " ]);", + "})();", + "{{Out}}", + "
    0-2,4,6-8,11,12,14-25,27-33,35-39
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f9c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function rangeExtraction(list) {\n var len = list.length;\n var out = [];\n var i, j;\n\n for (i = 0; i < len; i = j + 1) {\n // beginning of range or single\n out.push(list[i]);\n \n // find end of range\n for (var j = i + 1; j < len && list[j] == list[j-1] + 1; j++);\n j--;\n \n if (i == j) {\n // single number\n out.push(\",\");\n } else if (i + 1 == j) {\n // two numbers\n out.push(\",\", list[j], \",\");\n } else { \n // range\n out.push(\"-\", list[j], \",\");\n }\n }\n out.pop(); // remove trailing comma\n return out.join(\"\");\n}\n\n// using print function as supplied by Rhino standalone\nprint(rangeExtraction([\n 0, 1, 2, 4, 6, 7, 8, 11, 12, 14,\n 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\n 25, 27, 28, 29, 30, 31, 32, 33, 35, 36,\n 37, 38, 39\n]));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Ranking methods", + "type": "Waypoint", + "description": [ + "

    The numerical rank of competitors in a competition shows if one is better than, equal to, or worse than another based on their results in a competition.

    The numerical rank of a competitor can be assigned in several different ways.

    ", + "Task:", + "

    The following scores are accrued for all competitors of a competition (in best-first order):

    ", + "
    44 Solomon",
    +        "42 Jason",
    +        "42 Errol",
    +        "41 Garry",
    +        "41 Bernard",
    +        "41 Barry",
    +        "39 Stephen

    For each of the following ranking methods, create a function/method/procedure/subroutine... that applies the ranking method to an ordered list of scores with scorers:

    ", + "Standard. (Ties share what would have been their first ordinal number).", + "Modified. (Ties share what would have been their last ordinal number).", + "Dense. (Ties share the next available integer). ", + "Ordinal. ((Competitors take the next available integer. Ties are not treated otherwise).", + "Fractional. (Ties share the mean of what would have been their ordinal numbers).", + "

    See the wikipedia article for a fuller description.

    Show here, on this page, the ranking of the test scores under each of the numbered ranking methods.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "The task formulation doesn't seem to directly explain or determine the order of listing for players whose score is the same.", + "", + "( This version chooses to use a secondary (alphabetic) sort after the numeric sort by score. That does, of course, affect the ordinal placements for some players)", + "", + "(function () {", + " ", + " var xs = 'Solomon Jason Errol Garry Bernard Barry Stephen'.split(' '),", + " ns = [44, 42, 42, 41, 41, 41, 39],", + " ", + " sorted = xs.map(function (x, i) {", + " return { name: x, score: ns[i] };", + " }).sort(function (a, b) {", + " var c = b.score - a.score;", + " return c ? c : a.name < b.name ? -1 : a.name > b.name ? 1 : 0;", + " }),", + " ", + " names = sorted.map(function (x) { return x.name; }),", + " scores = sorted.map(function (x) { return x.score; }),", + " ", + " reversed = scores.slice(0).reverse(),", + " unique = scores.filter(function (x, i) {", + " return scores.indexOf(x) === i;", + " });", + " ", + " // RANKINGS AS FUNCTIONS OF SCORES: SORTED, REVERSED AND UNIQUE", + " ", + " var rankings = function (score, index) {", + " return {", + " name: names[index],", + " score: score,", + "", + " Ordinal: index + 1,", + "", + " Standard: function (n) {", + " return scores.indexOf(n) + 1;", + " }(score),", + "", + " Modified: function (n) {", + " return reversed.length - reversed.indexOf(n);", + " }(score),", + "", + " Dense: function (n) {", + " return unique.indexOf(n) + 1;", + " }(score),", + "", + " Fractional: function (n) {", + " return (", + " (scores.indexOf(n) + 1) +", + " (reversed.length - reversed.indexOf(n))", + " ) / 2;", + " }(score)", + " };", + " },", + " ", + " tbl = [", + " 'Name Score Standard Modified Dense Ordinal Fractional'.split(' ')", + " ].concat(scores.map(rankings).reduce(function (a, x) {", + " return a.concat([", + " [x.name, x.score,", + " x.Standard, x.Modified, x.Dense, x.Ordinal, x.Fractional", + " ]", + " ]);", + " }, [])),", + " ", + " //[[a]] -> bool -> s -> s", + " wikiTable = function (lstRows, blnHeaderRow, strStyle) {", + " return '{| class=\"wikitable\" ' + (", + " strStyle ? 'style=\"' + strStyle + '\"' : ''", + " ) + lstRows.map(function (lstRow, iRow) {", + " var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|');", + " ", + " return '\\n|-\\n' + strDelim + ' ' + lstRow.map(function (v) {", + " return typeof v === 'undefined' ? ' ' : v;", + " }).join(' ' + strDelim + strDelim + ' ');", + " }).join('') + '\\n|}';", + " };", + " ", + " return wikiTable(tbl, true, 'text-align:center');", + " ", + "})();", + "", + "{{out}}", + "", + "{| class=\"wikitable\" style=\"text-align:center\"", + "|-", + "! Name !! Score !! Standard !! Modified !! Dense !! Ordinal !! Fractional", + "|-", + "| Solomon || 44 || 1 || 1 || 1 || 1 || 1", + "|-", + "| Errol || 42 || 2 || 3 || 2 || 2 || 2.5", + "|-", + "| Jason || 42 || 2 || 3 || 2 || 3 || 2.5", + "|-", + "| Barry || 41 || 4 || 6 || 3 || 4 || 5", + "|-", + "| Bernard || 41 || 4 || 6 || 3 || 5 || 5", + "|-", + "| Garry || 41 || 4 || 6 || 3 || 6 || 5", + "|-", + "| Stephen || 39 || 7 || 7 || 4 || 7 || 7", + "|}", + "", + "===ES6===", + "", + "((() => {", + " const xs = 'Solomon Jason Errol Garry Bernard Barry Stephen'.split(' '),", + " ns = [44, 42, 42, 41, 41, 41, 39];", + "", + " const sorted = xs.map((x, i) => ({", + " name: x,", + " score: ns[i]", + " }))", + " .sort((a, b) => {", + " const c = b.score - a.score;", + " return c ? c : a.name < b.name ? -1 : a.name > b.name ? 1 : 0;", + " });", + "", + " const names = sorted.map(x => x.name),", + " scores = sorted.map(x => x.score),", + " reversed = scores.slice(0)", + " .reverse(),", + " unique = scores.filter((x, i) => scores.indexOf(x) === i);", + "", + " // RANKINGS AS FUNCTIONS OF SCORES: SORTED, REVERSED AND UNIQUE", + "", + " // rankings :: Int -> Int -> Dictonary", + " const rankings = (score, index) => ({", + " name: names[index],", + " score,", + " Ordinal: index + 1,", + " Standard: scores.indexOf(score) + 1,", + " Modified: reversed.length - reversed.indexOf(score),", + " Dense: unique.indexOf(score) + 1,", + "", + " Fractional: (n => (", + " (scores.indexOf(n) + 1) +", + " (reversed.length - reversed.indexOf(n))", + " ) / 2)(score)", + " });", + "", + " // tbl :: [[[a]]]", + " const tbl = [", + " 'Name Score Standard Modified Dense Ordinal Fractional'.split(' ')", + " ].concat(scores.map(rankings)", + " .reduce((a, x) => a.concat([", + " [x.name, x.score,", + " x.Standard, x.Modified, x.Dense, x.Ordinal, x.Fractional", + " ]", + " ]), []));", + "", + " // wikiTable :: [[[a]]] -> Bool -> String -> String", + " const wikiTable = (lstRows, blnHeaderRow, strStyle) =>", + " `{| class=\"wikitable\" ${strStyle ? 'style=\"' + strStyle + '\"' : ''}", + " ${lstRows.map((lstRow, iRow) => {", + " const strDelim = ((blnHeaderRow && !iRow) ? '!' : '|');", + "", + " return '\\n|-\\n' + strDelim + ' ' + lstRow", + " .map(v => typeof v === 'undefined' ? ' ' : v)", + " .join(' ' + strDelim + strDelim + ' ');", + " }).join('')}\\n|}`;", + "", + " return wikiTable(tbl, true, 'text-align:center');", + "}))();", + "", + "{| class=\"wikitable\" style=\"text-align:center\"", + " ", + "|-", + "! Name !! Score !! Standard !! Modified !! Dense !! Ordinal !! Fractional", + "|-", + "| Solomon || 44 || 1 || 1 || 1 || 1 || 1", + "|-", + "| Errol || 42 || 2 || 3 || 2 || 2 || 2.5", + "|-", + "| Jason || 42 || 2 || 3 || 2 || 3 || 2.5", + "|-", + "| Barry || 41 || 4 || 6 || 3 || 4 || 5", + "|-", + "| Bernard || 41 || 4 || 6 || 3 || 5 || 5", + "|-", + "| Garry || 41 || 4 || 6 || 3 || 6 || 5", + "|-", + "| Stephen || 39 || 7 || 7 || 4 || 7 || 7", + "|}", + "{{Out}}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f9d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function () {\n \n var xs = 'Solomon Jason Errol Garry Bernard Barry Stephen'.split(' '),\n ns = [44, 42, 42, 41, 41, 41, 39],\n \n sorted = xs.map(function (x, i) {\n return { name: x, score: ns[i] };\n }).sort(function (a, b) {\n var c = b.score - a.score;\n return c ? c : a.name < b.name ? -1 : a.name > b.name ? 1 : 0;\n }),\n \n names = sorted.map(function (x) { return x.name; }),\n scores = sorted.map(function (x) { return x.score; }),\n \n reversed = scores.slice(0).reverse(),\n unique = scores.filter(function (x, i) {\n return scores.indexOf(x) === i;\n });\n \n // RANKINGS AS FUNCTIONS OF SCORES: SORTED, REVERSED AND UNIQUE\n \n var rankings = function (score, index) {\n return {\n name: names[index],\n score: score,\n\n Ordinal: index + 1,\n\n Standard: function (n) {\n return scores.indexOf(n) + 1;\n }(score),\n\n Modified: function (n) {\n return reversed.length - reversed.indexOf(n);\n }(score),\n\n Dense: function (n) {\n return unique.indexOf(n) + 1;\n }(score),\n\n Fractional: function (n) {\n return (\n (scores.indexOf(n) + 1) +\n (reversed.length - reversed.indexOf(n))\n ) / 2;\n }(score)\n };\n },\n \n tbl = [\n 'Name Score Standard Modified Dense Ordinal Fractional'.split(' ')\n ].concat(scores.map(rankings).reduce(function (a, x) {\n return a.concat([\n [x.name, x.score,\n x.Standard, x.Modified, x.Dense, x.Ordinal, x.Fractional\n ]\n ]);\n }, [])),\n \n //[[a]] -> bool -> s -> s\n wikiTable = function (lstRows, blnHeaderRow, strStyle) {\n return '{| class=\"wikitable\" ' + (\n strStyle ? 'style=\"' + strStyle + '\"' : ''\n ) + lstRows.map(function (lstRow, iRow) {\n var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|');\n \n return '\\n|-\\n' + strDelim + ' ' + lstRow.map(function (v) {\n return typeof v === 'undefined' ? ' ' : v;\n }).join(' ' + strDelim + strDelim + ' ');\n }).join('') + '\\n|}';\n };\n \n return wikiTable(tbl, true, 'text-align:center');\n \n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Rate counter", + "type": "Waypoint", + "description": [ + "

    Counting the frequency at which something occurs is a common activity in measuring performance and managing resources. In this task, we assume that there is some job which we want to perform repeatedly, and we want to know how quickly these jobs are being performed.

    Of interest is the code that performs the actual measurements. Any other code (such as job implementation or dispatching) that is required to demonstrate the rate tracking is helpful, but not the focus.

    Multiple approaches are allowed (even preferable), so long as they can accomplish these goals:

    Run N seconds worth of jobs and/or Y jobs.", + "Report at least three distinct times.", + "Be aware of the precision and accuracy limitations of your timing mechanisms, and document them if you can.

    See also: System time, Time a function

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "The ''benchmark'' function below executes a given function n times, calling it with the specified arguments. After execution of all functions, it returns an array with the execution time of each execution, in milliseconds.", + "", + "function millis() { // Gets current time in milliseconds.", + " return (new Date()).getTime();", + "}", + "", + "/* Executes function 'func' n times, returns array of execution times. */", + "function benchmark(n, func, args) {", + " var times = [];", + " for (var i=0; i", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f9e", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function millis() { // Gets current time in milliseconds.\n return (new Date()).getTime();\n}\n\n/* Executes function 'func' n times, returns array of execution times. */\nfunction benchmark(n, func, args) {\n var times = [];\n for (var i=0; ireplaceMe is a function.');" + ] + }, + { + "title": "Ray-casting algorithm", + "type": "Waypoint", + "description": [ + "

    Given a point and a polygon, check if the point is inside or outside the polygon using the ray-casting algorithm.

    A pseudocode can be simply:

    count ← 0

    ", + "

    foreach side in polygon:

    ", + "

    if ray_intersects_segment(P,side) then

    ", + "

    count ← count + 1

    ", + "

    if is_odd(count) then

    ", + "

    return inside

    ", + "

    else

    ", + "

    return outside

    Where the function ray_intersects_segment return true if the horizontal ray starting from the point P intersects the side (segment), false otherwise.

    An intuitive explanation of why it works is that every time we cross

    ", + "

    a border, we change \"country\" (inside-outside, or outside-inside), but

    ", + "

    the last \"country\" we land on is surely outside (since the inside of the polygon is finite, while the ray continues towards infinity). So, if we crossed an odd number of borders we were surely inside, otherwise we were outside; we can follow the ray backward to see it better: starting from outside, only an odd number of crossing can give an inside: outside-inside, outside-inside-outside-inside, and so on (the - represents the crossing of a border).

    So the main part of the algorithm is how we determine if a ray intersects a segment. The following text explain one of the possible ways.

    200px|thumb|right

    ", + "

    Looking at the image on the right, we can easily be convinced of the fact that rays starting from points in the hatched area (like P1 and P2) surely do not intersect the segment AB. We also can easily see that rays starting from points in the greenish area surely intersect the segment AB (like point P3).

    So the problematic points are those inside the white area (the box delimited by the points A and B), like P4.

    128px|thumb|right

    ", + "

    128px|thumb|right

    Let us take into account a segment AB (the point A having y coordinate always smaller than B's y coordinate, i.e. point A is always below point B) and a point P. Let us use the cumbersome notation PAX to denote the angle between segment AP and AX, where X is always a point on the horizontal line passing by A with x coordinate bigger than the maximum between the x coordinate of A and the x coordinate of B. As explained graphically by the figures on the right, if PAX is greater than the angle BAX, then the ray starting from P intersects the segment AB. (In the images, the ray starting from PA does not intersect the segment, while the ray starting from PB in the second picture, intersects the segment).

    Points on the boundary or \"on\" a vertex are someway special and through this approach we do not obtain coherent results. They could be treated apart, but it is not necessary to do so.

    An algorithm for the previous speech could be (if P is a point, Px is its x coordinate):

    ray_intersects_segment:

    ", + "

    P : the point from which the ray starts

    ", + "

    A : the end-point of the segment with the smallest y coordinate

    ", + "

    (A must be \"below\" B)

    ", + "

    B : the end-point of the segment with the greatest y coordinate

    ", + "

    (B must be \"above\" A)

    ", + "

    if Py = Ay or Py = By then

    ", + "

    Py ← Py + ε

    ", + "

    end if

    ", + "

    if Py < Ay or Py > By then

    ", + "

    return false

    ", + "

    else if Px > max(Ax, Bx) then

    ", + "

    return false

    ", + "

    else

    ", + "

    if Px < min(Ax, Bx) then

    ", + "

    return true

    ", + "

    else

    ", + "

    if Ax ≠ Bx then

    ", + "

    m_red ← (By - Ay)/(Bx - Ax)

    ", + "

    else

    ", + "

    m_red ← ∞

    ", + "

    end if

    ", + "

    if Ax ≠ Px then

    ", + "

    m_blue ← (Py - Ay)/(Px - Ax)

    ", + "

    else

    ", + "

    m_blue ← ∞

    ", + "

    end if

    ", + "

    if m_blue ≥ m_red then

    ", + "

    return true

    ", + "

    else

    ", + "

    return false

    ", + "

    end if

    ", + "

    end if

    ", + "

    end if

    (To avoid the \"ray on vertex\" problem, the point is moved upward of a small quantity ε.)

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7f9f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "RCRPG", + "type": "Waypoint", + "description": [ + "

    Create a simple interactive game which incorporates the following features:

    room-based navigation in three integer dimensions (x,y,z)", + "player inventory", + "three types of item: sledge, gold and ladder", + "a goal coordinate", + "

    Use of the sledge should be required to create a passage between rooms. The ladder should be present in a room (but not held by the player), in order for the player to access the room above him. The gold need not have a function.

    This project is based on this blog post by Michael Mol, and the Perl version comes from there.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fa0", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Real constants and functions", + "type": "Waypoint", + "description": [ + "Task:", + "

    Show how to use the following math constants and functions in your language (if not available, note it):

    ", + "

    * e (base of the natural logarithm)

    ", + "

    * $\\pi$

    ", + "

    * square root

    ", + "

    * logarithm (any base allowed)

    ", + "

    * exponential (ex )

    ", + "

    * absolute value (a.k.a. \"magnitude\")

    ", + "

    * floor (largest integer less than or equal to this number--not the same as truncate or int)

    ", + "

    * ceiling (smallest integer not less than this number--not the same as round up)

    ", + "

    * power (xy )

    ", + "Related task:", + " Trigonometric Functions" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Math.E", + "Math.PI", + "Math.sqrt(x)", + "Math.log(x)", + "Math.exp(x)", + "Math.abs(x)", + "Math.floor(x)", + "Math.ceil(x)", + "Math.pow(x,y)", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fa5", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "Math.E\nMath.PI\nMath.sqrt(x)\nMath.log(x)\nMath.exp(x)\nMath.abs(x)\nMath.floor(x)\nMath.ceil(x)\nMath.pow(x,y)\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Reduced row echelon form", + "type": "Waypoint", + "description": [ + "

    Show how to compute the reduced row echelon form

    ", + "

    (a.k.a. row canonical form) of a matrix.

    The matrix can be stored in any datatype that is convenient

    ", + "

    (for most languages, this will probably be a two-dimensional array).

    Built-in functions or this pseudocode (from Wikipedia) may be used:

    ", + "

    function ToReducedRowEchelonForm(Matrix M) is

    ", + "

    lead := 0

    ", + "

    rowCount := the number of rows in M

    ", + "

    columnCount := the number of columns in M

    ", + "

    for 0 ≤ r < rowCount do

    ", + "

    if columnCount ≤ lead then

    ", + "

    stop

    ", + "

    end if

    ", + "

    i = r

    ", + "

    while M[i, lead] = 0 do

    ", + "

    i = i + 1

    ", + "

    if rowCount = i then

    ", + "

    i = r

    ", + "

    lead = lead + 1

    ", + "

    if columnCount = lead then

    ", + "

    stop

    ", + "

    end if

    ", + "

    end if

    ", + "

    end while

    ", + "

    Swap rows i and r

    ", + "

    If M[r, lead] is not 0 divide row r by M[r, lead]

    ", + "

    for 0 ≤ i < rowCount do

    ", + "

    if i ≠ r do

    ", + "

    Subtract M[i, lead] multiplied by row r from row i

    ", + "

    end if

    ", + "

    end for

    ", + "

    lead = lead + 1

    ", + "

    end for

    ", + "

    end function

    For testing purposes, the RREF of this matrix:

    ", + "
    1   2   -1   -4",
    +        "2   3   -1   -11",
    +        "-2   0   -3   22
    ", + "

    is:

    ", + "
    1   0   0   -8",
    +        "0   1   0   1",
    +        "0   0   1   -2
    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|SpiderMonkey}} for the print() function.", + "Extends the Matrix class defined at [[Matrix Transpose#JavaScript]]", + "// modifies the matrix in-place", + "Matrix.prototype.toReducedRowEchelonForm = function() {", + " var lead = 0;", + " for (var r = 0; r < this.rows(); r++) {", + " if (this.columns() <= lead) {", + " return;", + " }", + " var i = r;", + " while (this.mtx[i][lead] == 0) {", + " i++;", + " if (this.rows() == i) {", + " i = r;", + " lead++;", + " if (this.columns() == lead) {", + " return;", + " }", + " }", + " }", + "", + " var tmp = this.mtx[i];", + " this.mtx[i] = this.mtx[r];", + " this.mtx[r] = tmp;", + "", + " var val = this.mtx[r][lead];", + " for (var j = 0; j < this.columns(); j++) {", + " this.mtx[r][j] /= val;", + " }", + "", + " for (var i = 0; i < this.rows(); i++) {", + " if (i == r) continue;", + " val = this.mtx[i][lead];", + " for (var j = 0; j < this.columns(); j++) {", + " this.mtx[i][j] -= val * this.mtx[r][j];", + " }", + " }", + " lead++;", + " }", + " return this;", + "}", + "", + "var m = new Matrix([", + " [ 1, 2, -1, -4],", + " [ 2, 3, -1,-11],", + " [-2, 0, -3, 22]", + "]);", + "print(m.toReducedRowEchelonForm());", + "print();", + "", + "m = new Matrix([", + " [ 1, 2, 3, 7],", + " [-4, 7,-2, 7],", + " [ 3, 3, 0, 7]", + "]);", + "print(m.toReducedRowEchelonForm());", + "{{out}}", + "
    1,0,0,-8",
    +        "0,1,0,1",
    +        "0,0,1,-2",
    +        "",
    +        "1,0,0,0.6666666666666663",
    +        "0,1,0,1.666666666666667",
    +        "0,0,1,1
    ", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fa7", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// modifies the matrix in-place\nMatrix.prototype.toReducedRowEchelonForm = function() {\n var lead = 0;\n for (var r = 0; r < this.rows(); r++) {\n if (this.columns() <= lead) {\n return;\n }\n var i = r;\n while (this.mtx[i][lead] == 0) {\n i++;\n if (this.rows() == i) {\n i = r;\n lead++;\n if (this.columns() == lead) {\n return;\n }\n }\n }\n\n var tmp = this.mtx[i];\n this.mtx[i] = this.mtx[r];\n this.mtx[r] = tmp;\n\n var val = this.mtx[r][lead];\n for (var j = 0; j < this.columns(); j++) {\n this.mtx[r][j] /= val;\n }\n\n for (var i = 0; i < this.rows(); i++) {\n if (i == r) continue;\n val = this.mtx[i][lead];\n for (var j = 0; j < this.columns(); j++) {\n this.mtx[i][j] -= val * this.mtx[r][j];\n }\n }\n lead++;\n }\n return this;\n}\n\nvar m = new Matrix([\n [ 1, 2, -1, -4],\n [ 2, 3, -1,-11],\n [-2, 0, -3, 22]\n]);\nprint(m.toReducedRowEchelonForm());\nprint();\n\nm = new Matrix([\n [ 1, 2, 3, 7],\n [-4, 7,-2, 7],\n [ 3, 3, 0, 7]\n]);\nprint(m.toReducedRowEchelonForm());\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Regular expressions", + "type": "Waypoint", + "description": [ + "

    The goal of this task is

    ", + "to match a string against a regular expression", + "to substitute part of a string using a regular expression" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Test/Match", + "var subject = \"Hello world!\";", + "", + "// Two different ways to create the RegExp object", + "// Both examples use the exact same pattern... matching \"hello \"", + "var re_PatternToMatch = /Hello (World)/i; // creates a RegExp literal with case-insensitivity", + "var re_PatternToMatch2 = new RegExp(\"Hello (World)\", \"i\");", + "", + "// Test for a match - return a bool", + "var isMatch = re_PatternToMatch.test(subject);", + "", + "// Get the match details", + "// Returns an array with the match's details", + "// matches[0] == \"Hello world\"", + "// matches[1] == \"world\"", + "var matches = re_PatternToMatch2.exec(subject);", + "", + "Substitute", + "var subject = \"Hello world!\";", + "", + "// Perform a string replacement", + "// newSubject == \"Replaced!\"", + "var newSubject = subject.replace(re_PatternToMatch, \"Replaced\");", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fab", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var subject = \"Hello world!\";\n\n// Two different ways to create the RegExp object\n// Both examples use the exact same pattern... matching \"hello \"\nvar re_PatternToMatch = /Hello (World)/i; // creates a RegExp literal with case-insensitivity\nvar re_PatternToMatch2 = new RegExp(\"Hello (World)\", \"i\");\n\n// Test for a match - return a bool\nvar isMatch = re_PatternToMatch.test(subject);\n\n// Get the match details\n// Returns an array with the match's details\n// matches[0] == \"Hello world\"\n// matches[1] == \"world\"\nvar matches = re_PatternToMatch2.exec(subject);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Remove duplicate elements", + "type": "Waypoint", + "description": [ + "

    Given an Array, derive a sequence of elements in which all duplicates are removed.

    There are basically three approaches seen here:

    ", + "Put the elements into a hash table which does not allow duplicates. The complexity is O(n) on average, and O(n2) worst case. This approach requires a hash function for your type (which is compatible with equality), either built-in to your language, or provided by the user.", + "Sort the elements and remove consecutive duplicate elements. The complexity of the best sorting algorithms is O(n log n). This approach requires that your type be \"comparable\", i.e., have an ordering. Putting the elements into a self-balancing binary search tree is a special case of sorting.", + "Go through the list, and for each element, check the rest of the list to see if it appears again, and discard it if it does. The complexity is O(n2). The up-shot is that this always works on any type (provided that you can test for equality)." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "This uses the === \"strict equality\" operator, which does no type conversions (4 == \"4\" is true but 4 === \"4\" is false)", + "function unique(ary) {", + " // concat() with no args is a way to clone an array", + " var u = ary.concat().sort();", + " for (var i = 1; i < u.length; ) {", + " if (u[i-1] === u[i])", + " u.splice(i,1);", + " else", + " i++;", + " }", + " return u;", + "}", + "", + "var ary = [1, 2, 3, \"a\", \"b\", \"c\", 2, 3, 4, \"b\", \"c\", \"d\", \"4\"];", + "var uniq = unique(ary);", + "for (var i = 0; i < uniq.length; i++) ", + " print(uniq[i] + \"\\t\" + typeof(uniq[i]));", + "
    1 - number",
    +        "2 - number",
    +        "3 - number",
    +        "4 - number",
    +        "4 - string",
    +        "a - string",
    +        "b - string",
    +        "c - string",
    +        "d - string
    ", + "", + "Or, extend the prototype for Array:", + "Array.prototype.unique = function() {", + " var u = this.concat().sort();", + " for (var i = 1; i < u.length; ) {", + " if (u[i-1] === u[i])", + " u.splice(i,1);", + " else", + " i++;", + " }", + " return u;", + "}", + "var uniq = [1, 2, 3, \"a\", \"b\", \"c\", 2, 3, 4, \"b\", \"c\", \"d\"].unique();", + "", + "With reduce and arrow functions (ES6):", + "Array.prototype.unique = function() {", + " return this.sort().reduce( (a,e) => e === a[a.length-1] ? a : (a.push(e), a), [] )", + "}", + "", + "With sets and spread operator (ES6):", + "Array.prototype.unique = function() {", + " return [... new Set(this)]", + "}", + "", + "If, however, the array is homogenous, or we wish to interpret it as such by using JavaScript's Abstract Equality comparison (as in '==', see http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3) then it proves significantly faster to use a hash table.", + "", + "For example, in ES 5:", + "", + "function uniq(lst) {", + " var u = [],", + " dct = {},", + " i = lst.length,", + " v;", + "", + " while (i--) {", + " v = lst[i], dct[v] || (", + " dct[v] = u.push(v)", + " );", + " }", + " u.sort(); // optional", + " ", + " return u;", + "}", + "", + "Or, to allow for customised definitions of equality and duplication, we can follow the Haskell prelude in defining a '''nub :: [a] -> [a] function''' which is a special case of '''nubBy :: (a -> a -> Bool) -> [a] -> [a]'''", + "", + "{{trans|Haskell}}", + "", + "(function () {", + " 'use strict';", + "", + " // nub :: [a] -> [a]", + " function nub(xs) {", + "", + " // Eq :: a -> a -> Bool", + " function Eq(a, b) {", + " return a === b;", + " }", + "", + " // nubBy :: (a -> a -> Bool) -> [a] -> [a]", + " function nubBy(fnEq, xs) {", + " var x = xs.length ? xs[0] : undefined;", + "", + " return x !== undefined ? [x].concat(", + " nubBy(fnEq, xs.slice(1)", + " .filter(function (y) {", + " return !fnEq(x, y);", + " }))", + " ) : [];", + " }", + "", + " return nubBy(Eq, xs);", + " }", + "", + "", + " // TEST", + " ", + " return [", + " nub('4 3 2 8 0 1 9 5 1 7 6 3 9 9 4 2 1 5 3 2'.split(' '))", + " .map(function (x) {", + " return Number(x);", + " }),", + " nub('chthonic eleemosynary paronomasiac'.split(''))", + " .join('')", + " ]", + "", + "})();", + "", + "{{Out}}", + "", + "
    [[4, 3, 2, 8, 0, 1, 9, 5, 7, 6], \"chtoni elmsyarp\"]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fac", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function unique(ary) {\n // concat() with no args is a way to clone an array\n var u = ary.concat().sort();\n for (var i = 1; i < u.length; ) {\n if (u[i-1] === u[i])\n u.splice(i,1);\n else\n i++;\n }\n return u;\n}\n\nvar ary = [1, 2, 3, \"a\", \"b\", \"c\", 2, 3, 4, \"b\", \"c\", \"d\", \"4\"];\nvar uniq = unique(ary);\nfor (var i = 0; i < uniq.length; i++) \n print(uniq[i] + \"\\t\" + typeof(uniq[i]));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Rendezvous", + "type": "Waypoint", + "description": [ + "

    Demonstrate the “rendezvous” communications technique by implementing a printer monitor.

    ", + "

    ==Detailed Description of Programming Task==

    ", + "

    Rendezvous is a synchronization mechanism based on procedural decomposition. Rendezvous is similar to a procedure call with the difference that the caller and the callee belong to different tasks. The called procedure is usually called an entry point of the corresponding task. A call to an entry point is synchronous, i.e. the caller is blocked until completion. For the caller a call to the entry point is indivisible. Internally it consists of:

    Waiting for the callee ready to accept the rendezvous;", + "Engaging the rendezvous (servicing the entry point).", + "

    The caller may limit the waiting time to the callee to accept the rendezvous. I.e. a rendezvous request can be aborted if not yet accepted by the callee. When accepted the rendezvous is processed until its completion. During this time the caller and the callee tasks stay synchronized. Which context is used to process the rendezvous depends on the implementation which may wish to minimize context switching.

    The callee task may accept several rendezvous requests:

    Rendezvous to the same entry point from different tasks;", + "Rendezvous to different entry points.", + "

    The callee accepts one rendezvous at a time.

    Language mechanism of exceptions (if any) has to be consistent with the rendezvous. In particular when an exception is propagated out of a rendezvous it shall do in both tasks. The exception propagation is synchronous within the rendezvous and asynchronous outside it.

    An engaged rendezvous can be requeued by the callee to another entry point of its task or to another task, transparently to the caller.

    Differently to messages which are usually asynchronous, rendezvous are synchronous, as it was stated before. Therefore a rendezvous does not require marshaling the parameters and a buffer to keep them. Further, rendezvous can be implemented without context switch. This makes rendezvous a more efficient than messaging.

    Rendezvous can be used to implement monitor synchronization objects. A monitor guards a shared resource. All users of the resource request a rendezvous to the monitor in order to get access to the resource. Access is granted by accepting the rendezvous for the time while the rendezvous is serviced.

    ===Language task===

    ", + "

    Show how rendezvous are supported by the language. If the language does not have rendezvous, provide an implementation of them based on other primitives.

    ===Use case task===

    ", + "

    Implement a printer monitor. The monitor guards a printer. There are two printers main and reserve. Each has a monitor that accepts a rendezvous Print with a text line to print of the printer. The standard output may serve for printing purpose. Each character of the line is printed separately in order to illustrate that lines are printed indivisibly. Each printer has ink for only 5 lines of text. When the main printer runs out of ink it redirects its requests to the reserve printer. When that runs out of ink too, Out_Of_Ink exception propagates back to the caller. Create two writer tasks which print their plagiarisms on the printer. One does Humpty Dumpty, another Mother Goose.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7faf", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Rep-string", + "type": "Waypoint", + "description": [ + "

    Given a series of ones and zeroes in a string, define a repeated string or rep-string as a string which is created by repeating a substring of the first N characters of the string truncated on the right to the length of the input string, and in which the substring appears repeated at least twice in the original.

    For example, the string 10011001100 is a rep-string as the leftmost four characters of 1001 are repeated three times and truncated on the right to give the original string.

    Note that the requirement for having the repeat occur two or more times means that the repeating unit is never longer than half the length of the input string.

    ", + "Task:", + "Write a function/subroutine/method/... that takes a string and returns an indication of if it is a rep-string and the repeated string. (Either the string that is repeated, or the number of repeated characters would suffice). ", + "There may be multiple sub-strings that make a string a rep-string - in that case an indication of all, or the longest, or the shortest would suffice.", + "Use the function to indicate the repeating substring if any, in the following:
    ", + "
    ",
    +        "1001110011",
    +        "1110111011",
    +        "0010010010",
    +        "1010101010",
    +        "1111111111",
    +        "0100101101",
    +        "0100100",
    +        "101",
    +        "11",
    +        "00",
    +        "1",
    +        "
    ", + "Show your output on this page." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES6===", + "(() => {", + " 'use strict';", + "", + " // REP-CYCLES -------------------------------------------------------------", + "", + " // repCycles :: String -> [String]", + " const repCycles = xs => {", + " const n = xs.length;", + " return filter(", + " cs => xs === takeCycle(n, cs),", + " map(concat, tail(inits(take(quot(n, 2), xs))))", + " );", + " };", + "", + " // cycleReport :: String -> [String]", + " const cycleReport = xs => {", + " const reps = repCycles(xs);", + " return [xs, isNull(reps) ? '(n/a)' : last(reps)];", + " };", + "", + "", + " // GENERIC ----------------------------------------------------------------", + "", + " // compose :: (b -> c) -> (a -> b) -> (a -> c)", + " const compose = (f, g) => x => f(g(x));", + "", + " // concat :: [[a]] -> [a] | [String] -> String", + " const concat = xs => {", + " if (xs.length > 0) {", + " const unit = typeof xs[0] === 'string' ? '' : [];", + " return unit.concat.apply(unit, xs);", + " } else return [];", + " };", + "", + " // cons :: a -> [a] -> [a]", + " const cons = (x, xs) => [x].concat(xs);", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " const curry = f => a => b => f(a, b);", + "", + " // filter :: (a -> Bool) -> [a] -> [a]", + " const filter = (f, xs) => xs.filter(f);", + "", + " // inits :: [a] -> [[a]]", + " // inits :: String -> [String]", + " const inits = xs => [", + " []", + " ]", + " .concat((typeof xs === 'string' ? xs.split('') : xs)", + " .map((_, i, lst) => lst.slice(0, i + 1)));", + "", + " // intercalate :: String -> [a] -> String", + " const intercalate = (s, xs) => xs.join(s);", + "", + " // last :: [a] -> a", + " const last = xs => xs.length ? xs.slice(-1)[0] : undefined;", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = (f, xs) => xs.map(f);", + "", + " // isNull :: [a] -> Bool", + " const isNull = xs => (xs instanceof Array) ? xs.length < 1 : undefined;", + "", + " // Integral a => a -> a -> a", + " const quot = (n, m) => Math.floor(n / m);", + "", + " // replicate :: Int -> a -> [a]", + " const replicate = (n, a) => {", + " let v = [a],", + " o = [];", + " if (n < 1) return o;", + " while (n > 1) {", + " if (n & 1) o = o.concat(v);", + " n >>= 1;", + " v = v.concat(v);", + " }", + " return o.concat(v);", + " };", + "", + " // tail :: [a] -> [a]", + " const tail = xs => xs.length ? xs.slice(1) : undefined;", + "", + " // take :: Int -> [a] -> [a]", + " const take = (n, xs) => xs.slice(0, n);", + "", + " // First n members of an infinite cycle of xs", + " // takeCycle :: Int -> [a] -> [a]", + " const takeCycle = (n, xs) => {", + " const lng = xs.length;", + " return concat((lng >= n ? xs : replicate(Math.ceil(n / lng), xs)))", + " .slice(0, n);", + " };", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + "", + " // TEST -------------------------------------------------------------------", + " const samples = [\"1001110011\", \"1110111011\", \"0010010010\", \"1010101010\",", + " \"1111111111\", \"0100101101\", \"0100100\", \"101\", \"11\", \"00\", \"1\"", + " ];", + "", + " return unlines(cons('Longest cycle:\\n',", + " map(compose(curry(intercalate)(' -> '), cycleReport), samples)));", + "})();", + "{{Out}}", + "
    Longest cycle:",
    +        "",
    +        "1001110011 -> 10011",
    +        "1110111011 -> 1110",
    +        "0010010010 -> 001",
    +        "1010101010 -> 1010",
    +        "1111111111 -> 11111",
    +        "0100101101 -> (n/a)",
    +        "0100100 -> 010",
    +        "101 -> (n/a)",
    +        "11 -> 1",
    +        "00 -> 0",
    +        "1 -> (n/a)
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fb1", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n 'use strict';\n\n // REP-CYCLES -------------------------------------------------------------\n\n // repCycles :: String -> [String]\n const repCycles = xs => {\n const n = xs.length;\n return filter(\n cs => xs === takeCycle(n, cs),\n map(concat, tail(inits(take(quot(n, 2), xs))))\n );\n };\n\n // cycleReport :: String -> [String]\n const cycleReport = xs => {\n const reps = repCycles(xs);\n return [xs, isNull(reps) ? '(n/a)' : last(reps)];\n };\n\n\n // GENERIC ----------------------------------------------------------------\n\n // compose :: (b -> c) -> (a -> b) -> (a -> c)\n const compose = (f, g) => x => f(g(x));\n\n // concat :: [[a]] -> [a] | [String] -> String\n const concat = xs => {\n if (xs.length > 0) {\n const unit = typeof xs[0] === 'string' ? '' : [];\n return unit.concat.apply(unit, xs);\n } else return [];\n };\n\n // cons :: a -> [a] -> [a]\n const cons = (x, xs) => [x].concat(xs);\n\n // curry :: ((a, b) -> c) -> a -> b -> c\n const curry = f => a => b => f(a, b);\n\n // filter :: (a -> Bool) -> [a] -> [a]\n const filter = (f, xs) => xs.filter(f);\n\n // inits :: [a] -> [[a]]\n // inits :: String -> [String]\n const inits = xs => [\n []\n ]\n .concat((typeof xs === 'string' ? xs.split('') : xs)\n .map((_, i, lst) => lst.slice(0, i + 1)));\n\n // intercalate :: String -> [a] -> String\n const intercalate = (s, xs) => xs.join(s);\n\n // last :: [a] -> a\n const last = xs => xs.length ? xs.slice(-1)[0] : undefined;\n\n // map :: (a -> b) -> [a] -> [b]\n const map = (f, xs) => xs.map(f);\n\n // isNull :: [a] -> Bool\n const isNull = xs => (xs instanceof Array) ? xs.length < 1 : undefined;\n\n // Integral a => a -> a -> a\n const quot = (n, m) => Math.floor(n / m);\n\n // replicate :: Int -> a -> [a]\n const replicate = (n, a) => {\n let v = [a],\n o = [];\n if (n < 1) return o;\n while (n > 1) {\n if (n & 1) o = o.concat(v);\n n >>= 1;\n v = v.concat(v);\n }\n return o.concat(v);\n };\n\n // tail :: [a] -> [a]\n const tail = xs => xs.length ? xs.slice(1) : undefined;\n\n // take :: Int -> [a] -> [a]\n const take = (n, xs) => xs.slice(0, n);\n\n // First n members of an infinite cycle of xs\n // takeCycle :: Int -> [a] -> [a]\n const takeCycle = (n, xs) => {\n const lng = xs.length;\n return concat((lng >= n ? xs : replicate(Math.ceil(n / lng), xs)))\n .slice(0, n);\n };\n\n // unlines :: [String] -> String\n const unlines = xs => xs.join('\\n');\n\n\n // TEST -------------------------------------------------------------------\n const samples = [\"1001110011\", \"1110111011\", \"0010010010\", \"1010101010\",\n \"1111111111\", \"0100101101\", \"0100100\", \"101\", \"11\", \"00\", \"1\"\n ];\n\n return unlines(cons('Longest cycle:\\n',\n map(compose(curry(intercalate)(' -> '), cycleReport), samples)));\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Resistor mesh", + "type": "Waypoint", + "description": [ + "

    300px||right

    Task:", + "

    Given 10×10 grid nodes (as shown in the image) interconnected by resistors as shown,

    ", + "find the resistance between point A and B.", + "See also:", + " (humor, nerd sniping) xkcd.com cartoon" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fb2", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Retrieve and search chat history", + "type": "Waypoint", + "description": [ + "Task:

    Summary: Find and print the mentions of a given string in the recent chat logs from a chatroom. Only use your programming language's standard library.

    Details:

    The Tcl Chatroom is a online chatroom. Its conversations are logged. It is useful to know if some has mentioned you or your project in the chatroom recently. You can find this out by searching the chat logs. The logs are publicly available at http://tclers.tk/conferences/tcl/. One log file corresponds to the messages from one day in Germany's current time zone. Each chat log file has the name YYYY-MM-DD.tcl where YYYY is the year, MM is the month and DD the day. The logs store one message per line. The messages themselves are human-readable and their internal structure doesn't matter.

    Retrieve the chat logs from the last 10 days via HTTP. Find those lines that include a particular substring and print them in the following format:

    ",
    +        "------",
    +        "",
    +        "",
    +        "...",
    +        "",
    +        "------

    The substring will be given to your program as a command line argument.

    You need to account for the possible time zone difference between the client running your program and the chat log writer on the server to not miss any mentions. (For example, if you generated the log file URLs naively based on the local date, you could miss mentions if it was already April 5th for the logger but only April 4th for the client.) What this means in practice is that you should either generate the URLs in the time zone Europe/Berlin or, if your language can not do that, add an extra day (today + 1) to the range of dates you check, but then make sure to not print parts of a \"not found\" page by accident if a log file doesn't exist yet.

    The code should be contained in a single-file script, with no \"project\" or \"dependency\" file (e.g., no requirements.txt for Python). It should only use a given programming language's standard library to accomplish this task and not rely on the user having installed any third-party packages.

    If your language does not have an HTTP client in the standard library, you can speak raw HTTP 1.0 to the server. If it can't parse command line arguments in a standalone script, read the string to look for from the standard input.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fb4", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Reverse words in a string", + "type": "Waypoint", + "description": [ + "Task:", + "

    Reverse the order of all tokens in each of a number of strings and display the result; the order of characters within a token should not be modified.

    ", + "Example:", + "

    Hey you, Bub! would be shown reversed as: Bub! you, Hey

    ", + "

    Tokens are any non-space characters separated by spaces (formally, white-space); the visible punctuation form part of the word within which it is located and should not be modified.

    You may assume that there are no significant non-visible characters in the input. Multiple or superfluous spaces may be compressed into a single space.

    Some strings have no tokens, so an empty string (or one just containing spaces) would be the result.

    Display the strings in order (1st, 2nd, 3rd, ···), and one string per line.

    (You can consider the ten strings as ten lines, and the tokens as words.)

    ", + "Input data", + "
    ",
    +        "             (ten lines within the box)",
    +        " line",
    +        "     ╔════════════════════════════════════════╗",
    +        "   1 ║  ---------- Ice and Fire ------------  ║",
    +        "   2 ║                                        ║  ◄─── a blank line here.",
    +        "   3 ║  fire, in end will world the say Some  ║",
    +        "   4 ║  ice. in say Some                      ║",
    +        "   5 ║  desire of tasted I've what From       ║",
    +        "   6 ║  fire. favor who those with hold I     ║",
    +        "   7 ║                                        ║  ◄─── a blank line here.",
    +        "   8 ║  ... elided paragraph last ...         ║",
    +        "   9 ║                                        ║  ◄─── a blank line here.",
    +        "  10 ║  Frost Robert -----------------------  ║",
    +        "     ╚════════════════════════════════════════╝",
    +        "
    Cf.", + "Phrase reversals" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "var strReversed =", + "\"---------- Ice and Fire ------------\\n\\", + "\\n\\", + "fire, in end will world the say Some\\n\\", + "ice. in say Some\\n\\", + "desire of tasted I've what From\\n\\", + "fire. favor who those with hold I\\n\\", + "\\n\\", + "... elided paragraph last ...\\n\\", + "\\n\\", + "Frost Robert -----------------------\";", + " ", + "function reverseString(s) {", + " return s.split('\\n').map(", + " function (line) {", + " return line.split(/\\s/).reverse().join(' ');", + " }", + " ).join('\\n');", + "}", + " ", + "console.log(", + " reverseString(strReversed)", + ");", + "", + "Output:", + "
    ------------ Fire and Ice ----------",
    +        "",
    +        "Some say the world will end in fire,",
    +        "Some say in ice.",
    +        "From what I've tasted of desire",
    +        "I hold with those who favor fire.",
    +        "",
    +        "... last paragraph elided ...",
    +        "",
    +        "----------------------- Robert Frost
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fb7", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var strReversed =\n\"---------- Ice and Fire ------------\\n\\\n\\n\\\nfire, in end will world the say Some\\n\\\nice. in say Some\\n\\\ndesire of tasted I've what From\\n\\\nfire. favor who those with hold I\\n\\\n\\n\\\n... elided paragraph last ...\\n\\\n\\n\\\nFrost Robert -----------------------\";\n \nfunction reverseString(s) {\n return s.split('\\n').map(\n function (line) {\n return line.split(/\\s/).reverse().join(' ');\n }\n ).join('\\n');\n}\n \nconsole.log(\n reverseString(strReversed)\n);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "RIPEMD-160", + "type": "Waypoint", + "description": [ + "

    RIPEMD-160 is another hash function; it computes a 160-bit message digest.

    There is a RIPEMD-160 home page, with test vectors and pseudocode for RIPEMD-160.

    ", + "

    For padding the message, RIPEMD-160 acts like MD4 (RFC 1320).

    Find the RIPEMD-160 message digest of a string of octets.

    ", + "

    Use the ASCII encoded string “Rosetta Code”.

    ", + "

    You may either call an RIPEMD-160 library, or implement RIPEMD-160 in your language.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fb8", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Roman numerals/Decode", + "type": "Waypoint", + "description": [ + "Task:", + "

    Create a function that takes a Roman numeral as its argument and returns its value as a numeric decimal integer.

    You don't need to validate the form of the Roman numeral.

    Modern Roman numerals are written by expressing each decimal digit of the number to be encoded separately,

    ", + "starting with the leftmost decimal digit and skipping any 0s (zeroes).

    1990 is rendered as MCMXC (1000 = M, 900 = CM, 90 = XC) and

    ", + "2008 is rendered as MMVIII (2000 = MM, 8 = VIII).

    The Roman numeral for 1666, MDCLXVI, uses each letter in descending order.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "====Imperative====", + "{{works with|Rhino}}", + "{{works with|SpiderMonkey}}", + "var Roman = {", + " Values: [['CM', 900], ['CD', 400], ['XC', 90], ['XL', 40], ['IV', 4], ", + " ['IX', 9], ['V', 5], ['X', 10], ['L', 50], ", + " ['C', 100], ['M', 1000], ['I', 1], ['D', 500]],", + " UnmappedStr : 'Q',", + " parse: function(str) {", + " var result = 0", + " for (var i=0; i", + "{{out}}", + "
    MCMXC: 1990",
    +        "MDCLXVI: 1666",
    +        "MMVIII: 2008",
    +        "
    ", + "====Functional====", + "{{Trans|Haskell}}", + "(isPrefixOf example)", + "(function (lstTest) {", + " ", + " var mapping = [[\"M\", 1000], [\"CM\", 900], [\"D\", 500], [\"CD\", 400], [\"C\", 100], [", + " \"XC\", 90], [\"L\", 50], [\"XL\", 40], [\"X\", 10], [\"IX\", 9], [\"V\", 5], [\"IV\",", + " 4], [\"I\", 1]];", + " ", + " // s -> n", + " function romanValue(s) {", + " // recursion over list of characters", + " // [c] -> n", + " function toArabic(lst) {", + " return lst.length ? function (xs) {", + " var lstParse = chain(mapping, function (lstPair) {", + " return isPrefixOf(", + " lstPair[0], xs", + " ) ? [lstPair[1], drop(lstPair[0].length, xs)] : []", + " });", + " return lstParse[0] + toArabic(lstParse[1]);", + " }(lst) : 0", + " }", + " return toArabic(s.split(''));", + " }", + " ", + " // Monadic bind (chain) for lists", + " function chain(xs, f) {", + " return [].concat.apply([], xs.map(f));", + " }", + " ", + " // [a] -> [a] -> Bool", + " function isPrefixOf(lstFirst, lstSecond) {", + " return lstFirst.length ? (", + " lstSecond.length ?", + " lstFirst[0] === lstSecond[0] && isPrefixOf(", + " lstFirst.slice(1), lstSecond.slice(1)", + " ) : false", + " ) : true;", + " }", + " ", + " // Int -> [a] -> [a]", + " function drop(n, lst) {", + " return n <= 0 ? lst : (", + " lst.length ? drop(n - 1, lst.slice(1)) : []", + " );", + " }", + " ", + " return lstTest.map(romanValue);", + " ", + "})(['MCMXC', 'MDCLXVI', 'MMVIII']);", + "{{Out}}", + "[1990, 1666, 2008]", + "", + "or, more natively:", + "(function (lstTest) {", + " ", + " function romanValue(s) {", + " return s.length ? function () {", + " var parse = [].concat.apply([], glyphs.map(function (g) {", + " return 0 === s.indexOf(g) ? [trans[g], s.substr(g.length)] : [];", + " }));", + " return parse[0] + romanValue(parse[1]);", + " }() : 0;", + " }", + " ", + " var trans = {", + " M: 1E3,", + " CM: 900,", + " D: 500,", + " CD: 400,", + " C: 100,", + " XC: 90,", + " L: 50,", + " XL: 40,", + " X: 10,", + " IX: 9,", + " V: 5,", + " IV: 4,", + " I: 1", + " },", + " glyphs = Object.keys(trans);", + " ", + " return lstTest.map(romanValue);", + " ", + "})([\"MCMXC\", \"MDCLXVI\", \"MMVIII\", \"MMMM\"]);", + "{{Out}}", + "[1990, 1666, 2008]", + "", + "===ES6===", + "====Recursion====", + "(() => {", + " // romanValue :: String -> Int", + " const romanValue = s =>", + " s.length ? (() => {", + " const parse = [].concat(", + " ...glyphs.map(g => 0 === s.indexOf(g) ? (", + " [dctTrans[g], s.substr(g.length)]", + " ) : [])", + " );", + " return parse[0] + romanValue(parse[1]);", + " })() : 0;", + "", + " // dctTrans :: {romanKey: Integer}", + " const dctTrans = {", + " M: 1E3,", + " CM: 900,", + " D: 500,", + " CD: 400,", + " C: 100,", + " XC: 90,", + " L: 50,", + " XL: 40,", + " X: 10,", + " IX: 9,", + " V: 5,", + " IV: 4,", + " I: 1", + " };", + "", + " // glyphs :: [romanKey]", + " const glyphs = Object.keys(dctTrans);", + "", + " // TEST -------------------------------------------------------------------", + " return [\"MCMXC\", \"MDCLXVI\", \"MMVIII\", \"MMMM\"].map(romanValue);", + "})();", + "{{Out}}", + "[1990,1666,2008,4000]", + "", + "", + "====Folding from the right====", + "{{Trans|Haskell}} ", + "(fold and foldr examples)", + "(() => {", + "", + " // Folding from right to left,", + " // lower leftward characters are subtracted,", + " // others are added.", + "", + " // fromRoman :: String -> Int", + " const fromRoman = s =>", + " snd(foldr(", + " ([r, n], l) => [l, l >= r ? n + l : n - l], [0, 0],", + " map(charVal, stringChars(s))", + " ));", + "", + " // charVal :: Char -> Maybe Int", + " const charVal = k => {", + " const v = {", + " I: 1,", + " V: 5,", + " X: 10,", + " L: 50,", + " C: 100,", + " D: 500,", + " M: 1000", + " }[k];", + " return v !== undefined ? v : 0;", + " };", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // foldr (a -> b -> b) -> b -> [a] -> b", + " const foldr = (f, a, xs) => xs.reduceRight(f, a);", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = (f, xs) => xs.map(f);", + "", + " // snd :: (a, b) -> b", + " const snd = tpl => Array.isArray(tpl) ? tpl[1] : undefined;", + "", + " // stringChars :: String -> [Char]", + " const stringChars = s => s.split('');", + "", + " // show :: a -> String", + " const show = (...x) =>", + " JSON.stringify.apply(", + " null, x.length > 1 ? [x[1], null, x[0]] : x", + " );", + "", + " // TEST -------------------------------------------------------------------", + " return show(", + " map(fromRoman, [\"MDCLXVI\", \"MCMXC\", \"MMVIII\", \"MMXVI\", \"MMXVII\"])", + " );", + "})();", + "{{Out}}", + "
    [1666,1990,2008,2016,2017]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fba", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var Roman = {\n Values: [['CM', 900], ['CD', 400], ['XC', 90], ['XL', 40], ['IV', 4], \n ['IX', 9], ['V', 5], ['X', 10], ['L', 50], \n ['C', 100], ['M', 1000], ['I', 1], ['D', 500]],\n UnmappedStr : 'Q',\n parse: function(str) {\n var result = 0\n for (var i=0; ireplaceMe is a function.');" + ] + }, + { + "title": "Roman numerals/Encode", + "type": "Waypoint", + "description": [ + "Task:", + "

    Create a function taking a positive integer as its parameter and returning a string containing the Roman numeral representation of that integer. Modern Roman numerals are written by expressing each digit separately, starting with the left most digit and skipping any digit with a value of zero.

    ", + "

    In Roman numerals:

    ", + "1990 is rendered: 1000=M, 900=CM, 90=XC; resulting in MCMXC", + "2008 is written as 2000=MM, 8=VIII; or MMVIII", + "1666 uses each Roman symbol in descending order: MDCLXVI" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "====Iteration====", + "", + "{{trans|Tcl}}", + "var roman = {", + " map: [", + " 1000, 'M', 900, 'CM', 500, 'D', 400, 'CD', 100, 'C', 90, 'XC',", + " 50, 'L', 40, 'XL', 10, 'X', 9, 'IX', 5, 'V', 4, 'IV', 1, 'I',", + " ],", + " int_to_roman: function(n) {", + " var value = '';", + " for (var idx = 0; n > 0 && idx < this.map.length; idx += 2) {", + " while (n >= this.map[idx]) {", + " value += this.map[idx + 1];", + " n -= this.map[idx];", + " }", + " }", + " return value;", + " }", + "}", + "", + "roman.int_to_roman(1999); // \"MCMXCIX\"", + "", + "====Functional composition====", + "", + "(function () {", + " 'use strict';", + "", + "", + " // If the Roman is a string, pass any delimiters through", + "", + " // (Int | String) -> String", + " function romanTranscription(a) {", + " if (typeof a === 'string') {", + " var ps = a.split(/\\d+/),", + " dlm = ps.length > 1 ? ps[1] : undefined;", + "", + " return (dlm ? a.split(dlm)", + " .map(function (x) {", + " return Number(x);", + " }) : [a])", + " .map(roman)", + " .join(dlm);", + " } else return roman(a);", + " }", + "", + " // roman :: Int -> String", + " function roman(n) {", + " return [[1000, \"M\"], [900, \"CM\"], [500, \"D\"], [400, \"CD\"], [100,", + " \"C\"], [90, \"XC\"], [50, \"L\"], [40, \"XL\"], [10, \"X\"], [9,", + " \"IX\"], [5, \"V\"], [4, \"IV\"], [1, \"I\"]]", + " .reduce(function (a, lstPair) {", + " var m = a.remainder,", + " v = lstPair[0];", + "", + " return (v > m ? a : {", + " remainder: m % v,", + " roman: a.roman + Array(", + " Math.floor(m / v) + 1", + " )", + " .join(lstPair[1])", + " });", + " }, {", + " remainder: n,", + " roman: ''", + " }).roman; ", + " }", + "", + " // TEST", + "", + " return [2016, 1990, 2008, \"14.09.2015\", 2000, 1666].map(", + " romanTranscription);", + "", + "})();", + "", + "{{Out}}", + "[\"MMXVI\", \"MCMXC\", \"MMVIII\", \"XIV.IX.MMXV\", \"MM\", \"MDCLXVI\"]", + "", + "", + "===ES6===", + "{{Trans|Haskell}}", + "(mapAccumL version)", + "(() => {", + " // ROMAN INTEGER STRINGS ----------------------------------------------------", + "", + " // roman :: Int -> String", + " const roman = n =>", + " concat(snd(mapAccumL((balance, [k, v]) => {", + " const [q, r] = quotRem(balance, v);", + " return [r, q > 0 ? concat(replicate(q, k)) : ''];", + " }, n, [", + " ['M', 1000],", + " ['CM', 900],", + " ['D', 500],", + " ['CD', 400],", + " ['C', 100],", + " ['XC', 90],", + " ['L', 50],", + " ['XL', 40],", + " ['X', 10],", + " ['IX', 9],", + " ['V', 5],", + " ['IV', 4],", + " ['I', 1]", + " ])));", + "", + " // GENERIC FUNCTIONS -------------------------------------------------------", + "", + " // concat :: [[a]] -> [a] | [String] -> String", + " const concat = xs =>", + " xs.length > 0 ? (() => {", + " const unit = typeof xs[0] === 'string' ? '' : [];", + " return unit.concat.apply(unit, xs);", + " })() : [];", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = (f, xs) => xs.map(f);", + "", + " // 'The mapAccumL function behaves like a combination of map and foldl;", + " // it applies a function to each element of a list, passing an accumulating", + " // parameter from left to right, and returning a final value of this", + " // accumulator together with the new list.' (See Hoogle)", + "", + " // mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])", + " const mapAccumL = (f, acc, xs) =>", + " xs.reduce((a, x) => {", + " const pair = f(a[0], x);", + " return [pair[0], a[1].concat([pair[1]])];", + " }, [acc, []]);", + "", + " // quotRem :: Integral a => a -> a -> (a, a)", + " const quotRem = (m, n) => [Math.floor(m / n), m % n];", + "", + " // replicate :: Int -> a -> [a]", + " const replicate = (n, x) =>", + " Array.from({", + " length: n", + " }, () => x);", + "", + " // show :: a -> String", + " const show = (...x) =>", + " JSON.stringify.apply(", + " null, x.length > 1 ? [x[0], null, x[1]] : x", + " );", + "", + " // snd :: (a, b) -> b", + " const snd = tpl => Array.isArray(tpl) ? tpl[1] : undefined;", + "", + " // TEST -------------------------------------------------------------------", + " return show(", + " map(roman, [2016, 1990, 2008, 2000, 1666])", + " );", + "})();", + "{{Out}}", + "[\"MMXVI\",\"MCMXC\",\"MMVIII\",\"MM\",\"MDCLXVI\"]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fbb", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var roman = {\n map: [\n 1000, 'M', 900, 'CM', 500, 'D', 400, 'CD', 100, 'C', 90, 'XC',\n 50, 'L', 40, 'XL', 10, 'X', 9, 'IX', 5, 'V', 4, 'IV', 1, 'I',\n ],\n int_to_roman: function(n) {\n var value = '';\n for (var idx = 0; n > 0 && idx < this.map.length; idx += 2) {\n while (n >= this.map[idx]) {\n value += this.map[idx + 1];\n n -= this.map[idx];\n }\n }\n return value;\n }\n}\n\nroman.int_to_roman(1999); // \"MCMXCIX\"\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Roots of a function", + "type": "Waypoint", + "description": [ + "Task:", + "

    Create a program that finds and outputs the roots of a given function, range and (if applicable) step width.

    The program should identify whether the root is exact or approximate.

    ", + "

    For this task, use: ƒ(x) = x3 - 3x2 + 2x

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{trans|Java}}", + "{{works with|SpiderMonkey|22}}", + "{{works with|Firefox|22}}", + "", + "// This function notation is sorta new, but useful here", + "// Part of the EcmaScript 6 Draft", + "// developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope", + "var poly = (x => x*x*x - 3*x*x + 2*x);", + "", + "function sign(x) {", + "\treturn (x < 0.0) ? -1 : (x > 0.0) ? 1 : 0;", + "}", + "", + "function printRoots(f, lowerBound, upperBound, step) {", + "\tvar x = lowerBound, ox = x,", + "\t\t y = f(x), oy = y,", + "\t\t s = sign(y), os = s;", + "", + "\tfor (; x <= upperBound ; x += step) {", + "\t s = sign(y = f(x));", + "\t if (s == 0) {", + "\t\t\tconsole.log(x);", + "\t }", + "\t else if (s != os) {", + "\t\t\tvar dx = x - ox;", + "\t\t\tvar dy = y - oy;", + "\t\t\tvar cx = x - dx * (y / dy);", + "\t\t\tconsole.log(\"~\" + cx);", + "\t }", + "\t ox = x; oy = y; os = s;", + "\t}", + "}", + "", + "printRoots(poly, -1.0, 4, 0.002);", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fbc", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n// This function notation is sorta new, but useful here\n// Part of the EcmaScript 6 Draft\n// developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope\nvar poly = (x => x*x*x - 3*x*x + 2*x);\n\nfunction sign(x) {\n\treturn (x < 0.0) ? -1 : (x > 0.0) ? 1 : 0;\n}\n\nfunction printRoots(f, lowerBound, upperBound, step) {\n\tvar x = lowerBound, ox = x,\n\t\t y = f(x), oy = y,\n\t\t s = sign(y), os = s;\n\n\tfor (; x <= upperBound ; x += step) {\n\t s = sign(y = f(x));\n\t if (s == 0) {\n\t\t\tconsole.log(x);\n\t }\n\t else if (s != os) {\n\t\t\tvar dx = x - ox;\n\t\t\tvar dy = y - oy;\n\t\t\tvar cx = x - dx * (y / dy);\n\t\t\tconsole.log(\"~\" + cx);\n\t }\n\t ox = x; oy = y; os = s;\n\t}\n}\n\nprintRoots(poly, -1.0, 4, 0.002);\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Roots of a quadratic function", + "type": "Waypoint", + "description": [ + "

    Write a program to find the roots of a quadratic equation, i.e., solve the equation $ax^2 + bx + c = 0$.

    ", + "

    Your program must correctly handle non-real roots, but it need not check that $a \\neq 0$.

    The problem of solving a quadratic equation is a good example of how dangerous it can be to ignore the peculiarities of floating-point arithmetic.

    ", + "

    The obvious way to implement the quadratic formula suffers catastrophic loss of accuracy when one of the roots to be found is much closer to 0 than the other.

    ", + "

    In their classic textbook on numeric methods Computer Methods for Mathematical Computations, George Forsythe, Michael Malcolm, and Cleve Moler suggest trying the naive algorithm with $a = 1$, $b = -10^5$, and $c = 1$.

    ", + "

    (For double-precision floats, set $b = -10^9$.)

    ", + "

    Consider the following implementation in Ada:

    ", + "

    with Ada.Text_IO; use Ada.Text_IO;

    ", + "

    with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions;

    procedure Quadratic_Equation is

    ", + "

    type Roots is array (1..2) of Float;

    ", + "

    function Solve (A, B, C : Float) return Roots is

    ", + "

    SD : constant Float := sqrt (B**2 - 4.0 * A * C);

    ", + "

    AA : constant Float := 2.0 * A;

    ", + "

    begin

    ", + "

    return ((- B + SD) / AA, (- B - SD) / AA);

    ", + "

    end Solve;

    R : constant Roots := Solve (1.0, -10.0E5, 1.0);

    ", + "

    begin

    ", + "

    Put_Line (\"X1 =\" & Float'Image (R (1)) & \" X2 =\" & Float'Image (R (2)));

    ", + "

    end Quadratic_Equation;

    X1 = 1.00000E+06 X2 = 0.00000E+00
    ", + "

    As we can see, the second root has lost all significant figures. The right answer is that X2 is about $10^{-6}$. The naive method is numerically unstable.

    Suggested by Middlebrook (D-OA), a better numerical method: to define two parameters $ q = \\sqrt{a c} / b $ and $ f = 1/2 + \\sqrt{1 - 4 q^2} /2 $

    and the two roots of the quardratic are: $ \\frac{-b}{a} f $ and $ \\frac{-c}{b f} $

    ", + "

    Task: do it better. This means that given $a = 1$, $b = -10^9$, and $c = 1$, both of the roots your program returns should be greater than $10^{-11}$. Or, if your language can't do floating-point arithmetic any more precisely than single precision, your program should be able to handle $b = -10^6$. Either way, show what your program gives as the roots of the quadratic in question. See page 9 of

    ", + "

    \"What Every Scientist Should Know About Floating-Point Arithmetic\" for a possible algorithm.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fbd", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Roots of unity", + "type": "Waypoint", + "description": [ + "

    The purpose of this task is to explore working with complex numbers.

    ", + "Task:", + "

    Given n, find the n-th roots of unity.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function Root(angle) {", + "\twith (Math) { this.r = cos(angle); this.i = sin(angle) }", + "}", + "", + "Root.prototype.toFixed = function(p) {", + "\treturn this.r.toFixed(p) + (this.i >= 0 ? '+' : '') + this.i.toFixed(p) + 'i'", + "}", + "", + "function roots(n) {", + "\tvar rs = [], teta = 2*Math.PI/n", + "\tfor (var angle=0, i=0; i')", + "}", + "", + "{{Output}}", + "
    2: 1.00000+0.00000i, -1.00000+0.00000i",
    +        "3: 1.00000+0.00000i, -0.50000+0.86603i, -0.50000-0.86603i",
    +        "4: 1.00000+0.00000i, 0.00000+1.00000i, -1.00000+0.00000i, -0.00000-1.00000i",
    +        "5: 1.00000+0.00000i, 0.30902+0.95106i, -0.80902+0.58779i, -0.80902-0.58779i, 0.30902-0.95106i",
    +        "6: 1.00000+0.00000i, 0.50000+0.86603i, -0.50000+0.86603i, -1.00000+0.00000i, -0.50000-0.86603i, 0.50000-0.86603i",
    +        "7: 1.00000+0.00000i, 0.62349+0.78183i, -0.22252+0.97493i, -0.90097+0.43388i, -0.90097-0.43388i, -0.22252-0.97493i, 0.62349-0.78183i
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fbe", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function Root(angle) {\n\twith (Math) { this.r = cos(angle); this.i = sin(angle) }\n}\n\nRoot.prototype.toFixed = function(p) {\n\treturn this.r.toFixed(p) + (this.i >= 0 ? '+' : '') + this.i.toFixed(p) + 'i'\n}\n\nfunction roots(n) {\n\tvar rs = [], teta = 2*Math.PI/n\n\tfor (var angle=0, i=0; i')\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Rosetta Code/Find bare lang tags", + "type": "Waypoint", + "description": [ + "Task:", + "

    Find all tags without a language specified in the text of a page.

    Display counts by language section:

    ",
    +        "

    Description

    Pseudocode

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fc0", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Rosetta Code/Fix code tags", + "type": "Waypoint", + "description": [ + "Task:", + "

    Fix Rosetta Code deprecated code tags, with these rules:

    ", + "
    ",
    +        "Change <%s> to ",
    +        "Change  to ",
    +        "Change  to ",
    +        "Change  to ",
    +        "
    ", + "Usage:", + "
    ",
    +        "./convert.py < wikisource.txt > converted.txt",
    +        "
    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|SpiderMonkey}}", + "var langs = ['foo', 'bar', 'baz']; // real list of langs goes here", + "var end_tag = '';", + "", + "var line;", + "while (line = readline()) {", + " line = line.replace(new RegExp('', 'gi'), end_tag);", + " for (var i = 0; i < langs.length; i++)", + " line = line.replace(new RegExp('<(?:code )?(' + langs[i] + ')>', 'gi'), '')", + " .replace(new RegExp('', 'gi'), end_tag);", + " print(line);", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fc2", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var langs = ['foo', 'bar', 'baz']; // real list of langs goes here\nvar end_tag = '';\n\nvar line;\nwhile (line = readline()) {\n line = line.replace(new RegExp('', 'gi'), end_tag);\n for (var i = 0; i < langs.length; i++)\n line = line.replace(new RegExp('<(?:code )?(' + langs[i] + ')>', 'gi'), '')\n .replace(new RegExp('', 'gi'), end_tag);\n print(line);\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Rot-13", + "type": "Waypoint", + "description": [ + "Task:", + "

    Implement a rot-13 function (or procedure, class, subroutine, or other \"callable\" object as appropriate to your programming environment).

    Optionally wrap this function in a utility program (like tr, which acts like a common UNIX utility, performing a line-by-line rot-13 encoding of every line of input contained in each file listed on its command line, or (if no filenames are passed thereon) acting as a filter on its \"standard input.\"

    ", + "

    (A number of UNIX scripting languages and utilities, such as awk and sed either default to processing files in this way or have command line switches or modules to easily implement these wrapper semantics, e.g., Perl and Python).

    The rot-13 encoding is commonly known from the early days of Usenet \"Netnews\" as a way of obfuscating text to prevent casual reading of spoiler or potentially offensive material.

    Many news reader and mail user agent programs have built-in rot-13 encoder/decoders or have the ability to feed a message through any external utility script for performing this (or other) actions.

    The definition of the rot-13 function is to simply replace every letter of the ASCII alphabet with the letter which is \"rotated\" 13 characters \"around\" the 26 letter alphabet from its normal cardinal position (wrapping around from z' to a as necessary).

    Thus the letters abc become nop and so on.

    Technically rot-13 is a \"mono-alphabetic substitution cipher\" with a trivial \"key\".

    A proper implementation should work on upper and lower case letters, preserve case, and pass all non-alphabetic characters

    ", + "

    in the input stream through without alteration.

    ", + "Related tasks:", + " Caesar cipher", + " Substitution Cipher", + " Vigenère Cipher/Cryptanalysis" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function rot13(c) {", + " return c.replace(/([a-m])|([n-z])/ig, function($0,$1,$2) {", + " return String.fromCharCode($1 ? $1.charCodeAt(0) + 13 : $2 ? $2.charCodeAt(0) - 13 : 0) || $0;", + " });", + "}", + "rot13(\"ABJURER nowhere\") // NOWHERE abjurer", + "", + "", + "TDD with Jasmine using Underscore.js", + "", + "", + "function rot13(value){", + " if (!value)", + " return \"\";", + "", + " function singleChar(c) {", + " if (c.toUpperCase() < \"A\" || c.toUpperCase() > \"Z\")", + " return c;", + "", + " if (c.toUpperCase() <= \"M\")", + " return String.fromCharCode(c.charCodeAt(0) + 13);", + "", + " return String.fromCharCode(c.charCodeAt(0) - 13); ", + " }", + "", + " return _.map(value.split(\"\"), singleChar).join(\"\");", + "}", + "", + "describe(\"Rot-13\", function() {", + " it(\"Given nothing will return nothing\", function() {", + " expect(rot13()).toBe(\"\");", + " });", + "", + " it(\"Given empty string will return empty string\", function() {", + " expect(rot13(\"\")).toBe(\"\");", + " });", + "", + " it(\"Given A will return N\", function() {", + " expect(rot13(\"A\")).toBe(\"N\");", + " });", + "", + " it(\"Given B will return O\", function() {", + " expect(rot13(\"B\")).toBe(\"O\");", + " });", + "", + " it(\"Given N will return A\", function() {", + " expect(rot13(\"N\")).toBe(\"A\");", + " });", + "", + " it(\"Given Z will return M\", function() {", + " expect(rot13(\"Z\")).toBe(\"M\");", + " });", + "", + " it(\"Given ZA will return MN\", function() {", + " expect(rot13(\"ZA\")).toBe(\"MN\");", + " });", + "", + " it(\"Given HELLO will return URYYB\", function() {", + " expect(rot13(\"HELLO\")).toBe(\"URYYB\");", + " });", + "", + " it(\"Given hello will return uryyb\", function() {", + " expect(rot13(\"hello\")).toBe(\"uryyb\");", + " });", + "", + "", + " it(\"Given hello1 will return uryyb1\", function() {", + " expect(rot13(\"hello1\")).toBe(\"uryyb1\");", + " });", + "});", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fc4", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function rot13(c) {\n return c.replace(/([a-m])|([n-z])/ig, function($0,$1,$2) {\n return String.fromCharCode($1 ? $1.charCodeAt(0) + 13 : $2 ? $2.charCodeAt(0) - 13 : 0) || $0;\n });\n}\nrot13(\"ABJURER nowhere\") // NOWHERE abjurer\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "RSA code", + "type": "Waypoint", + "description": [ + "

    Given an RSA key (n,e,d), construct a program to encrypt and decrypt plaintext messages strings.

    Background

    RSA code is used to encode secret messages. It is named after Ron Rivest, Adi Shamir, and Leonard Adleman who published it at MIT in 1977. The advantage of this type of encryption is that you can distribute the number “$n$” and “$e$” (which makes up the Public Key used for encryption) to everyone. The Private Key used for decryption “$d$” is kept secret, so that only the recipient can read the encrypted plaintext.

    The process by which this is done is that a message, for example “Hello World” is encoded as numbers (This could be encoding as ASCII or as a subset of characters $a=01,b=02,...,z=26$). This yields a string of numbers, generally referred to as \"numerical plaintext\", “$P$”. For example, “Hello World” encoded with a=1,...,z=26 by hundreds would yield $0805 1212 1523 1518 1204$.

    The plaintext must also be split into blocks so that the numerical plaintext is smaller than $n$ otherwise the decryption will fail.

    The ciphertext, $C$, is then computed by taking each block of $P$, and computing

    ", + "

    $C \\equiv P^e \\mod n$

    ", + "

    Similarly, to decode, one computes

    ", + "

    $P \\equiv C^d \\mod n$

    To generate a key, one finds 2 (ideally large) primes $p$ and $q$. the value “$n$” is simply: $n = p \\times q$.

    ", + "

    One must then choose an “$e$” such that $\\gcd(e, (p-1)\\times(q-1) ) = 1$. That is to say, $e$ and $(p-1)\\times(q-1)$ are relatively prime to each other.

    The decryption value $d$ is then found by solving

    ", + "

    $d\\times e \\equiv 1 \\mod (p-1)\\times(q-1)$

    The security of the code is based on the secrecy of the Private Key (decryption exponent) “$d$” and the difficulty in factoring “$n$”. Research into RSA facilitated advances in factoring and a number of factoring challenges. Keys of 768 bits have been successfully factored. While factoring of keys of 1024 bits has not been demonstrated, NIST expected them to be factorable by 2010 and now recommends 2048 bit keys going forward (see Asymmetric algorithm key lengths or NIST 800-57 Pt 1 Revised Table 4: Recommended algorithms and minimum key sizes).

    Summary of the task requirements:

    Encrypt and Decrypt a short message or two using RSA with a demonstration key. ", + " Implement RSA do not call a library.", + " Encode and decode the message using any reversible method of your choice (ASCII or a=1,..,z=26 are equally fine). ", + " Either support blocking or give an error if the message would require blocking)", + " Demonstrate that your solution could support real keys by using a non-trivial key that requires large integer support (built-in or libraries). There is no need to include library code but it must be referenced unless it is built into the language. The following keys will be meet this requirement;however, they are NOT long enough to be considered secure:: n = 9516311845790656153499716760847001433441357", + "

    : e = 65537

    ", + "

    : d = 5617843187844953170308463622230283376298685

    ", + " Messages can be hard-coded into the program, there is no need for elaborate input coding.", + " Demonstrate that your implementation works by showing plaintext, intermediate results, encrypted text, and decrypted text." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fc5", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Runge-Kutta method", + "type": "Waypoint", + "description": [ + "

    Given the example Differential equation:

    ", + "

    $y'(t) = t \\times \\sqrt {y(t)}$

    ", + "

    With initial condition:

    ", + "

    $t_0 = 0$ and $y_0 = y(t_0) = y(0) = 1$

    ", + "

    This equation has an exact solution:

    ", + "

    $y(t) = \\tfrac{1}{16}(t^2 +4)^2$

    ", + "Task", + "

    Demonstrate the commonly used explicit fourth-order Runge–Kutta method to solve the above differential equation.

    ", + "Solve the given differential equation over the range $t = 0 \\ldots 10$ with a step value of $\\delta t=0.1$ (101 total points, the first being given)", + "Print the calculated values of $y$ at whole numbered $t$'s ($0.0, 1.0, \\ldots 10.0$) along with error as compared to the exact solution.Method summary", + "

    Starting with a given $y_n$ and $t_n$ calculate:

    ", + "

    $\\delta y_1 = \\delta t\\times y'(t_n, y_n)\\quad$

    ", + "

    $\\delta y_2 = \\delta t\\times y'(t_n + \\tfrac{1}{2}\\delta t , y_n + \\tfrac{1}{2}\\delta y_1)$

    ", + "

    $\\delta y_3 = \\delta t\\times y'(t_n + \\tfrac{1}{2}\\delta t , y_n + \\tfrac{1}{2}\\delta y_2)$

    ", + "

    $\\delta y_4 = \\delta t\\times y'(t_n + \\delta t , y_n + \\delta y_3)\\quad$

    ", + "

    then:

    ", + "

    $y_{n+1} = y_n + \\tfrac{1}{6} (\\delta y_1 + 2\\delta y_2 + 2\\delta y_3 + \\delta y_4)$

    ", + "

    $t_{n+1} = t_n + \\delta t\\quad$

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "function rk4(y, x, dx, f) {", + " var k1 = dx * f(x, y),", + " k2 = dx * f(x + dx / 2.0, +y + k1 / 2.0),", + " k3 = dx * f(x + dx / 2.0, +y + k2 / 2.0),", + " k4 = dx * f(x + dx, +y + k3);", + "", + " return y + (k1 + 2.0 * k2 + 2.0 * k3 + k4) / 6.0;", + "}", + "", + "function f(x, y) {", + " return x * Math.sqrt(y);", + "}", + "", + "function actual(x) {", + " return (1/16) * (x*x+4)*(x*x+4);", + "}", + "", + "var y = 1.0,", + " x = 0.0,", + " step = 0.1,", + " steps = 0,", + " maxSteps = 101,", + " sampleEveryN = 10;", + "", + "while (steps < maxSteps) {", + " if (steps%sampleEveryN === 0) {", + " console.log(\"y(\" + x + \") = \\t\" + y + \"\\t ± \" + (actual(x) - y).toExponential());", + " }", + "", + " y = rk4(y, x, step, f);", + "", + " // using integer math for the step addition", + " // to prevent floating point errors as 0.2 + 0.1 != 0.3", + " x = ((x * 10) + (step * 10)) / 10;", + " steps += 1;", + "}", + "", + "{{out}}", + "
    ",
    +        "y(0) =  \t1\t                 ± 0e+0",
    +        "y(1) =  \t1.562499854278108\t ± 1.4572189210859676e-7",
    +        "y(2) =  \t3.999999080520799\t ± 9.194792007782837e-7",
    +        "y(3) =  \t10.562497090437551\t ± 2.9095624487496252e-6",
    +        "y(4) =  \t24.999993765090636\t ± 6.234909363911356e-6",
    +        "y(5) =  \t52.562489180302585\t ± 1.0819697415342944e-5",
    +        "y(6) =  \t99.99998340540358\t ± 1.659459641700778e-5",
    +        "y(7) =  \t175.56247648227125\t ± 2.3517728749311573e-5",
    +        "y(8) =  \t288.9999684347986\t ± 3.156520142510999e-5",
    +        "y(9) =  \t451.56245927683966\t ± 4.07231603389846e-5",
    +        "y(10) =  \t675.9999490167097\t ± 5.098329029351589e-5",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fc6", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nfunction rk4(y, x, dx, f) {\n var k1 = dx * f(x, y),\n k2 = dx * f(x + dx / 2.0, +y + k1 / 2.0),\n k3 = dx * f(x + dx / 2.0, +y + k2 / 2.0),\n k4 = dx * f(x + dx, +y + k3);\n\n return y + (k1 + 2.0 * k2 + 2.0 * k3 + k4) / 6.0;\n}\n\nfunction f(x, y) {\n return x * Math.sqrt(y);\n}\n\nfunction actual(x) {\n return (1/16) * (x*x+4)*(x*x+4);\n}\n\nvar y = 1.0,\n x = 0.0,\n step = 0.1,\n steps = 0,\n maxSteps = 101,\n sampleEveryN = 10;\n\nwhile (steps < maxSteps) {\n if (steps%sampleEveryN === 0) {\n console.log(\"y(\" + x + \") = \\t\" + y + \"\\t ± \" + (actual(x) - y).toExponential());\n }\n\n y = rk4(y, x, step, f);\n\n // using integer math for the step addition\n // to prevent floating point errors as 0.2 + 0.1 != 0.3\n x = ((x * 10) + (step * 10)) / 10;\n steps += 1;\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Run-length encoding", + "type": "Waypoint", + "description": [ + "

    Given a string containing uppercase characters (A-Z), compress repeated 'runs' of the same character by storing the length of that run, and provide a function to reverse the compression. The output can be anything, as long as you can recreate the input with it.

    Example:

    Input: WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW

    ", + "

    Output: 12W1B12W3B24W1B14W

    Note: the encoding step in the above example is the same as a step of the Look-and-say sequence.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Here's an encoding method that walks the input string character by character", + "function encode(input) {", + " var encoding = [];", + " var prev, count, i;", + " for (count = 1, prev = input[0], i = 1; i < input.length; i++) {", + " if (input[i] != prev) {", + " encoding.push([count, prev]);", + " count = 1;", + " prev = input[i];", + " }", + " else ", + " count ++;", + " }", + " encoding.push([count, prev]);", + " return encoding;", + "}", + "", + "Here's an encoding method that uses a regular expression to grab the character runs ({{works with|JavaScript|1.6}} for the forEach method)", + "function encode_re(input) {", + " var encoding = [];", + " input.match(/(.)\\1*/g).forEach(function(substr){ encoding.push([substr.length, substr[0]]) });", + " return encoding;", + "}", + "", + "And to decode (see [[Repeating a string#JavaScript|Repeating a string]])", + "function decode(encoded) {", + " var output = \"\";", + " encoded.forEach(function(pair){ output += new Array(1+pair[0]).join(pair[1]) })", + " return output;", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fc7", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function encode(input) {\n var encoding = [];\n var prev, count, i;\n for (count = 1, prev = input[0], i = 1; i < input.length; i++) {\n if (input[i] != prev) {\n encoding.push([count, prev]);\n count = 1;\n prev = input[i];\n }\n else \n count ++;\n }\n encoding.push([count, prev]);\n return encoding;\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Safe addition", + "type": "Waypoint", + "description": [ + "

    Implementation of interval arithmetic and more generally fuzzy number arithmetic require operations that yield safe upper and lower bounds of the exact result.

    For example, for an addition, it is the operations +↑ and +↓ defined as: a +↓ b ≤ a + b ≤ a +↑ b.

    Additionally it is desired that the width of the interval (a +↑ b) - (a +↓ b) would be about the machine epsilon after removing the exponent part.

    Differently to the standard floating-point arithmetic, safe interval arithmetic is accurate (but still imprecise).

    I.E.: the result of each defined operation contains (though does not identify) the exact mathematical outcome.

    Usually a FPU's have machine +,-,*,/ operations accurate within the machine precision.

    To illustrate it, let us consider a machine with decimal floating-point arithmetic that has the precision is 3 decimal points.

    If the result of the machine addition is 1.23, then the exact mathematical result is within the interval ]1.22, 1.24[.

    When the machine rounds towards zero, then the exact result is within [1.23,1.24[. This is the basis for an implementation of safe addition.

    ", + "Task;", + "

    Show how +↓ and +↑ can be implemented in your language using the standard floating-point type.

    Define an interval type based on the standard floating-point one, and implement an interval-valued addition of two floating-point numbers considering them exact, in short an operation that yields the interval [a +↓ b, a +↑ b].

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fca", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Same Fringe", + "type": "Waypoint", + "description": [ + "

    Write a routine that will compare the leaves (\"fringe\") of two binary trees to determine whether they are the same list of leaves when visited left-to-right. The structure or balance of the trees does not matter; only the number, order, and value of the leaves is important.

    Any solution is allowed here, but many computer scientists will consider it inelegant to collect either fringe in its entirety before starting to collect the other one. In fact, this problem is usually proposed in various forums as a way to show off various forms of concurrency (tree-rotation algorithms have also been used to get around the need to collect one tree first). Thinking of it a slightly different way, an elegant solution is one that can perform the minimum amount of work to falsify the equivalence of the fringes when they differ somewhere in the middle, short-circuiting the unnecessary additional traversals and comparisons.

    Any representation of a binary tree is allowed, as long as the nodes are orderable, and only downward links are used (for example, you may not use parent or sibling pointers to avoid recursion).

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fcc", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Search a list of records", + "type": "Waypoint", + "description": [ + "

    Many programming languages provide convenient ways to look for a known value in a simple list of strings or numbers.

    ", + "

    But what if the elements of the list are themselves compound records/objects/data-structures, and the search condition is more complex than a simple equality test?

    ", + "

    Write a function/method/etc. that can find the first element in a given list matching a given condition.

    ", + "

    It should be as generic and reusable as possible.

    ", + "

    (Of course if your programming language already provides such a feature, you can use that instead of recreating it.)

    Then to demonstrate its functionality, create the data structure specified under #Data set, and perform on it the searches specified under #Test cases.

    ", + "

    The data structure to be used contains the names and populations (in millions) of the 10 largest metropolitan areas in Africa, and looks as follows when represented in JSON:

    [

    ", + "

    { \"name\": \"Lagos\", \"population\": 21.0 },

    ", + "

    { \"name\": \"Cairo\", \"population\": 15.2 },

    ", + "

    { \"name\": \"Kinshasa-Brazzaville\", \"population\": 11.3 },

    ", + "

    { \"name\": \"Greater Johannesburg\", \"population\": 7.55 },

    ", + "

    { \"name\": \"Mogadishu\", \"population\": 5.85 },

    ", + "

    { \"name\": \"Khartoum-Omdurman\", \"population\": 4.98 },

    ", + "

    { \"name\": \"Dar Es Salaam\", \"population\": 4.7 },

    ", + "

    { \"name\": \"Alexandria\", \"population\": 4.58 },

    ", + "

    { \"name\": \"Abidjan\", \"population\": 4.4 },

    ", + "

    { \"name\": \"Casablanca\", \"population\": 3.98 }

    ", + "

    ]

    However, you shouldn't parse it from JSON, but rather represent it natively in your programming language.

    The top-level data structure should be an ordered collection (i.e. a list, array, vector, or similar).", + "Each element in this list should be an associative collection that maps from keys to values (i.e. a struct, object, hash map, dictionary, or similar).", + "Each of them has two entries: One string value with key \"name\", and one numeric value with key \"population\".", + "You may rely on the list being sorted by population count, as long as you explain this to readers.", + "

    If any of that is impossible or unreasonable in your programming language, then feel free to deviate, as long as you explain your reasons in a comment above your solution.

    ", + "

    {|

    ", + "

    |-

    ", + "

    ! Search

    ", + "

    ! Expected result

    ", + "

    |-

    ", + "

    | Find the (zero-based) index of the first city in the list whose name is \"Dar Es Salaam\"

    ", + "

    | 6

    ", + "

    |-

    ", + "

    | Find the name of the first city in this list whose population is less than 5 million

    ", + "

    | Khartoum-Omdurman

    ", + "

    |-

    ", + "

    | Find the population of the first city in this list whose name starts with the letter \"A\"

    ", + "

    | 4.58

    ", + "

    |}

    ", + "

    If your programming language supports higher-order programming, then the most elegant way to implement the requested functionality in a generic and reusable way, might be to write a function (maybe called \"find_index\" or similar), that takes two arguments:

    ", + "The list to search through.", + "A function/lambda/closure (the so-called \"predicate\"), which will be applied in turn to each element in the list, and whose boolean return value defines whether that element matches the search requirement.", + "

    If this is not the approach which would be most natural or idiomatic in your language, explain why, and show what is.

    ", + "Search a list", + "


    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "(function () {", + " 'use strict';", + " ", + " // find :: (a -> Bool) -> [a] -> Maybe a", + " function find(f, xs) {", + " for (var i = 0, lng = xs.length; i < lng; i++) {", + " if (f(xs[i])) return xs[i];", + " }", + " return undefined;", + " }", + " ", + " // findIndex :: (a -> Bool) -> [a] -> Maybe Int", + " function findIndex(f, xs) {", + " for (var i = 0, lng = xs.length; i < lng; i++) {", + " if (f(xs[i])) return i;", + " } ", + " return undefined;", + " }", + " ", + " ", + " var lst = [", + " { \"name\": \"Lagos\", \"population\": 21.0 },", + " { \"name\": \"Cairo\", \"population\": 15.2 },", + " { \"name\": \"Kinshasa-Brazzaville\", \"population\": 11.3 },", + " { \"name\": \"Greater Johannesburg\", \"population\": 7.55 },", + " { \"name\": \"Mogadishu\", \"population\": 5.85 },", + " { \"name\": \"Khartoum-Omdurman\", \"population\": 4.98 },", + " { \"name\": \"Dar Es Salaam\", \"population\": 4.7 },", + " { \"name\": \"Alexandria\", \"population\": 4.58 },", + " { \"name\": \"Abidjan\", \"population\": 4.4 },", + " { \"name\": \"Casablanca\", \"population\": 3.98 }", + " ];", + " ", + " return {", + " darEsSalaamIndex: findIndex(function (x) {", + " return x.name === 'Dar Es Salaam';", + " }, lst),", + " ", + " firstBelow5M: find(function (x) {", + " return x.population < 5;", + " }, lst)", + " .name,", + " ", + " firstApop: find(function (x) {", + " return x.name.charAt(0) === 'A';", + " }, lst)", + " .population", + " };", + " ", + "})();", + "", + "", + "{{Out}}", + "
    {\"darEsSalaamIndex\":6, \"firstBelow5M\":\"Khartoum-Omdurman\", \"firstApop\":4.58}
    ", + "", + "===ES6===", + "", + "(() => {", + " 'use strict';", + " ", + " let lst = [", + " { \"name\": \"Lagos\", \"population\": 21.0 },", + " { \"name\": \"Cairo\", \"population\": 15.2 },", + " { \"name\": \"Kinshasa-Brazzaville\", \"population\": 11.3 },", + " { \"name\": \"Greater Johannesburg\", \"population\": 7.55 },", + " { \"name\": \"Mogadishu\", \"population\": 5.85 },", + " { \"name\": \"Khartoum-Omdurman\", \"population\": 4.98 },", + " { \"name\": \"Dar Es Salaam\", \"population\": 4.7 },", + " { \"name\": \"Alexandria\", \"population\": 4.58 },", + " { \"name\": \"Abidjan\", \"population\": 4.4 },", + " { \"name\": \"Casablanca\", \"population\": 3.98 }", + " ];", + " ", + " return {", + " darEsSalaamIndex: lst.findIndex(x => x.name === 'Dar Es Salaam'),", + " firstBelow5M: lst.find(x => x.population < 5)", + " .name,", + " firstApop: lst.find(x => x.name[0] === 'A')", + " .population", + " };", + " ", + "})();", + "", + "", + "{{Out}}", + "
    {\"darEsSalaamIndex\":6, \"firstBelow5M\":\"Khartoum-Omdurman\", \"firstApop\":4.58}
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fcf", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function () {\n 'use strict';\n \n // find :: (a -> Bool) -> [a] -> Maybe a\n function find(f, xs) {\n for (var i = 0, lng = xs.length; i < lng; i++) {\n if (f(xs[i])) return xs[i];\n }\n return undefined;\n }\n \n // findIndex :: (a -> Bool) -> [a] -> Maybe Int\n function findIndex(f, xs) {\n for (var i = 0, lng = xs.length; i < lng; i++) {\n if (f(xs[i])) return i;\n } \n return undefined;\n }\n \n \n var lst = [\n { \"name\": \"Lagos\", \"population\": 21.0 },\n { \"name\": \"Cairo\", \"population\": 15.2 },\n { \"name\": \"Kinshasa-Brazzaville\", \"population\": 11.3 },\n { \"name\": \"Greater Johannesburg\", \"population\": 7.55 },\n { \"name\": \"Mogadishu\", \"population\": 5.85 },\n { \"name\": \"Khartoum-Omdurman\", \"population\": 4.98 },\n { \"name\": \"Dar Es Salaam\", \"population\": 4.7 },\n { \"name\": \"Alexandria\", \"population\": 4.58 },\n { \"name\": \"Abidjan\", \"population\": 4.4 },\n { \"name\": \"Casablanca\", \"population\": 3.98 }\n ];\n \n return {\n darEsSalaamIndex: findIndex(function (x) {\n return x.name === 'Dar Es Salaam';\n }, lst),\n \n firstBelow5M: find(function (x) {\n return x.population < 5;\n }, lst)\n .name,\n \n firstApop: find(function (x) {\n return x.name.charAt(0) === 'A';\n }, lst)\n .population\n };\n \n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Search a list", + "type": "Waypoint", + "description": [ + "

    Find the index of a string (needle) in an indexable, ordered collection of strings (haystack).

    Raise an exception if the needle is missing.

    If there is more than one occurrence then return the smallest index to the needle.

    ", + "

    Return the largest index to a needle that has multiple occurrences in the haystack.

    ", + "Search a list of records", + "


    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "var haystack = ['Zig', 'Zag', 'Wally', 'Ronald', 'Bush', 'Krusty', 'Charlie', 'Bush', 'Bozo']", + "var needles = ['Bush', 'Washington']", + "", + "for (var i in needles) {", + " var found = false;", + " for (var j in haystack) {", + " if (haystack[j] == needles[i]) {", + " found = true;", + " break;", + " }", + " }", + " if (found)", + " print(needles[i] + \" appears at index \" + j + \" in the haystack\");", + " else", + " throw needles[i] + \" does not appear in the haystack\"", + "}", + "", + "The following {{works with|JavaScript|1.6}}:", + "for each (var needle in needles) {", + " var idx = haystack.indexOf(needle);", + " if (idx == -1)", + " throw needle + \" does not appear in the haystack\"", + " else", + " print(needle + \" appears at index \" + idx + \" in the haystack\");", + "}", + "", + "// extra credit", + "", + "for each (var elem in haystack) {", + " var first_idx = haystack.indexOf(elem);", + " var last_idx = haystack.lastIndexOf(elem);", + " if (last_idx > first_idx) {", + " print(elem + \" last appears at index \" + last_idx + \" in the haystack\");", + " break", + " }", + "}", + "", + "", + "Or, generalising enough (in ES5) to allow for varying definitions of the type of match we are looking for:", + "", + "(function () {", + "", + " function findIndex(fnPredicate, list) {", + " for (var i = 0, lng = list.length; i < lng; i++) {", + " if (fnPredicate(list[i])) {", + " return i;", + " }", + " }", + " return Error(\"not found\");", + " };", + "", + " // DEFINING A PARTICULAR TYPE OF SEARCH MATCH", + " ", + " function matchCaseInsensitive(s, t) {", + " return s.toLowerCase() === t.toLowerCase();", + " }", + "", + " var lstHaystack = [", + " 'Zig', 'Zag', 'Wally', 'Ronald', 'Bush',", + " 'Krusty', 'Charlie', 'Bush', 'Bozo'", + " ],", + " lstReversed = lstHaystack.slice(0).reverse(),", + " iLast = lstHaystack.length - 1,", + " lstNeedles = ['bush', 'washington'];", + "", + " return {", + " 'first': lstNeedles.map(function (s) {", + " return [s, findIndex(function (t) {", + " return matchCaseInsensitive(s, t);", + " },", + " lstHaystack)];", + " }),", + "", + " 'last': lstNeedles.map(function (s) {", + " var varIndex = findIndex(function (t) {", + " return matchCaseInsensitive(s, t);", + " },", + " lstReversed);", + "", + " return [", + " s,", + " typeof varIndex === 'number' ?", + " iLast - varIndex : varIndex", + " ];", + " })", + " }", + "})();", + "", + "Output:", + "", + "{", + " \"first\": [", + " [", + " \"bush\",", + " 4", + " ],", + " [", + " \"washington\",", + " \"Error: not found\"", + " ]", + " ],", + " \"last\": [", + " [", + " \"bush\",", + " 7", + " ],", + " [", + " \"washington\",", + " \"Error: not found\"", + " ]", + " ]", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fd0", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var haystack = ['Zig', 'Zag', 'Wally', 'Ronald', 'Bush', 'Krusty', 'Charlie', 'Bush', 'Bozo']\nvar needles = ['Bush', 'Washington']\n\nfor (var i in needles) {\n var found = false;\n for (var j in haystack) {\n if (haystack[j] == needles[i]) {\n found = true;\n break;\n }\n }\n if (found)\n print(needles[i] + \" appears at index \" + j + \" in the haystack\");\n else\n throw needles[i] + \" does not appear in the haystack\"\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Self-describing numbers", + "type": "Waypoint", + "description": [ + "

    There are several so-called \"self-describing\" or \"self-descriptive\" integers.

    An integer is said to be \"self-describing\" if it has the property that, when digit positions are labeled 0 to N-1, the digit in each position is equal to the number of times that that digit appears in the number.

    For example, 2020 is a four-digit self describing number:

    position 0 has value 2 and there are two 0s in the number;", + " position 1 has value 0 and there are no 1s in the number;", + " position 2 has value 2 and there are two 2s;", + " position 3 has value 0 and there are zero 3s.", + "

    Self-describing numbers < 100.000.000 are: 1210, 2020, 21200, 3211000, 42101000.

    ", + "Task Description", + "Write a function/routine/method/... that will check whether a given positive integer is self-describing.", + "As an optional stretch goal - generate and display the set of self-describing numbers." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|SpiderMonkey}}", + "", + "function is_self_describing(n) {", + " var digits = Number(n).toString().split(\"\").map(function(elem) {return Number(elem)});", + " var len = digits.length;", + " var count = digits.map(function(x){return 0});", + "", + " digits.forEach(function(digit, idx, ary) {", + " if (digit >= count.length)", + " return false", + " count[digit] ++;", + " });", + "", + " return digits.equals(count);", + "}", + "", + "Array.prototype.equals = function(other) {", + " if (this === other)", + " return true; // same object", + " if (this.length != other.length)", + " return false;", + " for (idx in this)", + " if (this[idx] !== other[idx])", + " return false;", + " return true;", + "}", + "", + "for (var i=1; i<=3300000; i++)", + " if (is_self_describing(i))", + " print(i);", + "", + "outputs", + "
    1210",
    +        "2020",
    +        "21200",
    +        "3211000
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fd3", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function is_self_describing(n) {\n var digits = Number(n).toString().split(\"\").map(function(elem) {return Number(elem)});\n var len = digits.length;\n var count = digits.map(function(x){return 0});\n\n digits.forEach(function(digit, idx, ary) {\n if (digit >= count.length)\n return false\n count[digit] ++;\n });\n\n return digits.equals(count);\n}\n\nArray.prototype.equals = function(other) {\n if (this === other)\n return true; // same object\n if (this.length != other.length)\n return false;\n for (idx in this)\n if (this[idx] !== other[idx])\n return false;\n return true;\n}\n\nfor (var i=1; i<=3300000; i++)\n if (is_self_describing(i))\n print(i);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Self-referential sequence", + "type": "Waypoint", + "description": [ + "

    There are several ways to generate a self-referential sequence. One very common one (the Look-and-say sequence) is to start with a positive integer, then generate the next term by concatenating enumerated groups of adjacent alike digits:

    0, 10, 1110, 3110, 132110, 1113122110, 311311222110 ...

    The terms generated grow in length geometrically and never converge.

    Another way to generate a self-referential sequence is to summarize the previous term.

    Count how many of each alike digit there is, then concatenate the sum and digit for each of the sorted enumerated digits. Note that the first five terms are the same as for the previous sequence.

    0, 10, 1110, 3110, 132110, 13123110, 23124110 ... see The On-Line Encyclopedia of Integer Sequences

    Sort the digits largest to smallest. Do not include counts of digits that do not appear in the previous term.

    Depending on the seed value, series generated this way always either converge to a stable value or to a short cyclical pattern. (For our purposes, I'll use converge to mean an element matches a previously seen element.) The sequence shown, with a seed value of 0, converges to a stable value of 1433223110 after 11 iterations. The seed value that converges most quickly is 22. It goes stable after the first element. (The next element is 22, which has been seen before.)

    Task:

    Find all the positive integer seed values under 1000000, for the above convergent self-referential sequence, that takes the largest number of iterations before converging. Then print out the number of iterations and the sequence they return. Note that different permutations of the digits of the seed will yield the same sequence. For this task, assume leading zeros are not permitted.

    Seed Value(s): 9009 9090 9900Iterations: 21 Sequence: (same for all three seeds except for first element)",
    +        "9009",
    +        "2920",
    +        "192210",
    +        "19222110",
    +        "19323110",
    +        "1923123110",
    +        "1923224110",
    +        "191413323110",
    +        "191433125110",
    +        "19151423125110",
    +        "19251413226110",
    +        "1916151413325110",
    +        "1916251423127110",
    +        "191716151413326110",
    +        "191726151423128110",
    +        "19181716151413327110",
    +        "19182716151423129110",
    +        "29181716151413328110",
    +        "19281716151423228110",
    +        "19281716151413427110",
    +        "19182716152413228110",
    +        "
    ", + "

    See also: Self-describing numbers and Look-and-say sequence

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fd4", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Semiprime", + "type": "Waypoint", + "description": [ + "

    Semiprime numbers are natural numbers that are products of exactly two (possibly equal) prime numbers.

    ", + "

    Semiprimes are also known as:

    ", + "

    ::* semi-primes

    ", + "

    ::* biprimes

    ", + "

    ::* bi-primes

    ", + "

    ::* 2-almost primes

    ", + "

    ::* or simply: P2

    ", + "Example: ", + "

    1679 = 23 × 73

    (This particular number was chosen as the length of the Arecibo message).

    ", + "Task;", + "

    Write a function determining whether a given number is semiprime.

    ", + "See also:", + "The Wikipedia article: semiprime.", + "The Wikipedia article: almost prime.", + "The OEIS article: semiprimes which has a shorter definition: the product of two primes." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fd5", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Semordnilap", + "type": "Waypoint", + "description": [ + "

    A semordnilap is a word (or phrase) that spells a different word (or phrase) backward.

    ", + "

    \"Semordnilap\" is a word that itself is a semordnilap.

    Example: lager and regal

    ", + " ", + "Task", + "

    Using only words from the unixdict, report the total number of unique semordnilap pairs, and print 5 examples. (Note that lager/regal and regal/lager should be counted as one unique pair.)

    ", + " ", + "Related tasks", + "Palindrome detection" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{trans|Clojure}}", + "{{works with|Node.js}}", + "#!/usr/bin/env node", + "var fs = require('fs');", + "var sys = require('sys');", + "", + "var dictFile = process.argv[2] || \"unixdict.txt\";", + "", + "var dict = {};", + "fs.readFileSync(dictFile)", + " .toString()", + " .split('\\n')", + " .forEach(function(word) {", + " dict[word] = word.split(\"\").reverse().join(\"\");", + " });", + "", + "function isSemordnilap(word) { return dict[dict[word]]; };", + "", + "var semordnilaps = []", + "for (var key in dict) {", + " if (isSemordnilap(key)) {", + " var rev = dict[key];", + " if (key < rev) {", + " semordnilaps.push([key,rev]) ;", + " }", + " }", + "}", + "", + "var count = semordnilaps.length;", + "sys.puts(\"There are \" + count + \" semordnilaps in \" +", + " dictFile + \". Here are 5:\" );", + "", + "var indices=[]", + "for (var i=0; i", + "", + "{{works with|Rhino|1.7}}", + "", + "#!/usr/bin/env rhino", + "", + "importPackage (java.io)", + "", + "var dictFile = arguments[0] || \"unixdict.txt\";", + "", + "var reader = new BufferedReader(new FileReader(dictFile));", + "var dict = {};", + "var word;", + "while (word = reader.readLine()) {", + " dict[word] = word.split(\"\").reverse().join(\"\");", + "}", + "", + "function isSemordnilap(word) { return dict[dict[word]]; };", + "", + "var semordnilaps = []", + "for (var key in dict) {", + " if (isSemordnilap(key)) {", + " var rev = dict[key];", + " if (key < rev) {", + " semordnilaps.push([key,rev]) ;", + " }", + " }", + "}", + "", + "var count = semordnilaps.length;", + "print(\"There are \" + count + \" semordnilaps in \" +", + " dictFile + \". Here are 5:\" );", + "var indices=[]", + "for (var i=0; i", + "", + "{{out}}", + "
    There are 158 semordnilaps in unixdict.txt.  Here are 5:",
    +        "loot,tool",
    +        "ah,ha",
    +        "dial,laid",
    +        "dine,enid",
    +        "haw,wah
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fd6", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "#!/usr/bin/env node\nvar fs = require('fs');\nvar sys = require('sys');\n\nvar dictFile = process.argv[2] || \"unixdict.txt\";\n\nvar dict = {};\nfs.readFileSync(dictFile)\n .toString()\n .split('\\n')\n .forEach(function(word) {\n dict[word] = word.split(\"\").reverse().join(\"\");\n });\n\nfunction isSemordnilap(word) { return dict[dict[word]]; };\n\nvar semordnilaps = []\nfor (var key in dict) {\n if (isSemordnilap(key)) {\n var rev = dict[key];\n if (key < rev) {\n semordnilaps.push([key,rev]) ;\n }\n }\n}\n\nvar count = semordnilaps.length;\nsys.puts(\"There are \" + count + \" semordnilaps in \" +\n dictFile + \". Here are 5:\" );\n\nvar indices=[]\nfor (var i=0; ireplaceMe is a function.');" + ] + }, + { + "title": "Sequence of non-squares", + "type": "Waypoint", + "description": [ + "Task:", + "

    Show that the following remarkable formula gives the sequence of non-square natural numbers:

    ", + "

    n + floor(1/2 + sqrt(n))

    ", + "Print out the values for n in the range 1 to 22", + "Show that no squares occur for n less than one million

    This sequence is also known as A000037 in the OEIS database.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "Iterative", + "", + "var a = [];", + "for (var i = 1; i < 23; i++) a[i] = i + Math.floor(1/2 + Math.sqrt(i));", + "console.log(a);", + "", + "for (i = 1; i < 1000000; i++) if (Number.isInteger(i + Math.floor(1/2 + Math.sqrt(i))) === false) {", + " console.log(\"The \",i,\"th element of the sequence is a square\");", + "}", + "", + "===ES6===", + "", + "", + "By functional composition", + "", + "(() => {", + "", + " // nonSquare :: Int -> Int", + " let nonSquare = n =>", + " n + floor(1 / 2 + sqrt(n));", + "", + "", + "", + " // floor :: Num -> Int", + " let floor = Math.floor,", + "", + " // sqrt :: Num -> Num", + " sqrt = Math.sqrt,", + "", + " // isSquare :: Int -> Bool", + " isSquare = n => {", + " let root = sqrt(n);", + "", + " return root === floor(root);", + " };", + "", + "", + " // TEST", + " return {", + " first22: Array.from({", + " length: 22", + " }, (_, i) => nonSquare(i + 1)),", + "", + " firstMillionNotSquare: Array.from({", + " length: 10E6", + " }, (_, i) => nonSquare(i + 1))", + " .filter(isSquare)", + " .length === 0", + " };", + "", + "})();", + "", + "{{Out}}", + "{", + " \"first22\":[2, 3, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15,", + " 17, 18, 19, 20, 21, 22, 23, 24, 26, 27], ", + " \"firstMillionNotSquare\":true", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fd9", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var a = [];\nfor (var i = 1; i < 23; i++) a[i] = i + Math.floor(1/2 + Math.sqrt(i));\nconsole.log(a);\n\nfor (i = 1; i < 1000000; i++) if (Number.isInteger(i + Math.floor(1/2 + Math.sqrt(i))) === false) {\n console.log(\"The \",i,\"th element of the sequence is a square\");\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sequence of primes by Trial Division", + "type": "Waypoint", + "description": [ + "Task:", + "

    Generate a sequence of primes by means of trial division.

    ", + "

    Trial division is an algorithm where a candidate number is tested for being a prime by trying to divide it by other numbers.

    You may use primes, or any numbers of your choosing, as long as the result is indeed a sequence of primes.

    The sequence may be bounded (i.e. up to some limit), unbounded, starting from the start (i.e. 2) or above some given value.

    Organize your function as you wish, in particular, it might resemble a filtering operation, or a sieving operation.

    If you want to use a ready-made is_prime function, use one from the Primality by trial division page (i.e., add yours there if it isn't there already).

    ", + "Related tasks:", + " count in factors", + " prime decomposition", + " factors of an integer", + " Sieve of Eratosthenes", + " primality by trial division", + " factors of a Mersenne number", + " trial factoring of a Mersenne number", + " partition an integer X into N primes" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fda", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Set consolidation", + "type": "Waypoint", + "description": [ + "

    Given two sets of items then if any item is common to any set then the result of applying consolidation to those sets is a set of sets whose contents is:

    ", + " The two input sets if no common item exists between the two input sets of items.", + " The single set that is the union of the two input sets if they share a common item.", + "Given N sets of items where N>2 then the result is the same as repeatedly replacing all combinations of two sets by their consolidation until no further consolidation between set pairs is possible.", + "

    If N<2 then consolidation has no strict meaning and the input can be returned.

    Example 1:", + "

    Given the two sets {A,B} and {C,D} then there is no common element between the sets and the result is the same as the input.

    ", + "Example 2:", + "

    Given the two sets {A,B} and {B,D} then there is a common element B between the sets and the result is the single set {B,D,A}. (Note that order of items in a set is immaterial: {A,B,D} is the same as {B,D,A} and {D,A,B}, etc).

    ", + "Example 3:", + "

    Given the three sets {A,B} and {C,D} and {D,B} then there is no common element between the sets {A,B} and {C,D} but the sets {A,B} and {D,B} do share a common element that consolidates to produce the result {B,D,A}. On examining this result with the remaining set, {C,D}, they share a common element and so consolidate to the final output of the single set {A,B,C,D}

    ", + "Example 4:", + "

    The consolidation of the five sets:

    ", + "

    :{H,I,K}, {A,B}, {C,D}, {D,B}, and {F,G,H}

    ", + "

    Is the two sets:

    ", + "

    :{A, C, B, D}, and {G, F, I, H, K}

    ", + "

    See also

    ", + "Connected component (graph theory)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fdb", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Set of real numbers", + "type": "Waypoint", + "description": [ + "

    All real numbers form the uncountable set ℝ. Among its subsets, relatively simple are the convex sets, each expressed as a range between two real numbers a and b where a ≤ b. There are actually four cases for the meaning of \"between\", depending on open or closed boundary:

    ", + "[a, b]: {x | a ≤ x and x ≤ b }", + "(a, b): {x | a < x and x < b }", + "[a, b): {x | a ≤ x and x < b }", + "(a, b]: {x | a < x and x ≤ b }Note that if a = b, of the four only [a, a] would be non-empty.

    Task

    ", + "Devise a way to represent any set of real numbers, for the definition of 'any' in the implementation notes below.", + "Provide methods for these common set operations (x is a real number; A and B are sets):* x ∈ A: determine if x is an element of A", + "

    : example: 1 is in [1, 2), while 2, 3, ... are not.

    ", + "

    * A ∪ B: union of A and B, i.e. {x | x ∈ A or x ∈ B}

    ", + "

    : example: [0, 2) ∪ (1, 3) = [0, 3); [0, 1) ∪ (2, 3] = well, [0, 1) ∪ (2, 3]

    ", + "

    * A ∩ B: intersection of A and B, i.e. {x | x ∈ A and x ∈ B}

    ", + "

    : example: [0, 2) ∩ (1, 3) = (1, 2); [0, 1) ∩ (2, 3] = empty set

    ", + "

    * A - B: difference between A and B, also written as A \\ B, i.e. {x | x ∈ A and x ∉ B}

    ", + "

    : example: [0, 2) − (1, 3) = [0, 1]

    ", + "Test your implementation by checking if numbers 0, 1, and 2 are in any of the following sets:* (0, 1] ∪ [0, 2)", + "

    * [0, 2) ∩ (1, 2]

    ", + "

    * [0, 3) − (0, 1)

    ", + "

    * [0, 3) − [0, 1]

    Implementation notes

    ", + "'Any' real set means 'sets that can be expressed as the union of a finite number of convex real sets'. Cantor's set needs not apply.", + "Infinities should be handled gracefully; indeterminate numbers (NaN) can be ignored.", + "You can use your machine's native real number representation, which is probably IEEE floating point, and assume it's good enough (it usually is).", + "

    Optional work

    ", + "Create a function to determine if a given set is empty (contains no element).", + "Define A = {x | 0 < x < 10 and |sin(π x²)| > 1/2 }, B = {x | 0 < x < 10 and |sin(π x)| > 1/2}, calculate the length of the real axis covered by the set A − B. Note that |sin(π x)| > 1/2 is the same as n + 1/6 < x < n + 5/6 for all integers n; your program does not need to derive this by itself." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fdc", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Set puzzle", + "type": "Waypoint", + "description": [ + "

    Set Puzzles are created with a deck of cards from the Set Game™. The object of the puzzle is to find sets of 3 cards in a rectangle of cards that have been dealt face up.

    ", + "

    There are 81 cards in a deck.

    ", + "

    Each card contains a unique variation of the following four features: color, symbol, number and shading.

    there are three colors: red, green, purple", + "there are three symbols: oval, squiggle, diamond", + "there is a number of symbols on the card: one, two, three", + "there are three shadings: solid, open, striped", + "

    Three cards form a set if each feature is either the same on each card, or is different on each card. For instance: all 3 cards are red, all 3 cards have a different symbol, all 3 cards have a different number of symbols, all 3 cards are striped.

    There are two degrees of difficulty: basic and advanced. The basic mode deals 9 cards, that contain exactly 4 sets; the advanced mode deals 12 cards that contain exactly 6 sets.

    When creating sets you may use the same card more than once.

    ", + "Task", + "

    Write code that deals the cards (9 or 12, depending on selected mode) from a shuffled deck in which the total number of sets that could be found is 4 (or 6, respectively); and print the contents of the cards and the sets.

    For instance:

    DEALT 9 CARDS:

    green, one, oval, striped

    green, one, diamond, open

    green, one, diamond, striped

    green, one, diamond, solid

    purple, one, diamond, open

    purple, two, squiggle, open

    purple, three, oval, open

    red, three, oval, open

    red, three, diamond, solid

    ", + "

    CONTAINING 4 SETS:

    green, one, oval, striped

    purple, two, squiggle, open

    red, three, diamond, solid

    ", + "

    green, one, diamond, open

    green, one, diamond, striped

    green, one, diamond, solid

    ", + "

    green, one, diamond, open

    purple, two, squiggle, open

    red, three, oval, open

    ", + "

    purple, one, diamond, open

    purple, two, squiggle, open

    purple, three, oval, open

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fdd", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Set", + "type": "Waypoint", + "description": [ + "

    A set is a collection of elements, without duplicates and without order.

    ", + "Task:", + "

    Show each of these set operations:

    Set creation", + "Test m ∈ S -- \"m is an element in set S\"", + "A ∪ B -- union; a set of all elements either in set A or in set B.", + "A ∩ B -- intersection; a set of all elements in both set A and set B.", + "A ∖ B -- difference; a set of all elements in set A, except those in set B.", + "A ⊆ B -- subset; true if every element in set A is also in set B.", + "A = B -- equality; true if every element of set A is in set B and vice versa.", + "

    As an option, show some other set operations.

    ", + "(If A ⊆ B, but A ≠ B, then A is called a true or proper subset of B, written A ⊂ B or A ⊊ B.)

    As another option, show how to modify a mutable set.

    ", + "

    One might implement a set using an associative array (with set elements as array keys and some dummy value as the values).

    One might also implement a set with a binary search tree, or with a hash table, or with an ordered array of binary bits (operated on with bit-wise binary operators).

    The basic test, m ∈ S, is O(n) with a sequential list of elements, O(log n) with a balanced binary search tree, or (O(1) average-case, O(n) worst case) with a hash table.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "JavaScript does not support native sets before ECMAScript 6. ", + "", + "", + "var set = new Set();", + "", + "set.add(0);", + "set.add(1);", + "set.add('two');", + "set.add('three');", + "", + "set.has(0); //=> true", + "set.has(3); //=> false", + "set.has('two'); // true", + "set.has(Math.sqrt(4)); //=> false", + "set.has('TWO'.toLowerCase()); //=> true", + "", + "set.size; //=> 4", + "", + "set.delete('two');", + "set.has('two'); //==> false", + "set.size; //=> 3", + "", + "//iterating set using ES6 for..of", + "//Set order is preserved in order items are added.", + "for (var item of set) {", + " console.log('item is ' + item);", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fde", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nvar set = new Set();\n\nset.add(0);\nset.add(1);\nset.add('two');\nset.add('three');\n\nset.has(0); //=> true\nset.has(3); //=> false\nset.has('two'); // true\nset.has(Math.sqrt(4)); //=> false\nset.has('TWO'.toLowerCase()); //=> true\n\nset.size; //=> 4\n\nset.delete('two');\nset.has('two'); //==> false\nset.size; //=> 3\n\n//iterating set using ES6 for..of\n//Set order is preserved in order items are added.\nfor (var item of set) {\n console.log('item is ' + item);\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Seven-sided dice from five-sided dice", + "type": "Waypoint", + "description": [ + "Task:", + "

    (Given an equal-probability generator of one of the integers 1 to 5

    ", + "

    as dice5), create dice7 that generates a pseudo-random integer from

    ", + "

    1 to 7 in equal probability using only dice5 as a source of random

    ", + "

    numbers, and check the distribution for at least one million calls using the function created in Simple Random Distribution Checker.

    ", + "

    Implementation suggestion:

    ", + "

    dice7 might call dice5 twice, re-call if four of the 25

    ", + "

    combinations are given, otherwise split the other 21 combinations

    ", + "

    into 7 groups of three, and return the group index from the rolls.

    (Task adapted from an answer here)

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{trans|Ruby}}", + "function dice5()", + "{", + " return 1 + Math.floor(5 * Math.random());", + "}", + "", + "function dice7()", + "{", + " while (true)", + " {", + " var dice55 = 5 * dice5() + dice5() - 6;", + " if (dice55 < 21)", + " return dice55 % 7 + 1;", + " }", + "}", + "", + "distcheck(dice5, 1000000);", + "print();", + "distcheck(dice7, 1000000);", + "{{out}}", + "
    1       199792",
    +        "2       200425",
    +        "3       199243",
    +        "4       200407",
    +        "5       200133",
    +        "",
    +        "1       143617",
    +        "2       142209",
    +        "3       143023",
    +        "4       142990",
    +        "5       142894",
    +        "6       142648",
    +        "7       142619 
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fdf", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function dice5()\n{\n return 1 + Math.floor(5 * Math.random());\n}\n\nfunction dice7()\n{\n while (true)\n {\n var dice55 = 5 * dice5() + dice5() - 6;\n if (dice55 < 21)\n return dice55 % 7 + 1;\n }\n}\n\ndistcheck(dice5, 1000000);\nprint();\ndistcheck(dice7, 1000000);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "SHA-1", + "type": "Waypoint", + "description": [ + "

    SHA-1 or SHA1 is a one-way hash function;

    ", + "

    it computes a 160-bit message digest.

    ", + "

    SHA-1 often appears in security protocols; for example,

    ", + "

    many HTTPS websites use RSA with SHA-1 to secure their connections.

    ", + "

    BitTorrent uses SHA-1 to verify downloads.

    ", + "

    Git and Mercurial use SHA-1 digests to identify commits.

    A US government standard, FIPS 180-1, defines SHA-1.

    Find the SHA-1 message digest for a string of octets. You may either call a SHA-1 library, or implement SHA-1 in your language. Both approaches interest Rosetta Code.

    {{alertbox|lightgray|Warning: SHA-1 has known weaknesses. Theoretical attacks may find a collision after 252 operations, or perhaps fewer.

    ", + "

    This is much faster than a brute force attack of 280 operations. USgovernment deprecated SHA-1.

    ", + "

    For production-grade cryptography, users may consider a stronger alternative, such as SHA-256 (from the SHA-2 family) or the upcoming SHA-3.}}

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fe1", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "SHA-256", + "type": "Waypoint", + "description": [ + "

    SHA-256 is the recommended stronger alternative to SHA-1. See FIPS PUB 180-4 for implementation details.

    Either by using a dedicated library or implementing the algorithm in your language, show that the SHA-256 digest of the string \"Rosetta code\" is: 764faf5c61ac315f1497f9dfa542713965b785e5cc2f707d6468d7d1124cdfcf

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fe2", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Shell one-liner", + "type": "Waypoint", + "description": [ + "Task:", + "

    Show how to specify and execute a short program in the language from a command shell, where the input to the command shell is only one line in length.

    Avoid depending on the particular shell or operating system used as much as is reasonable; if the language has notable implementations which have different command argument syntax, or the systems those implementations run on have different styles of shells, it would be good to show multiple examples.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|SpiderMonkey}}", + "$ js -e 'print(\"hello\")'", + "hello", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fe3", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "null\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Short-circuit evaluation", + "type": "Waypoint", + "description": [ + "

    Assume functions a and b return boolean values, and further, the execution of function b takes considerable resources without side effects, and is to be minimized.

    If we needed to compute the conjunction (and):

    ", + "

    ::: x = a() and b()

    Then it would be best to not compute the value of b() if the value of a() is computed as false, as the value of x can then only ever be false.

    Similarly, if we needed to compute the disjunction (or):

    ", + "

    ::: y = a() or b()

    Then it would be best to not compute the value of b() if the value of a() is computed as true, as the value of y can then only ever be true.

    Some languages will stop further computation of boolean equations as soon as the result is known, so-called short-circuit evaluation of boolean expressions

    ", + "Task:", + "

    Create two functions named a and b, that take and return the same boolean value.

    The functions should also print their name whenever they are called.

    Calculate and assign the values of the following equations to a variable in such a way that function b is only called when necessary:

    ", + "

    ::: x = a(i) and b(j)

    ", + "

    ::: y = a(i) or b(j)

    If the language does not have short-circuit evaluation, this might be achieved with nested if statements." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "Short-circuiting evaluation of boolean expressions has been the default since the first versions of JavaScript.", + "", + "(function () {", + " 'use strict';", + "", + " function a(bool) {", + " console.log('a -->', bool);", + "", + " return bool;", + " }", + "", + " function b(bool) {", + " console.log('b -->', bool);", + "", + " return bool;", + " }", + " ", + " ", + " var x = a(false) && b(true),", + " y = a(true) || b(false),", + " z = true ? a(true) : b(false);", + " ", + " return [x, y, z];", + "})();", + "", + "The console log shows that in each case (the binding of all three values), only the left-hand part of the expression (the application of ''a(expr)'') was evaluated – ''b(expr)'' was skipped by logical short-circuiting.", + "", + "{{Out}}", + "", + "Console:", + "
    /* a --> false */",
    +        "/* a --> true */",
    +        "/* a --> true */
    ", + "", + "Return value:", + "
    [false, true, true]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fe4", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function () {\n 'use strict';\n\n function a(bool) {\n console.log('a -->', bool);\n\n return bool;\n }\n\n function b(bool) {\n console.log('b -->', bool);\n\n return bool;\n }\n \n \n var x = a(false) && b(true),\n y = a(true) || b(false),\n z = true ? a(true) : b(false);\n \n return [x, y, z];\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sieve of Eratosthenes", + "type": "Waypoint", + "description": [ + "

    The Sieve of Eratosthenes is a simple algorithm that finds the prime numbers up to a given integer.

    ", + "Task:", + "

    Implement the Sieve of Eratosthenes algorithm, with the only allowed optimization that the outer loop can stop at the square root of the limit, and the inner loop may start at the square of the prime just found.

    That means especially that you shouldn't optimize by using pre-computed wheels, i.e. don't assume you need only to cross out odd numbers (wheel based on 2), numbers equal to 1 or 5 modulo 6 (wheel based on 2 and 3), or similar wheels based on low primes.

    If there's an easy way to add such a wheel based optimization, implement it as an alternative version.

    ", + "Note:", + "It is important that the sieve algorithm be the actual algorithm used to find prime numbers for the task.Related tasks:", + " Emirp primes", + " count in factors", + " prime decomposition", + " factors of an integer", + " extensible prime generator", + " primality by trial division", + " factors of a Mersenne number", + " trial factoring of a Mersenne number", + " partition an integer X into N primes", + " sequence of primes by Trial Division" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function eratosthenes(limit) {", + " var primes = [];", + " if (limit >= 2) {", + " var sqrtlmt = Math.sqrt(limit) - 2;", + " var nums = new Array(); // start with an empty Array...", + " for (var i = 2; i <= limit; i++) // and", + " nums.push(i); // only initialize the Array once...", + " for (var i = 0; i <= sqrtlmt; i++) {", + " var p = nums[i]", + " if (p)", + " for (var j = p * p - 2; j < nums.length; j += p)", + " nums[j] = 0;", + " }", + " for (var i = 0; i < nums.length; i++) {", + " var p = nums[i];", + " if (p)", + " primes.push(p);", + " }", + " }", + " return primes;", + "}", + "", + "var primes = eratosthenes(100);", + "", + "if (typeof print == \"undefined\")", + " print = (typeof WScript != \"undefined\") ? WScript.Echo : alert;", + "print(primes);", + "outputs:", + "
    2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97
    ", + "", + "Substituting the following code for the function for '''an odds-only algorithm using bit packing''' for the array produces code that is many times faster than the above:", + "", + "function eratosthenes(limit) {", + " var prms = [];", + " if (limit >= 2) prms = [2];", + " if (limit >= 3) {", + " var sqrtlmt = (Math.sqrt(limit) - 3) >> 1;", + " var lmt = (limit - 3) >> 1;", + " var bfsz = (lmt >> 5) + 1", + " var buf = [];", + " for (var i = 0; i < bfsz; i++)", + " buf.push(0);", + " for (var i = 0; i <= sqrtlmt; i++)", + " if ((buf[i >> 5] & (1 << (i & 31))) == 0) {", + " var p = i + i + 3;", + " for (var j = (p * p - 3) >> 1; j <= lmt; j += p)", + " buf[j >> 5] |= 1 << (j & 31);", + " }", + " for (var i = 0; i <= lmt; i++)", + " if ((buf[i >> 5] & (1 << (i & 31))) == 0)", + " prms.push(i + i + 3);", + " }", + " return prms;", + "}", + "", + "While the above code is quite fast especially using an efficient JavaScript engine such as Google Chrome's V8, it isn't as elegant as it could be using the features of the new EcmaScript6 specification when it comes out about the end of 2014 and when JavaScript engines including those of browsers implement that standard in that we might choose to implement an incremental algorithm iterators or generators similar to as implemented in Python or F# (yield). Meanwhile, we can emulate some of those features by using a simulation of an iterator class (which is easier than using a call-back function) for an '''\"infinite\" generator based on an Object dictionary''' as in the following odds-only code written as a JavaScript class:", + "", + "var SoEIncClass = (function () {", + " function SoEIncClass() {", + " this.n = 0;", + " }", + " SoEIncClass.prototype.next = function () {", + " this.n += 2;", + " if (this.n < 7) { // initialization of sequence to avoid runaway:", + " if (this.n < 3) { // only even of two:", + " this.n = 1; // odds from here...", + " return 2;", + " }", + " if (this.n < 5)", + " return 3;", + " this.dict = {}; // n must be 5...", + " this.bps = new SoEIncClass(); // new source of base primes", + " this.bps.next(); // advance past the even prime of two...", + " this.p = this.bps.next(); // first odd prime (3 in this case)", + " this.q = this.p * this.p; // set guard", + " return 5;", + " } else { // past initialization:", + " var s = this.dict[this.n]; // may or may not be defined...", + " if (!s) { // not defined:", + " if (this.n < this.q) // haven't reached the guard:", + " return this.n; // found a prime", + " else { // n === q => not prime but at guard, so:", + " var p2 = this.p << 1; // the span odds-only is twice prime", + " this.dict[this.n + p2] = p2; // add next composite of prime to dict", + " this.p = this.bps.next();", + " this.q = this.p * this.p; // get next base prime guard", + " return this.next(); // not prime so advance...", + " }", + " } else { // is a found composite of previous base prime => not prime", + " delete this.dict[this.n]; // advance to next composite of this prime:", + " var nxt = this.n + s;", + " while (this.dict[nxt]) nxt += s; // find unique empty slot in dict", + " this.dict[nxt] = s; // to put the next composite for this base prime", + " return this.next(); // not prime so advance...", + " }", + " }", + " };", + " return SoEIncClass;", + "})();", + "", + "The above code can be used to find the nth prime (which would require estimating the required range limit using the previous fixed range code) by using the following code:", + "", + "var gen = new SoEIncClass(); ", + "for (var i = 1; i < 1000000; i++, gen.next());", + "var prime = gen.next();", + " ", + "if (typeof print == \"undefined\")", + " print = (typeof WScript != \"undefined\") ? WScript.Echo : alert;", + "print(prime);", + "", + "to produce the following output (about five seconds using Google Chrome's V8 JavaScript engine):", + "", + "
    15485863
    ", + "", + "The above code is considerably slower than the fixed range code due to the multiple method calls and the use of an object as a dictionary, which (using a hash table as its basis for most implementations) will have about a constant O(1) amortized time per operation but has quite a high constant overhead to convert the numeric indices to strings which are then hashed to be used as table keys for the look-up operations as compared to doing this more directly in implementations such as the Python dict with Python's built-in hashing functions for every supported type.", + "", + "This can be implemented as '''an \"infinite\" odds-only generator using page segmentation''' for a considerable speed-up with the alternate JavaScript class code as follows:", + "", + "var SoEPgClass = (function () {", + " function SoEPgClass() {", + " this.bi = -1; // constructor resets the enumeration to start...", + " }", + " SoEPgClass.prototype.next = function () {", + " if (this.bi < 1) {", + " if (this.bi < 0) {", + " this.bi++;", + " this.lowi = 0; // other initialization done here...", + " this.bpa = [];", + " return 2;", + " } else { // bi must be zero:", + " var nxt = 3 + (this.lowi << 1) + 262144;", + " this.buf = new Array();", + " for (var i = 0; i < 4096; i++) // faster initialization:", + " this.buf.push(0);", + " if (this.lowi <= 0) { // special culling for first page as no base primes yet:", + " for (var i = 0, p = 3, sqr = 9; sqr < nxt; i++, p += 2, sqr = p * p)", + " if ((this.buf[i >> 5] & (1 << (i & 31))) === 0)", + " for (var j = (sqr - 3) >> 1; j < 131072; j += p)", + " this.buf[j >> 5] |= 1 << (j & 31);", + " } else { // after the first page:", + " if (!this.bpa.length) { // if this is the first page after the zero one:", + " this.bps = new SoEPgClass(); // initialize separate base primes stream:", + " this.bps.next(); // advance past the only even prime of two", + " this.bpa.push(this.bps.next()); // get the next prime (3 in this case)", + " }", + " // get enough base primes for the page range...", + " for (var p = this.bpa[this.bpa.length - 1], sqr = p * p; sqr < nxt;", + " p = this.bps.next(), this.bpa.push(p), sqr = p * p) ;", + " for (var i = 0; i < this.bpa.length; i++) {", + " var p = this.bpa[i];", + " var s = (p * p - 3) >> 1;", + " if (s >= this.lowi) // adjust start index based on page lower limit...", + " s -= this.lowi;", + " else {", + " var r = (this.lowi - s) % p;", + " s = (r != 0) ? p - r : 0;", + " }", + " for (var j = s; j < 131072; j += p)", + " this.buf[j >> 5] |= 1 << (j & 31);", + " }", + " }", + " }", + " }", + " while (this.bi < 131072 && this.buf[this.bi >> 5] & (1 << (this.bi & 31)))", + " this.bi++; // find next marker still with prime status", + " if (this.bi < 131072) // within buffer: output computed prime", + " return 3 + ((this.lowi + this.bi++) << 1);", + " else { // beyond buffer range: advance buffer", + " this.bi = 0;", + " this.lowi += 131072;", + " return this.next(); // and recursively loop", + " }", + " };", + " return SoEPgClass;", + "})();", + "", + "The above code is about fifty times faster (about five seconds to calculate 50 million primes to about a billion on the Google Chrome V8 JavaScript engine) than the above dictionary based code.", + "", + "The speed for both of these \"infinite\" solutions will also respond to further wheel factorization techniques, especially for the dictionary based version where any added overhead to deal with the factorization wheel will be negligible compared to the dictionary overhead. The dictionary version would likely speed up about a factor of three or a little more with maximum wheel factorization applied; the page segmented version probably won't gain more than a factor of two and perhaps less due to the overheads of array look-up operations.", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fea", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function eratosthenes(limit) {\n var primes = [];\n if (limit >= 2) {\n var sqrtlmt = Math.sqrt(limit) - 2;\n var nums = new Array(); // start with an empty Array...\n for (var i = 2; i <= limit; i++) // and\n nums.push(i); // only initialize the Array once...\n for (var i = 0; i <= sqrtlmt; i++) {\n var p = nums[i]\n if (p)\n for (var j = p * p - 2; j < nums.length; j += p)\n nums[j] = 0;\n }\n for (var i = 0; i < nums.length; i++) {\n var p = nums[i];\n if (p)\n primes.push(p);\n }\n }\n return primes;\n}\n\nvar primes = eratosthenes(100);\n\nif (typeof print == \"undefined\")\n print = (typeof WScript != \"undefined\") ? WScript.Echo : alert;\nprint(primes);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Singleton", + "type": "Waypoint", + "description": [ + "

    A Global Singleton is a class of which only one instance exists within a program.

    Any attempt to use non-static members of the class involves performing operations on this one instance.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function Singleton() {", + "\tif(Singleton._instance) return Singleton._instance;", + "\tthis.set(\"\");", + "\tSingleton._instance = this;", + "}", + "", + "Singleton.prototype.set = function(msg) { this.msg = msg; }", + "Singleton.prototype.append = function(msg) { this.msg += msg; }", + "Singleton.prototype.get = function() { return this.msg; }", + "", + "", + "var a = new Singleton();", + "var b = new Singleton();", + "var c = new Singleton();", + "", + "a.set(\"Hello\");", + "b.append(\" World\");", + "c.append(\"!!!\");", + "", + "document.write( (new Singleton()).get() );", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fef", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function Singleton() {\n\tif(Singleton._instance) return Singleton._instance;\n\tthis.set(\"\");\n\tSingleton._instance = this;\n}\n\nSingleton.prototype.set = function(msg) { this.msg = msg; }\nSingleton.prototype.append = function(msg) { this.msg += msg; }\nSingleton.prototype.get = function() { return this.msg; }\n\n\nvar a = new Singleton();\nvar b = new Singleton();\nvar c = new Singleton();\n\na.set(\"Hello\");\nb.append(\" World\");\nc.append(\"!!!\");\n\ndocument.write( (new Singleton()).get() );\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Singly-linked list/Element definition", + "type": "Waypoint", + "description": [ + "

    Define the data structure for a singly-linked list element. Said element should contain a data member capable of holding a numeric value, and the link to the next element should be mutable.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function LinkedList(value, next) {", + " this._value = value;", + " this._next = next;", + "}", + "LinkedList.prototype.value = function() {", + " if (arguments.length == 1) ", + " this._value = arguments[0];", + " else", + " return this._value;", + "}", + "LinkedList.prototype.next = function() {", + " if (arguments.length == 1) ", + " this._next = arguments[0];", + " else", + " return this._next;", + "}", + "", + "// convenience function to assist the creation of linked lists.", + "function createLinkedListFromArray(ary) {", + " var head = new LinkedList(ary[0], null);", + " var prev = head;", + " for (var i = 1; i < ary.length; i++) {", + " var node = new LinkedList(ary[i], null);", + " prev.next(node);", + " prev = node;", + " }", + " return head;", + "}", + "", + "var head = createLinkedListFromArray([10,20,30,40]);", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ff0", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function LinkedList(value, next) {\n this._value = value;\n this._next = next;\n}\nLinkedList.prototype.value = function() {\n if (arguments.length == 1) \n this._value = arguments[0];\n else\n return this._value;\n}\nLinkedList.prototype.next = function() {\n if (arguments.length == 1) \n this._next = arguments[0];\n else\n return this._next;\n}\n\n// convenience function to assist the creation of linked lists.\nfunction createLinkedListFromArray(ary) {\n var head = new LinkedList(ary[0], null);\n var prev = head;\n for (var i = 1; i < ary.length; i++) {\n var node = new LinkedList(ary[i], null);\n prev.next(node);\n prev = node;\n }\n return head;\n}\n\nvar head = createLinkedListFromArray([10,20,30,40]);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Singly-linked list/Element insertion", + "type": "Waypoint", + "description": [ + "

    Using the link element defined in Singly-Linked List (element), define a method to insert an element into a singly-linked list following a given element.

    Using this method, insert an element C into a list comprised of elements A->B, following element A.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Extending [[Singly-Linked_List_(element)#JavaScript]]", + "LinkedList.prototype.insertAfter = function(searchValue, nodeToInsert) {", + " if (this._value == searchValue) {", + " nodeToInsert.next(this.next());", + " this.next(nodeToInsert);", + " }", + " else if (this.next() == null) ", + " throw new Error(0, \"value '\" + searchValue + \"' not found in linked list.\")", + " else", + " this.next().insertAfter(searchValue, nodeToInsert);", + "}", + "var list = createLinkedListFromArray(['A','B']);", + "list.insertAfter('A', new LinkedList('C', null));", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ff1", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "LinkedList.prototype.insertAfter = function(searchValue, nodeToInsert) {\n if (this._value == searchValue) {\n nodeToInsert.next(this.next());\n this.next(nodeToInsert);\n }\n else if (this.next() == null) \n throw new Error(0, \"value '\" + searchValue + \"' not found in linked list.\")\n else\n this.next().insertAfter(searchValue, nodeToInsert);\n}\nvar list = createLinkedListFromArray(['A','B']);\nlist.insertAfter('A', new LinkedList('C', null));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Singly-linked list/Traversal", + "type": "Waypoint", + "description": [ + "

    Traverse from the beginning of a singly-linked list to the end.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Extending [[Singly-Linked_List_(element)#JavaScript]]", + "LinkedList.prototype.traverse = function(func) {", + " func(this);", + " if (this.next() != null)", + " this.next().traverse(func);", + "}", + "", + "LinkedList.prototype.print = function() {", + " this.traverse( function(node) {print(node.value())} );", + "}", + "", + "var head = createLinkedListFromArray([10,20,30,40]);", + "head.print();", + "Uses the print() function from [[Rhino]]", + "", + "", + "Alternatively, translating the [[#Haskell | Haskell]] examples in terms of JavaScript's Array.map, Array.reduce, and Array.forEach:", + "", + "var map = function (fn, list) {", + " return list.map(fn);", + " },", + "", + " foldr = function (fn, acc, list) {", + " var listr = list.slice();", + " listr.reverse();", + "", + " return listr.reduce(fn, acc);", + " },", + "", + " traverse = function (list, fn) {", + " return list.forEach(fn);", + " };", + "", + "var range = function (m, n) {", + " return Array.apply(null, Array(n - m + 1)).map(", + " function (x, i) {", + " return m + i;", + " }", + " );", + "};", + "", + "// --> [false, false, false, false, false, true, true, true, true, true]", + "map(function (x) {", + " return x > 5;", + "}, range(1, 10));", + "", + "// --> [\"Apples\", \"Oranges\", \"Mangos\", \"Pears\"]", + "map(function (x) {", + " return x + 's';", + "}, [\"Apple\", \"Orange\", \"Mango\", \"Pear\"])", + "", + "// --> 55", + "foldr(function (acc, x) {", + " return acc + x;", + "}, 0, range(1, 10))", + "", + "", + "traverse([\"Apple\", \"Orange\", \"Mango\", \"Pear\"], function (x) {", + " console.log(x);", + "})", + "/* Apple */", + "/* Orange */", + "/* Mango */", + "/* Pear */", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ff2", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "LinkedList.prototype.traverse = function(func) {\n func(this);\n if (this.next() != null)\n this.next().traverse(func);\n}\n\nLinkedList.prototype.print = function() {\n this.traverse( function(node) {print(node.value())} );\n}\n\nvar head = createLinkedListFromArray([10,20,30,40]);\nhead.print();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Smith numbers", + "type": "Waypoint", + "description": [ + "

    Smith numbers are numbers such that the sum of the decimal digits of the integers that make up that number is the same as the sum of the decimal digits of its prime factors excluding 1.

    By definition, all primes are excluded as they (naturally) satisfy this condition!

    Smith numbers are also known as joke numbers.

    ", + "Example", + "

    Using the number 166

    ", + "

    Find the prime factors of 166 which are: 2 x 83

    ", + "

    Then, take those two prime factors and sum all their decimal digits: 2 + 8 + 3 which is 13

    ", + "

    Then, take the decimal digits of 166 and add their decimal digits: 1 + 6 + 6 which is 13

    ", + "

    Therefore, the number 166 is a Smith number.

    ", + "Task", + "

    Write a program to find all Smith numbers below 10000.

    ", + "See also", + "from Wikipedia: https://en.wikipedia.org/wiki/Smith_number Smith number.", + "from MathWorld: http://mathworld.wolfram.com/SmithNumber.html Smith number. ", + "from OEIS A6753: https://oeis.org/A006753 OEIS sequence A6753.", + "from OEIS A104170: https://oeis.org/A104170 Number of Smith numbers below 10^n. ", + "from The Prime pages: http://primes.utm.edu/glossary/xpage/SmithNumber.html Smith numbers." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES6===", + "{{Trans|Haskell}}", + "(() => {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS -----------------------------------------------------", + "", + " // concat :: [[a]] -> [a] | [String] -> String", + " const concat = xs => {", + " if (xs.length > 0) {", + " const unit = typeof xs[0] === 'string' ? '' : [];", + " return unit.concat.apply(unit, xs);", + " } else return [];", + " }", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // dropWhile :: (a -> Bool) -> [a] -> [a]", + " const dropWhile = (p, xs) => {", + " let i = 0;", + " for (let lng = xs.length;", + " (i < lng) && p(xs[i]); i++) {}", + " return xs.slice(i);", + " }", + "", + " // head :: [a] -> a", + " const head = xs => xs.length ? xs[0] : undefined;", + "", + " // Int -> [a] -> [a]", + " const take = (n, xs) => xs.slice(0, n);", + "", + " // drop :: Int -> [a] -> [a]", + " const drop = (n, xs) => xs.slice(n);", + "", + " // floor :: Num a => a -> Int", + " const floor = Math.floor;", + "", + " // floor :: Num -> Num", + " const sqrt = Math.sqrt;", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x, null, 2);", + "", + " // unwords :: [String] -> String", + " const unwords = xs => xs.join(' ');", + "", + "", + " // MAIN -----------------------------------------------------------------", + "", + " // primeFactors :: Int -> [Int]", + " const primeFactors = n => {", + " const fs = take(1, (dropWhile(x => n % x !== 0, range(2, floor(sqrt(n))))));", + " return fs.length === 0 ? (", + " [n]", + " ) : fs.concat(primeFactors(floor(n / head(fs))));", + " };", + "", + " // digitSum :: [Char] -> Int", + " const digitSum = ds =>", + " ds", + " .reduce((a, b) => parseInt(a, 10) + parseInt(b, 10), 0);", + "", + " // isSmith :: Int -> Bool", + " const isSmith = n => {", + " const pfs = primeFactors(n);", + " return (head(pfs) !== n) &&", + " digitSum(n.toString()", + " .split('')) == digitSum(", + " concat(pfs.map(x => x.toString()))", + " .split('')", + " );", + " }", + "", + " // TEST ------------------------------------------------------------------", + "", + " // lowSmiths :: [Int]", + " const lowSmiths = range(2, 9999)", + " .filter(isSmith);", + "", + " // lowSmithCount :: Int", + " const lowSmithCount = lowSmiths.length;", + "", + " return [", + " \"Count of Smith Numbers below 10k:\",", + " show(lowSmithCount),", + " \"\\nFirst 15 Smith Numbers:\",", + " unwords(take(15, lowSmiths)),", + " \"\\nLast 12 Smith Numbers below 10000:\",", + " unwords(drop(lowSmithCount - 12, lowSmiths))", + " ].join('\\n');", + "})();", + "{{Out}}", + "
    Count of Smith Numbers below 10k:",
    +        "376",
    +        "",
    +        "First 15 Smith Numbers:",
    +        "4 22 27 58 85 94 121 166 202 265 274 319 346 355 378",
    +        "",
    +        "Last 12 Smith Numbers below 10000:",
    +        "9778 9840 9843 9849 9861 9880 9895 9924 9942 9968 9975 9985
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ff4", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n 'use strict';\n\n // GENERIC FUNCTIONS -----------------------------------------------------\n\n // concat :: [[a]] -> [a] | [String] -> String\n const concat = xs => {\n if (xs.length > 0) {\n const unit = typeof xs[0] === 'string' ? '' : [];\n return unit.concat.apply(unit, xs);\n } else return [];\n }\n\n // range :: Int -> Int -> [Int]\n const range = (m, n) =>\n Array.from({\n length: Math.floor(n - m) + 1\n }, (_, i) => m + i);\n\n // dropWhile :: (a -> Bool) -> [a] -> [a]\n const dropWhile = (p, xs) => {\n let i = 0;\n for (let lng = xs.length;\n (i < lng) && p(xs[i]); i++) {}\n return xs.slice(i);\n }\n\n // head :: [a] -> a\n const head = xs => xs.length ? xs[0] : undefined;\n\n // Int -> [a] -> [a]\n const take = (n, xs) => xs.slice(0, n);\n\n // drop :: Int -> [a] -> [a]\n const drop = (n, xs) => xs.slice(n);\n\n // floor :: Num a => a -> Int\n const floor = Math.floor;\n\n // floor :: Num -> Num\n const sqrt = Math.sqrt;\n\n // show :: a -> String\n const show = x => JSON.stringify(x, null, 2);\n\n // unwords :: [String] -> String\n const unwords = xs => xs.join(' ');\n\n\n // MAIN -----------------------------------------------------------------\n\n // primeFactors :: Int -> [Int]\n const primeFactors = n => {\n const fs = take(1, (dropWhile(x => n % x !== 0, range(2, floor(sqrt(n))))));\n return fs.length === 0 ? (\n [n]\n ) : fs.concat(primeFactors(floor(n / head(fs))));\n };\n\n // digitSum :: [Char] -> Int\n const digitSum = ds =>\n ds\n .reduce((a, b) => parseInt(a, 10) + parseInt(b, 10), 0);\n\n // isSmith :: Int -> Bool\n const isSmith = n => {\n const pfs = primeFactors(n);\n return (head(pfs) !== n) &&\n digitSum(n.toString()\n .split('')) == digitSum(\n concat(pfs.map(x => x.toString()))\n .split('')\n );\n }\n\n // TEST ------------------------------------------------------------------\n\n // lowSmiths :: [Int]\n const lowSmiths = range(2, 9999)\n .filter(isSmith);\n\n // lowSmithCount :: Int\n const lowSmithCount = lowSmiths.length;\n\n return [\n \"Count of Smith Numbers below 10k:\",\n show(lowSmithCount),\n \"\\nFirst 15 Smith Numbers:\",\n unwords(take(15, lowSmiths)),\n \"\\nLast 12 Smith Numbers below 10000:\",\n unwords(drop(lowSmithCount - 12, lowSmiths))\n ].join('\\n');\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "SOAP", + "type": "Waypoint", + "description": [ + "

    In this task, the goal is to create a SOAP client which accesses functions defined at http://example.com/soap/wsdl, and calls the functions soapFunc( ) and anotherSoapFunc( ).

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ff5", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sokoban", + "type": "Waypoint", + "description": [ + "

    Demonstrate how to find a solution to a given Sokoban level. For the purpose of this task (formally, a PSPACE-complete problem) any method may be used. However a move-optimal or push-optimal (or any other -optimal) solutions is preferred.

    Sokoban levels are usually stored as a character array where

    ", + "space is an empty square", + "# is a wall", + "@ is the player", + "$ is a box", + ". is a goal", + "+ is the player on a goal", + "* is a box on a goal", + "

    Sokoban solutions are usually stored in the LURD format, where lowercase l, u, r and d represent a move in that (left, up, right, down) direction and capital LURD represents a push.

    Please state if you use some other format for either the input or output, and why.

    For more information, see the Sokoban wiki.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ff7", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Solve a Hidato puzzle", + "type": "Waypoint", + "description": [ + "

    The task is to write a program which solves Hidato (aka Hidoku) puzzles.

    The rules are:

    ", + "You are given a grid with some numbers placed in it. The other squares in the grid will be blank.", + "* The grid is not necessarily rectangular.", + "* The grid may have holes in it.", + "* The grid is always connected.", + "* The number “1” is always present, as is another number that is equal to the number of squares in the grid. Other numbers are present so as to force the solution to be unique.", + "* It may be assumed that the difference between numbers present on the grid is not greater than lucky 13.", + "The aim is to place a natural number in each blank square so that in the sequence of numbered squares from “1” upwards, each square is in the [[wp:Moore neighborhood]] of the squares immediately before and after it in the sequence (except for the first and last squares, of course, which only have one-sided constraints).", + "* Thus, if the grid was overlaid on a chessboard, a king would be able to make legal moves along the path from first to last square in numerical order.", + "* A square may only contain one number.", + "In a proper Hidato puzzle, the solution is unique.", + "For example the following problem", + "

    has the following solution, with path marked on it:

    ", + "Related tasks:", + "A* search algorithm", + "N-queens problem", + "Solve a Holy Knight's tour", + "Solve a Knight's tour", + "Solve a Hopido puzzle", + "Solve a Numbrix puzzle", + "Solve the no connection puzzle;" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ff8", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Solve a Holy Knight's tour", + "type": "Waypoint", + "description": [ + "

    Chess coaches have been known to inflict a kind of torture on beginners by taking a chess board, placing pennies on some squares and requiring that a Knight's tour be constructed that avoids the squares with pennies.

    This kind of knight's tour puzzle is similar to Hidato.

    The present task is to produce a solution to such problems. At least demonstrate your program by solving the following:

    Example 1", + "
    ",
    +        "  0 0 0 ",
    +        "  0   0 0 ",
    +        "  0 0 0 0 0 0 0",
    +        "0 0 0     0   0",
    +        "0   0     0 0 0",
    +        "1 0 0 0 0 0 0",
    +        "    0 0   0",
    +        "      0 0 0",
    +        "

    Note that the zeros represent the available squares, not the pennies.

    Extra credit is available for other interesting examples.

    ", + "Related tasks:", + "A* search algorithm", + "Knight's tour", + "N-queens problem", + "Solve a Hidato puzzle", + "Solve a Hopido puzzle", + "Solve a Numbrix puzzle", + "Solve the no connection puzzle" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES6===", + "By composition of generic functions, cacheing degree-sorted moves for each node.", + "(() => {", + " 'use strict';", + "", + " // problems :: [[String]]", + " const problems = [", + " [", + " \" 000 \" //", + " , \" 0 00 \" //", + " , \" 0000000\" //", + " , \"000 0 0\" //", + " , \"0 0 000\" //", + " , \"1000000 \" //", + " , \" 00 0 \" //", + " , \" 000 \" //", + " ],", + " [", + " \"-----1-0-----\" //", + " , \"-----0-0-----\" //", + " , \"----00000----\" //", + " , \"-----000-----\" //", + " , \"--0--0-0--0--\" //", + " , \"00000---00000\" //", + " , \"--00-----00--\" //", + " , \"00000---00000\" //", + " , \"--0--0-0--0--\" //", + " , \"-----000-----\" //", + " , \"----00000----\" //", + " , \"-----0-0-----\" //", + " , \"-----0-0-----\" //", + " ]", + " ];", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // comparing :: (a -> b) -> (a -> a -> Ordering)", + " const comparing = f =>", + " (x, y) => {", + " const", + " a = f(x),", + " b = f(y);", + " return a < b ? -1 : a > b ? 1 : 0", + " };", + "", + " // concat :: [[a]] -> [a] | [String] -> String", + " const concat = xs =>", + " xs.length > 0 ? (() => {", + " const unit = typeof xs[0] === 'string' ? '' : [];", + " return unit.concat.apply(unit, xs);", + " })() : [];", + "", + " // charColRow :: Char -> [String] -> Maybe (Int, Int)", + " const charColRow = (c, rows) =>", + " foldr((a, xs, iRow) =>", + " a.nothing ? (() => {", + " const mbiCol = elemIndex(c, xs);", + " return mbiCol.nothing ? mbiCol : {", + " just: [mbiCol.just, iRow],", + " nothing: false", + " };", + " })() : a, {", + " nothing: true", + " }, rows);", + "", + " // 2 or more arguments", + " // curry :: Function -> Function", + " const curry = (f, ...args) => {", + " const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :", + " function () {", + " return go(xs.concat(Array.from(arguments)));", + " };", + " return go([].slice.call(args, 1));", + " };", + "", + " // elem :: Eq a => a -> [a] -> Bool", + " const elem = (x, xs) => xs.indexOf(x) !== -1;", + "", + " // elemIndex :: Eq a => a -> [a] -> Maybe Int", + " const elemIndex = (x, xs) => {", + " const i = xs.indexOf(x);", + " return {", + " nothing: i === -1,", + " just: i", + " };", + " };", + "", + " // enumFromTo :: Int -> Int -> [Int]", + " const enumFromTo = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // filter :: (a -> Bool) -> [a] -> [a]", + " const filter = (f, xs) => xs.filter(f);", + "", + " // findIndex :: (a -> Bool) -> [a] -> Maybe Int", + " const findIndex = (f, xs) => {", + " for (var i = 0, lng = xs.length; i < lng; i++) {", + " if (f(xs[i])) return {", + " nothing: false,", + " just: i", + " };", + " }", + " return {", + " nothing: true", + " };", + " };", + "", + " // foldl :: (b -> a -> b) -> b -> [a] -> b", + " const foldl = (f, a, xs) => xs.reduce(f, a);", + "", + " // foldr (a -> b -> b) -> b -> [a] -> b", + " const foldr = (f, a, xs) => xs.reduceRight(f, a);", + "", + " // groupBy :: (a -> a -> Bool) -> [a] -> [[a]]", + " const groupBy = (f, xs) => {", + " const dct = xs.slice(1)", + " .reduce((a, x) => {", + " const", + " h = a.active.length > 0 ? a.active[0] : undefined,", + " blnGroup = h !== undefined && f(h, x);", + " return {", + " active: blnGroup ? a.active.concat([x]) : [x],", + " sofar: blnGroup ? a.sofar : a.sofar.concat([a.active])", + " };", + " }, {", + " active: xs.length > 0 ? [xs[0]] : [],", + " sofar: []", + " });", + " return dct.sofar.concat(dct.active.length > 0 ? [dct.active] : []);", + " };", + "", + " // intercalate :: String -> [a] -> String", + " const intercalate = (s, xs) => xs.join(s);", + "", + " // intersectBy::(a - > a - > Bool) - > [a] - > [a] - > [a]", + " const intersectBy = (eq, xs, ys) =>", + " (xs.length > 0 && ys.length > 0) ?", + " xs.filter(x => ys.some(curry(eq)(x))) : [];", + "", + " // justifyRight :: Int -> Char -> Text -> Text", + " const justifyRight = (n, cFiller, strText) =>", + " n > strText.length ? (", + " (cFiller.repeat(n) + strText)", + " .slice(-n)", + " ) : strText;", + "", + " // length :: [a] -> Int", + " const length = xs => xs.length;", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = (f, xs) => xs.map(f);", + "", + " // mappendComparing :: [(a -> b)] -> (a -> a -> Ordering)", + " const mappendComparing = fs => (x, y) =>", + " fs.reduce((ord, f) => {", + " if (ord !== 0) return ord;", + " const", + " a = f(x),", + " b = f(y);", + " return a < b ? -1 : a > b ? 1 : 0", + " }, 0);", + "", + " // maximumBy :: (a -> a -> Ordering) -> [a] -> a", + " const maximumBy = (f, xs) =>", + " xs.reduce((a, x) => a === undefined ? x : (", + " f(x, a) > 0 ? x : a", + " ), undefined);", + "", + " // min :: Ord a => a -> a -> a", + " const min = (a, b) => b < a ? b : a;", + "", + " // replicate :: Int -> a -> [a]", + " const replicate = (n, a) => {", + " let v = [a],", + " o = [];", + " if (n < 1) return o;", + " while (n > 1) {", + " if (n & 1) o = o.concat(v);", + " n >>= 1;", + " v = v.concat(v);", + " }", + " return o.concat(v);", + " };", + "", + " // sortBy :: (a -> a -> Ordering) -> [a] -> [a]", + " const sortBy = (f, xs) => xs.slice()", + " .sort(f);", + "", + " // splitOn :: String -> String -> [String]", + " const splitOn = (s, xs) => xs.split(s);", + "", + " // take :: Int -> [a] -> [a]", + " const take = (n, xs) => xs.slice(0, n);", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + " // until :: (a -> Bool) -> (a -> a) -> a -> a", + " const until = (p, f, x) => {", + " let v = x;", + " while (!p(v)) v = f(v);", + " return v;", + " };", + "", + " // zip :: [a] -> [b] -> [(a,b)]", + " const zip = (xs, ys) =>", + " xs.slice(0, Math.min(xs.length, ys.length))", + " .map((x, i) => [x, ys[i]]);", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " const zipWith = (f, xs, ys) =>", + " Array.from({", + " length: min(xs.length, ys.length)", + " }, (_, i) => f(xs[i], ys[i]));", + "", + " // HOLY KNIGHT's TOUR FUNCTIONS -------------------------------------------", + "", + " // kmoves :: (Int, Int) -> [(Int, Int)]", + " const kmoves = ([x, y]) => map(", + " ([a, b]) => [a + x, b + y], [", + " [1, 2],", + " [1, -2],", + " [-1, 2],", + " [-1, -2],", + " [2, 1],", + " [2, -1],", + " [-2, 1],", + " [-2, -1]", + " ]);", + "", + " // rowPosns :: Int -> String -> [(Int, Int)]", + " const rowPosns = (iRow, s) => {", + " return foldl((a, x, i) => (elem(x, ['0', '1']) ? (", + " a.concat([", + " [i, iRow]", + " ])", + " ) : a), [], splitOn('', s));", + " };", + "", + " // hash :: (Int, Int) -> String", + " const hash = ([col, row]) => col.toString() + '.' + row.toString();", + "", + " // Start node, and degree-sorted cache of moves from each node", + " // All node references are hash strings (for this cache)", + "", + " // problemModel :: [[String]] -> {cache: {nodeKey: [nodeKey], start:String}}", + " const problemModel = boardLines => {", + " const", + " steps = foldl((a, xs, i) =>", + " a.concat(rowPosns(i, xs)), [], boardLines),", + " courseMoves = (xs, [x, y]) => intersectBy(", + " ([a, b], [c, d]) => a === c && b === d, kmoves([x, y]), xs", + " ),", + " maybeStart = charColRow('1', boardLines);", + " return {", + " start: maybeStart.nothing ? '' : hash(maybeStart.just),", + " boardWidth: boardLines.length > 0 ? boardLines[0].length : 0,", + " stepCount: steps.length,", + " cache: (() => {", + " const moveCache = foldl((a, xy) => (", + " a[hash(xy)] = map(hash, courseMoves(steps, xy)),", + " a", + " ), {}, steps),", + " lstMoves = Object.keys(moveCache),", + " dctDegree = foldl((a, k) =>", + " (a[k] = moveCache[k].length,", + " a), {}, lstMoves);", + "", + " return foldl((a, k) => (", + " a[k] = sortBy(comparing(x => dctDegree[x]), moveCache[k]),", + " a", + " ), {}, lstMoves);", + " })()", + " };", + " };", + "", + " // firstSolution :: {nodeKey: [nodeKey]} -> Int ->", + " // nodeKey -> nodeKey -> [nodeKey] ->", + " // -> {path::[nodeKey], pathLen::Int, found::Bool}", + " const firstSolution = (dctMoves, intTarget, strStart, strNodeKey, path) => {", + " const", + " intPath = path.length,", + " moves = dctMoves[strNodeKey];", + "", + " if ((intTarget - intPath) < 2 && elem(strStart, moves)) {", + " return {", + " nothing: false,", + " just: [strStart, strNodeKey].concat(path),", + " pathLen: intTarget", + " };", + " }", + "", + " const", + " nexts = filter(k => !elem(k, path), moves),", + " intNexts = nexts.length,", + " lstFullPath = [strNodeKey].concat(path);", + "", + " // Until we find a full path back to start", + " return until(", + " x => (x.nothing === false || x.i >= intNexts),", + " x => {", + " const", + " idx = x.i,", + " dctSoln = firstSolution(", + " dctMoves, intTarget, strStart, nexts[idx], lstFullPath", + " );", + " return {", + " i: idx + 1,", + " nothing: dctSoln.nothing,", + " just: dctSoln.just,", + " pathLen: dctSoln.pathLen", + " };", + " }, {", + " nothing: true,", + " just: [],", + " i: 0", + " }", + " );", + " };", + "", + " // maybeTour :: [String] -> {", + " // nothing::Bool, Just::[nodeHash], i::Int: pathLen::Int }", + " const maybeTour = trackLines => {", + " const", + " dctModel = problemModel(trackLines),", + " strStart = dctModel.start;", + " return strStart !== '' ? firstSolution(", + " dctModel.cache, dctModel.stepCount, strStart, strStart, []", + " ) : {", + " nothing: true", + " };", + " };", + "", + " // showLine :: Int -> Int -> String -> Maybe (Int, Int) ->", + " // [(Int, Int, String)] -> String", + " const showLine = curry((intCell, strFiller, maybeStart, xs) => {", + " const", + " blnSoln = maybeStart.nothing,", + " [startCol, startRow] = blnSoln ? [0, 0] : maybeStart.just;", + " return foldl((a, [iCol, iRow, sVal], i, xs) => ({", + " col: iCol + 1,", + " txt: a.txt +", + " concat(replicate((iCol - a.col) * intCell, strFiller)) +", + " justifyRight(", + " intCell, strFiller,", + " (blnSoln ? sVal : (", + " iRow === startRow &&", + " iCol === startCol ? '1' : '0')", + " )", + " )", + " }), {", + " col: 0,", + " txt: ''", + " },", + " xs", + " )", + " .txt", + " });", + "", + " // solutionString :: [String] -> Int -> String", + " const solutionString = (boardLines, iProblem) => {", + " const", + " dtePre = Date.now(),", + " intCols = boardLines.length > 0 ? boardLines[0].length : 0,", + " soln = maybeTour(boardLines),", + " intMSeconds = Date.now() - dtePre;", + "", + " if (soln.nothing) return 'No solution found …';", + "", + " const", + " kCol = 0,", + " kRow = 1,", + " kSeq = 2,", + " steps = soln.just,", + " lstTriples = zipWith((h, n) => {", + " const [col, row] = map(", + " x => parseInt(x, 10), splitOn('.', h)", + " );", + " return [col, row, n.toString()];", + " },", + " steps,", + " enumFromTo(1, soln.pathLen)),", + " cellWidth = length(maximumBy(", + " comparing(x => length(x[kSeq])), lstTriples", + " )[kSeq]) + 1,", + " lstGroups = groupBy(", + " (a, b) => a[kRow] === b[kRow],", + " sortBy(", + " mappendComparing([x => x[kRow], x => x[kCol]]),", + " lstTriples", + " )),", + " startXY = take(2, lstTriples[0]),", + " strMap = 'PROBLEM ' + (parseInt(iProblem, 10) + 1) + '.\\n\\n' +", + " unlines(map(showLine(cellWidth, ' ', {", + " nothing: false,", + " just: startXY", + " }), lstGroups)),", + " strSoln = 'First solution found in c. ' +", + " intMSeconds + ' milliseconds:\\n\\n' +", + " unlines(map(showLine(cellWidth, ' ', {", + " nothing: true,", + " just: startXY", + " }), lstGroups)) + '\\n\\n';", + "", + " console.log(strSoln);", + " return strMap + '\\n\\n' + strSoln;", + " };", + "", + " // TEST -------------------------------------------------------------------", + " return unlines(map(solutionString, problems));", + "})();", + "{{Out}}", + "(Executed in Atom editor, using 'Script' package).", + "
    PROBLEM 1.",
    +        "",
    +        "     0  0  0",
    +        "     0     0  0",
    +        "     0  0  0  0  0  0  0",
    +        "  0  0  0        0     0",
    +        "  0     0        0  0  0",
    +        "  1  0  0  0  0  0  0",
    +        "        0  0     0",
    +        "           0  0  0",
    +        "",
    +        "First solution found in c. 21 milliseconds:",
    +        "",
    +        "    25 14 23",
    +        "     8    26 15",
    +        "    13 24  7 22 27 16 31",
    +        "  9 36 11       30    28",
    +        " 12     6       21 32 17",
    +        "  1 10 35 20  3 18 29",
    +        "        2  5    33",
    +        "          34 19  4",
    +        "",
    +        "",
    +        "PROBLEM 2.",
    +        "",
    +        "                 1     0",
    +        "                 0     0",
    +        "              0  0  0  0  0",
    +        "                 0  0  0",
    +        "        0        0     0        0",
    +        "  0  0  0  0  0           0  0  0  0  0",
    +        "        0  0                 0  0",
    +        "  0  0  0  0  0           0  0  0  0  0",
    +        "        0        0     0        0",
    +        "                 0  0  0",
    +        "              0  0  0  0  0",
    +        "                 0     0",
    +        "                 0     0",
    +        "",
    +        "First solution found in c. 7084 milliseconds:",
    +        "",
    +        "                 1     3",
    +        "                50    52",
    +        "             56 53  2 49  4",
    +        "                48 51 54",
    +        "       46       55     5       10",
    +        " 45 42 35 40 47          11  6 13  8 15",
    +        "       44 37                 9 16",
    +        " 43 36 41 34 39          19 12  7 14 17",
    +        "       38       33    27       18",
    +        "                26 23 20",
    +        "             32 21 30 25 28",
    +        "                24    22",
    +        "                31    29",
    +        "",
    +        "",
    +        "[Finished in 7.2s]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ff9", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n 'use strict';\n\n // problems :: [[String]]\n const problems = [\n [\n \" 000 \" //\n , \" 0 00 \" //\n , \" 0000000\" //\n , \"000 0 0\" //\n , \"0 0 000\" //\n , \"1000000 \" //\n , \" 00 0 \" //\n , \" 000 \" //\n ],\n [\n \"-----1-0-----\" //\n , \"-----0-0-----\" //\n , \"----00000----\" //\n , \"-----000-----\" //\n , \"--0--0-0--0--\" //\n , \"00000---00000\" //\n , \"--00-----00--\" //\n , \"00000---00000\" //\n , \"--0--0-0--0--\" //\n , \"-----000-----\" //\n , \"----00000----\" //\n , \"-----0-0-----\" //\n , \"-----0-0-----\" //\n ]\n ];\n\n // GENERIC FUNCTIONS ------------------------------------------------------\n\n // comparing :: (a -> b) -> (a -> a -> Ordering)\n const comparing = f =>\n (x, y) => {\n const\n a = f(x),\n b = f(y);\n return a < b ? -1 : a > b ? 1 : 0\n };\n\n // concat :: [[a]] -> [a] | [String] -> String\n const concat = xs =>\n xs.length > 0 ? (() => {\n const unit = typeof xs[0] === 'string' ? '' : [];\n return unit.concat.apply(unit, xs);\n })() : [];\n\n // charColRow :: Char -> [String] -> Maybe (Int, Int)\n const charColRow = (c, rows) =>\n foldr((a, xs, iRow) =>\n a.nothing ? (() => {\n const mbiCol = elemIndex(c, xs);\n return mbiCol.nothing ? mbiCol : {\n just: [mbiCol.just, iRow],\n nothing: false\n };\n })() : a, {\n nothing: true\n }, rows);\n\n // 2 or more arguments\n // curry :: Function -> Function\n const curry = (f, ...args) => {\n const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :\n function () {\n return go(xs.concat(Array.from(arguments)));\n };\n return go([].slice.call(args, 1));\n };\n\n // elem :: Eq a => a -> [a] -> Bool\n const elem = (x, xs) => xs.indexOf(x) !== -1;\n\n // elemIndex :: Eq a => a -> [a] -> Maybe Int\n const elemIndex = (x, xs) => {\n const i = xs.indexOf(x);\n return {\n nothing: i === -1,\n just: i\n };\n };\n\n // enumFromTo :: Int -> Int -> [Int]\n const enumFromTo = (m, n) =>\n Array.from({\n length: Math.floor(n - m) + 1\n }, (_, i) => m + i);\n\n // filter :: (a -> Bool) -> [a] -> [a]\n const filter = (f, xs) => xs.filter(f);\n\n // findIndex :: (a -> Bool) -> [a] -> Maybe Int\n const findIndex = (f, xs) => {\n for (var i = 0, lng = xs.length; i < lng; i++) {\n if (f(xs[i])) return {\n nothing: false,\n just: i\n };\n }\n return {\n nothing: true\n };\n };\n\n // foldl :: (b -> a -> b) -> b -> [a] -> b\n const foldl = (f, a, xs) => xs.reduce(f, a);\n\n // foldr (a -> b -> b) -> b -> [a] -> b\n const foldr = (f, a, xs) => xs.reduceRight(f, a);\n\n // groupBy :: (a -> a -> Bool) -> [a] -> [[a]]\n const groupBy = (f, xs) => {\n const dct = xs.slice(1)\n .reduce((a, x) => {\n const\n h = a.active.length > 0 ? a.active[0] : undefined,\n blnGroup = h !== undefined && f(h, x);\n return {\n active: blnGroup ? a.active.concat([x]) : [x],\n sofar: blnGroup ? a.sofar : a.sofar.concat([a.active])\n };\n }, {\n active: xs.length > 0 ? [xs[0]] : [],\n sofar: []\n });\n return dct.sofar.concat(dct.active.length > 0 ? [dct.active] : []);\n };\n\n // intercalate :: String -> [a] -> String\n const intercalate = (s, xs) => xs.join(s);\n\n // intersectBy::(a - > a - > Bool) - > [a] - > [a] - > [a]\n const intersectBy = (eq, xs, ys) =>\n (xs.length > 0 && ys.length > 0) ?\n xs.filter(x => ys.some(curry(eq)(x))) : [];\n\n // justifyRight :: Int -> Char -> Text -> Text\n const justifyRight = (n, cFiller, strText) =>\n n > strText.length ? (\n (cFiller.repeat(n) + strText)\n .slice(-n)\n ) : strText;\n\n // length :: [a] -> Int\n const length = xs => xs.length;\n\n // map :: (a -> b) -> [a] -> [b]\n const map = (f, xs) => xs.map(f);\n\n // mappendComparing :: [(a -> b)] -> (a -> a -> Ordering)\n const mappendComparing = fs => (x, y) =>\n fs.reduce((ord, f) => {\n if (ord !== 0) return ord;\n const\n a = f(x),\n b = f(y);\n return a < b ? -1 : a > b ? 1 : 0\n }, 0);\n\n // maximumBy :: (a -> a -> Ordering) -> [a] -> a\n const maximumBy = (f, xs) =>\n xs.reduce((a, x) => a === undefined ? x : (\n f(x, a) > 0 ? x : a\n ), undefined);\n\n // min :: Ord a => a -> a -> a\n const min = (a, b) => b < a ? b : a;\n\n // replicate :: Int -> a -> [a]\n const replicate = (n, a) => {\n let v = [a],\n o = [];\n if (n < 1) return o;\n while (n > 1) {\n if (n & 1) o = o.concat(v);\n n >>= 1;\n v = v.concat(v);\n }\n return o.concat(v);\n };\n\n // sortBy :: (a -> a -> Ordering) -> [a] -> [a]\n const sortBy = (f, xs) => xs.slice()\n .sort(f);\n\n // splitOn :: String -> String -> [String]\n const splitOn = (s, xs) => xs.split(s);\n\n // take :: Int -> [a] -> [a]\n const take = (n, xs) => xs.slice(0, n);\n\n // unlines :: [String] -> String\n const unlines = xs => xs.join('\\n');\n\n // until :: (a -> Bool) -> (a -> a) -> a -> a\n const until = (p, f, x) => {\n let v = x;\n while (!p(v)) v = f(v);\n return v;\n };\n\n // zip :: [a] -> [b] -> [(a,b)]\n const zip = (xs, ys) =>\n xs.slice(0, Math.min(xs.length, ys.length))\n .map((x, i) => [x, ys[i]]);\n\n // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]\n const zipWith = (f, xs, ys) =>\n Array.from({\n length: min(xs.length, ys.length)\n }, (_, i) => f(xs[i], ys[i]));\n\n // HOLY KNIGHT's TOUR FUNCTIONS -------------------------------------------\n\n // kmoves :: (Int, Int) -> [(Int, Int)]\n const kmoves = ([x, y]) => map(\n ([a, b]) => [a + x, b + y], [\n [1, 2],\n [1, -2],\n [-1, 2],\n [-1, -2],\n [2, 1],\n [2, -1],\n [-2, 1],\n [-2, -1]\n ]);\n\n // rowPosns :: Int -> String -> [(Int, Int)]\n const rowPosns = (iRow, s) => {\n return foldl((a, x, i) => (elem(x, ['0', '1']) ? (\n a.concat([\n [i, iRow]\n ])\n ) : a), [], splitOn('', s));\n };\n\n // hash :: (Int, Int) -> String\n const hash = ([col, row]) => col.toString() + '.' + row.toString();\n\n // Start node, and degree-sorted cache of moves from each node\n // All node references are hash strings (for this cache)\n\n // problemModel :: [[String]] -> {cache: {nodeKey: [nodeKey], start:String}}\n const problemModel = boardLines => {\n const\n steps = foldl((a, xs, i) =>\n a.concat(rowPosns(i, xs)), [], boardLines),\n courseMoves = (xs, [x, y]) => intersectBy(\n ([a, b], [c, d]) => a === c && b === d, kmoves([x, y]), xs\n ),\n maybeStart = charColRow('1', boardLines);\n return {\n start: maybeStart.nothing ? '' : hash(maybeStart.just),\n boardWidth: boardLines.length > 0 ? boardLines[0].length : 0,\n stepCount: steps.length,\n cache: (() => {\n const moveCache = foldl((a, xy) => (\n a[hash(xy)] = map(hash, courseMoves(steps, xy)),\n a\n ), {}, steps),\n lstMoves = Object.keys(moveCache),\n dctDegree = foldl((a, k) =>\n (a[k] = moveCache[k].length,\n a), {}, lstMoves);\n\n return foldl((a, k) => (\n a[k] = sortBy(comparing(x => dctDegree[x]), moveCache[k]),\n a\n ), {}, lstMoves);\n })()\n };\n };\n\n // firstSolution :: {nodeKey: [nodeKey]} -> Int ->\n // nodeKey -> nodeKey -> [nodeKey] ->\n // -> {path::[nodeKey], pathLen::Int, found::Bool}\n const firstSolution = (dctMoves, intTarget, strStart, strNodeKey, path) => {\n const\n intPath = path.length,\n moves = dctMoves[strNodeKey];\n\n if ((intTarget - intPath) < 2 && elem(strStart, moves)) {\n return {\n nothing: false,\n just: [strStart, strNodeKey].concat(path),\n pathLen: intTarget\n };\n }\n\n const\n nexts = filter(k => !elem(k, path), moves),\n intNexts = nexts.length,\n lstFullPath = [strNodeKey].concat(path);\n\n // Until we find a full path back to start\n return until(\n x => (x.nothing === false || x.i >= intNexts),\n x => {\n const\n idx = x.i,\n dctSoln = firstSolution(\n dctMoves, intTarget, strStart, nexts[idx], lstFullPath\n );\n return {\n i: idx + 1,\n nothing: dctSoln.nothing,\n just: dctSoln.just,\n pathLen: dctSoln.pathLen\n };\n }, {\n nothing: true,\n just: [],\n i: 0\n }\n );\n };\n\n // maybeTour :: [String] -> {\n // nothing::Bool, Just::[nodeHash], i::Int: pathLen::Int }\n const maybeTour = trackLines => {\n const\n dctModel = problemModel(trackLines),\n strStart = dctModel.start;\n return strStart !== '' ? firstSolution(\n dctModel.cache, dctModel.stepCount, strStart, strStart, []\n ) : {\n nothing: true\n };\n };\n\n // showLine :: Int -> Int -> String -> Maybe (Int, Int) ->\n // [(Int, Int, String)] -> String\n const showLine = curry((intCell, strFiller, maybeStart, xs) => {\n const\n blnSoln = maybeStart.nothing,\n [startCol, startRow] = blnSoln ? [0, 0] : maybeStart.just;\n return foldl((a, [iCol, iRow, sVal], i, xs) => ({\n col: iCol + 1,\n txt: a.txt +\n concat(replicate((iCol - a.col) * intCell, strFiller)) +\n justifyRight(\n intCell, strFiller,\n (blnSoln ? sVal : (\n iRow === startRow &&\n iCol === startCol ? '1' : '0')\n )\n )\n }), {\n col: 0,\n txt: ''\n },\n xs\n )\n .txt\n });\n\n // solutionString :: [String] -> Int -> String\n const solutionString = (boardLines, iProblem) => {\n const\n dtePre = Date.now(),\n intCols = boardLines.length > 0 ? boardLines[0].length : 0,\n soln = maybeTour(boardLines),\n intMSeconds = Date.now() - dtePre;\n\n if (soln.nothing) return 'No solution found …';\n\n const\n kCol = 0,\n kRow = 1,\n kSeq = 2,\n steps = soln.just,\n lstTriples = zipWith((h, n) => {\n const [col, row] = map(\n x => parseInt(x, 10), splitOn('.', h)\n );\n return [col, row, n.toString()];\n },\n steps,\n enumFromTo(1, soln.pathLen)),\n cellWidth = length(maximumBy(\n comparing(x => length(x[kSeq])), lstTriples\n )[kSeq]) + 1,\n lstGroups = groupBy(\n (a, b) => a[kRow] === b[kRow],\n sortBy(\n mappendComparing([x => x[kRow], x => x[kCol]]),\n lstTriples\n )),\n startXY = take(2, lstTriples[0]),\n strMap = 'PROBLEM ' + (parseInt(iProblem, 10) + 1) + '.\\n\\n' +\n unlines(map(showLine(cellWidth, ' ', {\n nothing: false,\n just: startXY\n }), lstGroups)),\n strSoln = 'First solution found in c. ' +\n intMSeconds + ' milliseconds:\\n\\n' +\n unlines(map(showLine(cellWidth, ' ', {\n nothing: true,\n just: startXY\n }), lstGroups)) + '\\n\\n';\n\n console.log(strSoln);\n return strMap + '\\n\\n' + strSoln;\n };\n\n // TEST -------------------------------------------------------------------\n return unlines(map(solutionString, problems));\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Solve a Hopido puzzle", + "type": "Waypoint", + "description": [ + "

    Hopido puzzles are similar to Hidato. The most important difference is that the only moves allowed are: hop over one tile diagonally; and over two tiles horizontally and vertically. It should be possible to start anywhere in the path, the end point isn't indicated and there are no intermediate clues. Hopido Design Post Mortem contains the following:

    \"Big puzzles represented another problem. Up until quite late in the project our puzzle solver was painfully slow with most puzzles above 7×7 tiles. Testing the solution from each starting point could take hours. If the tile layout was changed even a little, the whole puzzle had to be tested again. We were just about to give up the biggest puzzles entirely when our programmer suddenly came up with a magical algorithm that cut the testing process down to only minutes. Hooray!\"

    Knowing the kindness in the heart of every contributor to Rosetta Code, I know that we shall feel that as an act of humanity we must solve these puzzles for them in let's say milliseconds.

    Example:

    . 0 0 . 0 0 .

    ", + "

    0 0 0 0 0 0 0

    ", + "

    0 0 0 0 0 0 0

    ", + "

    . 0 0 0 0 0 .

    ", + "

    . . 0 0 0 . .

    ", + "

    . . . 0 . . .

    Extra credits are available for other interesting designs.

    ", + "Related tasks:", + "A* search algorithm", + "Solve a Holy Knight's tour", + "Knight's tour", + "N-queens problem", + "Solve a Hidato puzzle", + "Solve a Holy Knight's tour", + "Solve a Numbrix puzzle", + "Solve the no connection puzzle" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ffa", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Solve a Numbrix puzzle", + "type": "Waypoint", + "description": [ + "

    Numbrix puzzles are similar to Hidato.

    ", + "

    The most important difference is that it is only possible to move 1 node left, right, up, or down (sometimes referred to as the Von Neumann neighborhood).

    ", + "

    Published puzzles also tend not to have holes in the grid and may not always indicate the end node.

    ", + "

    Two examples follow:

    Example 1", + "

    Problem.

    ", + "
    ",
    +        " 0  0  0  0  0  0  0  0  0",
    +        " 0  0 46 45  0 55 74  0  0",
    +        " 0 38  0  0 43  0  0 78  0",
    +        " 0 35  0  0  0  0  0 71  0",
    +        " 0  0 33  0  0  0 59  0  0",
    +        " 0 17  0  0  0  0  0 67  0",
    +        " 0 18  0  0 11  0  0 64  0",
    +        " 0  0 24 21  0  1  2  0  0",
    +        " 0  0  0  0  0  0  0  0  0",
    +        "
    ", + "

    Solution.

    ", + "
    ",
    +        " 49 50 51 52 53 54 75 76 81",
    +        " 48 47 46 45 44 55 74 77 80",
    +        " 37 38 39 40 43 56 73 78 79",
    +        " 36 35 34 41 42 57 72 71 70",
    +        " 31 32 33 14 13 58 59 68 69",
    +        " 30 17 16 15 12 61 60 67 66",
    +        " 29 18 19 20 11 62 63 64 65",
    +        " 28 25 24 21 10  1  2  3  4",
    +        " 27 26 23 22  9  8  7  6  5",
    +        "
    ", + "Example 2", + "

    Problem.

    ", + "
    ",
    +        " 0  0  0  0  0  0  0  0  0",
    +        " 0 11 12 15 18 21 62 61  0",
    +        " 0  6  0  0  0  0  0 60  0",
    +        " 0 33  0  0  0  0  0 57  0",
    +        " 0 32  0  0  0  0  0 56  0",
    +        " 0 37  0  1  0  0  0 73  0",
    +        " 0 38  0  0  0  0  0 72  0",
    +        " 0 43 44 47 48 51 76 77  0",
    +        " 0  0  0  0  0  0  0  0  0",
    +        "
    ", + "

    Solution.

    ", + "
    ",
    +        "  9 10 13 14 19 20 63 64 65",
    +        "  8 11 12 15 18 21 62 61 66",
    +        "  7  6  5 16 17 22 59 60 67",
    +        " 34 33  4  3 24 23 58 57 68",
    +        " 35 32 31  2 25 54 55 56 69",
    +        " 36 37 30  1 26 53 74 73 70",
    +        " 39 38 29 28 27 52 75 72 71",
    +        " 40 43 44 47 48 51 76 77 78",
    +        " 41 42 45 46 49 50 81 80 79",
    +        "
    ", + "Task", + "

    Write a program to solve puzzles of this ilk,

    ", + "

    demonstrating your program by solving the above examples.

    ", + "

    Extra credit for other interesting examples.

    ", + "Related tasks:", + "A* search algorithm", + "Solve a Holy Knight's tour", + "Knight's tour", + "N-queens problem", + "Solve a Hidato puzzle", + "Solve a Holy Knight's tour", + "Solve a Hopido puzzle", + "Solve the no connection puzzle" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ffb", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Solve the no connection puzzle", + "type": "Waypoint", + "description": [ + "

    You are given a box with eight holes labelled A-to-H, connected by fifteen

    ", + "

    straight lines in the pattern as shown

    A B

    ", + "

    /|\\ /|\\

    ", + "

    / | X | \\

    ", + "

    / |/ \\| \\

    ", + "

    C - D - E - F

    ", + "

    \\ |\\ /| /

    ", + "

    \\ | X | /

    ", + "

    \\|/ \\|/

    ", + "

    G H

    You are also given eight pegs numbered 1-to-8. The idea is to place the pegs in

    ", + "

    the holes so that the (absolute) difference between any two numbers connected by

    ", + "

    any line is greater than one.

    For example, in this attempt:

    4 7

    ", + "

    /|\\ /|\\

    ", + "

    / | X | \\

    ", + "

    / |/ \\| \\

    ", + "

    8 - 1 - 6 - 2

    ", + "

    \\ |\\ /| /

    ", + "

    \\ | X | /

    ", + "

    \\|/ \\|/

    ", + "

    3 5

    Note that 7 and 6 are connected and have a difference of 1 so it is not a solution.

    ", + "Task", + "

    Produce and show here one solution to the puzzle.

    ", + "Related tasks:", + "A* search algorithm", + "Solve a Holy Knight's tour", + "Knight's tour", + "N-queens problem", + "Solve a Hidato puzzle", + "Solve a Holy Knight's tour", + "Solve a Hopido puzzle", + "Solve a Numbrix puzzle", + "4-rings or 4-squares puzzle", + "See also", + "

    No Connection Puzzle (youtube).

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES6===", + "{{Trans|Haskell}}", + "(() => {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // abs :: Num a => a -> a", + " const abs = Math.abs;", + "", + " // all :: (a -> Bool) -> [a] -> Bool", + " const all = (f, xs) => xs.every(f);", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " const concatMap = (f, xs) => [].concat.apply([], xs.map(f));", + "", + " // delete_ :: Eq a => a -> [a] -> [a]", + " const delete_ = (x, xs) =>", + " deleteBy((a, b) => a === b, x, xs);", + "", + " // deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]", + " const deleteBy = (f, x, xs) =>", + " xs.length > 0 ? (", + " f(x, xs[0]) ? (", + " xs.slice(1)", + " ) : [xs[0]].concat(deleteBy(f, x, xs.slice(1)))", + " ) : [];", + "", + " // enumFromTo :: Enum a => a -> a -> [a]", + " const enumFromTo = (m, n) => {", + " const [tm, tn] = [typeof m, typeof n];", + " return tm !== tn ? undefined : (() => {", + " const", + " blnS = (tm === 'string'),", + " [base, end] = [m, n].map(blnS ? (s => s.codePointAt(0)) : id);", + " return Array.from({", + " length: Math.floor(end - base) + 1", + " }, (_, i) => blnS ? String.fromCodePoint(base + i) : m + i);", + " })();", + " };", + "", + " // id :: a -> a", + " const id = x => x;", + "", + " // justifyRight :: Int -> Char -> Text -> Text", + " const justifyRight = (n, cFiller, strText) =>", + " n > strText.length ? (", + " (cFiller.repeat(n) + strText)", + " .slice(-n)", + " ) : strText;", + "", + " // permutations :: [a] -> [[a]]", + " const permutations = xs =>", + " xs.length ? concatMap(x => concatMap(ys => [", + " [x].concat(ys)", + " ],", + " permutations(delete_(x, xs))), xs) : [", + " []", + " ];", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x);", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + " // until :: (a -> Bool) -> (a -> a) -> a -> a", + " const until = (p, f, x) => {", + " let v = x;", + " while (!p(v)) v = f(v);", + " return v;", + " };", + "", + " // unwords :: [String] -> String", + " const unwords = xs => xs.join(' ');", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " const zipWith = (f, xs, ys) => {", + " const ny = ys.length;", + " return (xs.length <= ny ? xs : xs.slice(0, ny))", + " .map((x, i) => f(x, ys[i]));", + " };", + "", + "", + " // CONNECTION PUZZLE ------------------------------------------------------", + "", + " // universe :: [[Int]]", + " const universe = permutations(enumFromTo(1, 8));", + "", + " // isSolution :: [Int] -> Bool", + " const isSolution = ([a, b, c, d, e, f, g, h]) =>", + " all(x => abs(x) > 1, [a - d, c - d, g - d, e - d, a - c, c - g, g - e,", + " e - a, b - e, d - e, h - e, f - e, b - d, d - h, h - f, f - b", + " ]);", + "", + " // firstSolution :: [Int]", + " const firstSolution = universe[until(", + " i => isSolution(universe[i]),", + " i => i + 1,", + " 0", + " )];", + "", + " // TEST -------------------------------------------------------------------", + "", + " // [Int]", + " const [a, b, c, d, e, f, g, h] = firstSolution;", + "", + " return unlines(", + " zipWith(", + " (a, n) => a + ' = ' + n.toString(),", + " enumFromTo('A', 'H'),", + " firstSolution", + " )", + " .concat(", + " [", + " [],", + " [a, b],", + " [c, d, e, f],", + " [g, h]", + " ].map(xs => justifyRight(5, ' ', unwords(xs.map(show))))", + " )", + " );", + "})();", + "{{Out}}", + "
    A = 3",
    +        "B = 4",
    +        "C = 7",
    +        "D = 1",
    +        "E = 8",
    +        "F = 2",
    +        "G = 5",
    +        "H = 6",
    +        "     ",
    +        "  3 4",
    +        "7 1 8 2",
    +        "  5 6
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ffc", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n 'use strict';\n\n // GENERIC FUNCTIONS ------------------------------------------------------\n\n // abs :: Num a => a -> a\n const abs = Math.abs;\n\n // all :: (a -> Bool) -> [a] -> Bool\n const all = (f, xs) => xs.every(f);\n\n // concatMap :: (a -> [b]) -> [a] -> [b]\n const concatMap = (f, xs) => [].concat.apply([], xs.map(f));\n\n // delete_ :: Eq a => a -> [a] -> [a]\n const delete_ = (x, xs) =>\n deleteBy((a, b) => a === b, x, xs);\n\n // deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]\n const deleteBy = (f, x, xs) =>\n xs.length > 0 ? (\n f(x, xs[0]) ? (\n xs.slice(1)\n ) : [xs[0]].concat(deleteBy(f, x, xs.slice(1)))\n ) : [];\n\n // enumFromTo :: Enum a => a -> a -> [a]\n const enumFromTo = (m, n) => {\n const [tm, tn] = [typeof m, typeof n];\n return tm !== tn ? undefined : (() => {\n const\n blnS = (tm === 'string'),\n [base, end] = [m, n].map(blnS ? (s => s.codePointAt(0)) : id);\n return Array.from({\n length: Math.floor(end - base) + 1\n }, (_, i) => blnS ? String.fromCodePoint(base + i) : m + i);\n })();\n };\n\n // id :: a -> a\n const id = x => x;\n\n // justifyRight :: Int -> Char -> Text -> Text\n const justifyRight = (n, cFiller, strText) =>\n n > strText.length ? (\n (cFiller.repeat(n) + strText)\n .slice(-n)\n ) : strText;\n\n // permutations :: [a] -> [[a]]\n const permutations = xs =>\n xs.length ? concatMap(x => concatMap(ys => [\n [x].concat(ys)\n ],\n permutations(delete_(x, xs))), xs) : [\n []\n ];\n\n // show :: a -> String\n const show = x => JSON.stringify(x);\n\n // unlines :: [String] -> String\n const unlines = xs => xs.join('\\n');\n\n // until :: (a -> Bool) -> (a -> a) -> a -> a\n const until = (p, f, x) => {\n let v = x;\n while (!p(v)) v = f(v);\n return v;\n };\n\n // unwords :: [String] -> String\n const unwords = xs => xs.join(' ');\n\n // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]\n const zipWith = (f, xs, ys) => {\n const ny = ys.length;\n return (xs.length <= ny ? xs : xs.slice(0, ny))\n .map((x, i) => f(x, ys[i]));\n };\n\n\n // CONNECTION PUZZLE ------------------------------------------------------\n\n // universe :: [[Int]]\n const universe = permutations(enumFromTo(1, 8));\n\n // isSolution :: [Int] -> Bool\n const isSolution = ([a, b, c, d, e, f, g, h]) =>\n all(x => abs(x) > 1, [a - d, c - d, g - d, e - d, a - c, c - g, g - e,\n e - a, b - e, d - e, h - e, f - e, b - d, d - h, h - f, f - b\n ]);\n\n // firstSolution :: [Int]\n const firstSolution = universe[until(\n i => isSolution(universe[i]),\n i => i + 1,\n 0\n )];\n\n // TEST -------------------------------------------------------------------\n\n // [Int]\n const [a, b, c, d, e, f, g, h] = firstSolution;\n\n return unlines(\n zipWith(\n (a, n) => a + ' = ' + n.toString(),\n enumFromTo('A', 'H'),\n firstSolution\n )\n .concat(\n [\n [],\n [a, b],\n [c, d, e, f],\n [g, h]\n ].map(xs => justifyRight(5, ' ', unwords(xs.map(show))))\n )\n );\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sort a list of object identifiers", + "type": "Waypoint", + "description": [ + "

    Object identifiers (OID) are strings used to identify objects in network data.

    ", + "Task:", + "

    Show how to sort a list of OIDs, in their natural sort order.

    ", + "An OID consists of one or more non-negative integers in base 10, separated by dots. It starts and ends with a number.", + "Their natural sort order is lexicographical with regard to the dot-separated fields, using numeric comparison between fields.", + "

    {|

    ", + "

    |-

    ", + "

    ! Input (list of strings)

    ", + "

    ! Output (list of strings)

    ", + "

    |-

    ", + "

    |

    ", + "

    1.3.6.1.4.1.11.2.17.19.3.4.0.10

    ", + "

    1.3.6.1.4.1.11.2.17.5.2.0.79

    ", + "

    1.3.6.1.4.1.11.2.17.19.3.4.0.4

    ", + "

    1.3.6.1.4.1.11150.3.4.0.1

    ", + "

    1.3.6.1.4.1.11.2.17.19.3.4.0.1

    ", + "

    1.3.6.1.4.1.11150.3.4.0

    ", + "

    |

    ", + "

    1.3.6.1.4.1.11.2.17.5.2.0.79

    ", + "

    1.3.6.1.4.1.11.2.17.19.3.4.0.1

    ", + "

    1.3.6.1.4.1.11.2.17.19.3.4.0.4

    ", + "

    1.3.6.1.4.1.11.2.17.19.3.4.0.10

    ", + "

    1.3.6.1.4.1.11150.3.4.0

    ", + "

    1.3.6.1.4.1.11150.3.4.0.1

    ", + "

    |}

    ", + "Natural sorting", + "Sort using a custom comparator", + "


    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ffd", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sort an array of composite structures", + "type": "Waypoint", + "description": [ + "

    Sort an array of composite structures by a key.

    ", + "

    For example, if you define a composite structure that presents a name-value pair (in pseudo-code):

    Define structure pair such that:

    ", + "

    name as a string

    ", + "

    value as a string

    and an array of such pairs:

    x: array of pairs

    then define a sort routine that sorts the array x by the key name.

    This task can always be accomplished with Sorting Using a Custom Comparator. If your language is not listed here, please see the other article.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "var arr = [", + " {id: 3, value: \"foo\"},", + " {id: 2, value: \"bar\"},", + " {id: 4, value: \"baz\"},", + " {id: 1, value: 42},", + " {id: 5, something: \"another string\"} // Works with any object declaring 'id' as a number.", + "];", + "arr = arr.sort(function(a, b) {return a.id - b.id}); // Sort with comparator checking the id.", + "", + "", + "===ES6===", + "", + "(() => {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS FOR COMPARISONS", + "", + " // compare :: a -> a -> Ordering", + " const compare = (a, b) => a < b ? -1 : (a > b ? 1 : 0);", + "", + " // on :: (b -> b -> c) -> (a -> b) -> a -> a -> c", + " const on = (f, g) => (a, b) => f(g(a), g(b));", + "", + " // flip :: (a -> b -> c) -> b -> a -> c", + " const flip = f => (a, b) => f.apply(null, [b, a]);", + "", + " // arrayCopy :: [a] -> [a]", + " const arrayCopy = (xs) => xs.slice(0);", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x, null, 2);", + "", + "", + " // TEST", + " const xs = [{", + " name: 'Shanghai',", + " pop: 24.2", + " }, {", + " name: 'Karachi',", + " pop: 23.5", + " }, {", + " name: 'Beijing',", + " pop: 21.5", + " }, {", + " name: 'Sao Paulo',", + " pop: 24.2", + " }, {", + " name: 'Dhaka',", + " pop: 17.0", + " }, {", + " name: 'Delhi',", + " pop: 16.8", + " }, {", + " name: 'Lagos',", + " pop: 16.1", + " }]", + "", + " // population :: Dictionary -> Num", + " const population = x => x.pop;", + "", + " // name :: Dictionary -> String", + " const name = x => x.name;", + "", + " return show({", + " byPopulation: arrayCopy(xs)", + " .sort(on(compare, population)),", + " byDescendingPopulation: arrayCopy(xs)", + " .sort(on(flip(compare), population)),", + " byName: arrayCopy(xs)", + " .sort(on(compare, name)),", + " byDescendingName: arrayCopy(xs)", + " .sort(on(flip(compare), name))", + " });", + "})();", + "", + "{{Out}}", + "
    {",
    +        "  \"byPopulation\": [",
    +        "    {",
    +        "      \"name\": \"Lagos\",",
    +        "      \"pop\": 16.1",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Delhi\",",
    +        "      \"pop\": 16.8",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Dhaka\",",
    +        "      \"pop\": 17",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Beijing\",",
    +        "      \"pop\": 21.5",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Karachi\",",
    +        "      \"pop\": 23.5",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Shanghai\",",
    +        "      \"pop\": 24.2",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Sao Paulo\",",
    +        "      \"pop\": 24.2",
    +        "    }",
    +        "  ],",
    +        "  \"byDescendingPopulation\": [",
    +        "    {",
    +        "      \"name\": \"Shanghai\",",
    +        "      \"pop\": 24.2",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Sao Paulo\",",
    +        "      \"pop\": 24.2",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Karachi\",",
    +        "      \"pop\": 23.5",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Beijing\",",
    +        "      \"pop\": 21.5",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Dhaka\",",
    +        "      \"pop\": 17",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Delhi\",",
    +        "      \"pop\": 16.8",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Lagos\",",
    +        "      \"pop\": 16.1",
    +        "    }",
    +        "  ],",
    +        "  \"byName\": [",
    +        "    {",
    +        "      \"name\": \"Beijing\",",
    +        "      \"pop\": 21.5",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Delhi\",",
    +        "      \"pop\": 16.8",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Dhaka\",",
    +        "      \"pop\": 17",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Karachi\",",
    +        "      \"pop\": 23.5",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Lagos\",",
    +        "      \"pop\": 16.1",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Sao Paulo\",",
    +        "      \"pop\": 24.2",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Shanghai\",",
    +        "      \"pop\": 24.2",
    +        "    }",
    +        "  ],",
    +        "  \"byDescendingName\": [",
    +        "    {",
    +        "      \"name\": \"Shanghai\",",
    +        "      \"pop\": 24.2",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Sao Paulo\",",
    +        "      \"pop\": 24.2",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Lagos\",",
    +        "      \"pop\": 16.1",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Karachi\",",
    +        "      \"pop\": 23.5",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Dhaka\",",
    +        "      \"pop\": 17",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Delhi\",",
    +        "      \"pop\": 16.8",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Beijing\",",
    +        "      \"pop\": 21.5",
    +        "    }",
    +        "  ]",
    +        "}
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7ffe", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var arr = [\n {id: 3, value: \"foo\"},\n {id: 2, value: \"bar\"},\n {id: 4, value: \"baz\"},\n {id: 1, value: 42},\n {id: 5, something: \"another string\"} // Works with any object declaring 'id' as a number.\n];\narr = arr.sort(function(a, b) {return a.id - b.id}); // Sort with comparator checking the id.\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sort an integer array", + "type": "Waypoint", + "description": [ + "

    Sort an array (or list) of integers in ascending numerical order.

    Task:", + "

    Use a sorting facility provided by the language/library if possible.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|Firefox|2.0}}", + "", + "JavaScript sorts lexically by default, so \"10000\" comes before \"2\". To sort numerically, a custom comparator is used.", + "", + "function int_arr(a, b) {", + " return a - b;", + "}", + "var numbers = [20, 7, 65, 10, 3, 0, 8, -60];", + "numbers.sort(int_arr);", + "document.write(numbers);", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc7fff", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function int_arr(a, b) {\n return a - b;\n}\nvar numbers = [20, 7, 65, 10, 3, 0, 8, -60];\nnumbers.sort(int_arr);\ndocument.write(numbers);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sort disjoint sublist", + "type": "Waypoint", + "description": [ + "

    Given a list of values and a set of integer indices into that value list, the task is to sort the values at the given indices, but preserving the values at indices outside the set of those to be sorted.

    Make your example work with the following list of values and set of indices:

    ", + "

    ", + "

    values: [7, 6, 5, 4, 3, 2, 1, 0]

    ", + "

    indices: {6, 1, 7}

    ", + "

    Where the correct result would be:

    ", + "

    [7, 0, 5, 4, 3, 2, 1, 6].

    Note that for one based, rather than the zero-based indexing above, use the indices: {7, 2, 8}. The indices are described as a set rather than a list but any collection-type of those indices without duplication may be used as long as the example is insensitive to the order of indices given.

    Cf.", + "Order disjoint list items" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "====Iterative====", + "", + "Does not check for duplicate indices.", + "function sort_disjoint(values, indices) {", + " var sublist = [];", + " indices.sort(function(a, b) { return a > b; });", + "", + " for (var i = 0; i < indices.length; i += 1) {", + " sublist.push(values[indices[i]]);", + " }", + "", + " sublist.sort(function(a, b) { return a < b; });", + "", + " for (var i = 0; i < indices.length; i += 1) {", + " values[indices[i]] = sublist.pop();", + " }", + "", + " return values;", + "}", + "", + "====Functional====", + "", + "(function () {", + " 'use strict';", + "", + " // disjointSort :: [a] -> [Int] -> [a]", + " function disjointSort(xs, indices) {", + "", + " // Sequence of indices discarded", + " var indicesSorted = indices.sort(),", + " subsetSorted = indicesSorted", + " .map(function (i) {", + " return xs[i];", + " })", + " .sort();", + "", + " return xs", + " .map(function (x, i) {", + " var iIndex = indicesSorted.indexOf(i);", + "", + " return iIndex !== -1 ? (", + " subsetSorted[iIndex]", + " ) : x;", + " });", + " }", + "", + " return disjointSort([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7])", + "", + "})();", + "", + "{{Out}}", + "
    [7, 0, 5, 4, 3, 2, 1, 6]
    ", + "", + "===ES6===", + "", + "(() => {", + " 'use strict';", + "", + " // disjointSort :: [a] -> [Int] -> [a]", + " const disjointSort = (xs, indices) => {", + "", + " // Sequence of indices discarded", + " const indicesSorted = indices.sort(),", + " subsetSorted = indicesSorted", + " .map(i => xs[i])", + " .sort();", + " ", + " return xs", + " .map((x, i) => {", + " const iIndex = indicesSorted.indexOf(i);", + " return iIndex !== -1 ? (", + " subsetSorted[iIndex]", + " ) : x;", + " });", + " };", + "", + " return disjointSort([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7]);", + "})();", + "{{Out}}", + "
    [7, 0, 5, 4, 3, 2, 1, 6]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8000", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function sort_disjoint(values, indices) {\n var sublist = [];\n indices.sort(function(a, b) { return a > b; });\n\n for (var i = 0; i < indices.length; i += 1) {\n sublist.push(values[indices[i]]);\n }\n\n sublist.sort(function(a, b) { return a < b; });\n\n for (var i = 0; i < indices.length; i += 1) {\n values[indices[i]] = sublist.pop();\n }\n\n return values;\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Bead sort", + "type": "Waypoint", + "description": [ + "Task:", + "

    Sort an array of positive integers using the Bead Sort Algorithm.

    A bead sort is also known as a gravity sort.

    ", + "

    Algorithm has O(S), where S is the sum of the integers in the input set: Each bead is moved individually.

    This is the case when bead sort is implemented without a mechanism to assist in finding empty spaces below the beads, such as in software implementations.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8001", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Bogosort", + "type": "Waypoint", + "description": [ + "Task:", + "

    Bogosort a list of numbers.

    ", + "

    Bogosort simply shuffles a collection randomly until it is sorted.

    \"Bogosort\" is a perversely inefficient algorithm only used as an in-joke.

    Its average run-time is O(n!) because the chance that any given shuffle of a set will end up in sorted order is about one in n factorial, and the worst case is infinite since there's no guarantee that a random shuffling will ever produce a sorted sequence.

    Its best case is O(n) since a single pass through the elements may suffice to order them.

    ", + "

    Pseudocode:

    ", + "

    while not InOrder(list) do

    ", + "

    Shuffle(list)

    ", + "

    done

    ", + "

    The Knuth shuffle may be used to implement the shuffle part of this algorithm.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "shuffle = function(v) {", + " for(var j, x, i = v.length; i; j = Math.floor(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x);", + " return v;", + "};", + "", + "isSorted = function(v){", + " for(var i=1; i v[i]) { return false; }", + " }", + " return true;", + "}", + "\t\t", + "bogosort = function(v){", + " var sorted = false;", + " while(sorted == false){", + " v = shuffle(v);", + " sorted = isSorted(v);", + " }", + " return v;", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8002", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "shuffle = function(v) {\n for(var j, x, i = v.length; i; j = Math.floor(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x);\n return v;\n};\n\nisSorted = function(v){\n for(var i=1; i v[i]) { return false; }\n }\n return true;\n}\n\t\t\nbogosort = function(v){\n var sorted = false;\n while(sorted == false){\n v = shuffle(v);\n sorted = isSorted(v);\n }\n return v;\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Bubble sort", + "type": "Waypoint", + "description": [ + "Task:", + "

    Sort an array of elements using the bubble sort algorithm. The elements must have a total order and the index of the array can be of any discrete type. For languages where this is not possible, sort an array of integers.

    The bubble sort is generally considered to be the simplest sorting algorithm.

    Because of its simplicity and ease of visualization, it is often taught in introductory computer science courses.

    Because of its abysmal O(n2) performance, it is not used often for large (or even medium-sized) datasets.

    The bubble sort works by passing sequentially over a list, comparing each value to the one immediately after it. If the first value is greater than the second, their positions are switched. Over a number of passes, at most equal to the number of elements in the list, all of the values drift into their correct positions (large values \"bubble\" rapidly toward the end, pushing others down around them).

    ", + "

    Because each pass finds the maximum item and puts it at the end, the portion of the list to be sorted can be reduced at each pass.

    ", + "

    A boolean variable is used to track whether any changes have been made in the current pass; when a pass completes without changing anything, the algorithm exits.

    This can be expressed in pseudo-code as follows (assuming 1-based indexing):

    ", + "

    repeat

    ", + "

    hasChanged := false

    ", + "

    decrement itemCount

    ", + "

    repeat with index from 1 to itemCount

    ", + "

    if (item at index) > (item at (index + 1))

    ", + "

    swap (item at index) with (item at (index + 1))

    ", + "

    hasChanged := true

    ", + "

    until hasChanged = false

    ", + "References:", + "The article on Wikipedia.", + "Dance interpretation." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Array.prototype.bubblesort = function() {", + " var done = false;", + " while (!done) {", + " done = true;", + " for (var i = 1; i this[i]) {", + " done = false;", + " [this[i-1], this[i]] = [this[i], this[i-1]]", + " }", + " }", + " }", + " return this;", + "}", + "", + "{{works with|SEE|3.0}}", + "{{works with|OSSP js|1.6.20070208}}", + "Array.prototype.bubblesort = function() {", + " var done = false;", + " while (! done) {", + " done = true;", + " for (var i = 1; i < this.length; i++) {", + " if (this[i - 1] > this[i]) {", + " done = false;", + " var tmp = this[i - 1];", + " this[i - 1] = this[i];", + " this[i] = tmp;", + " }", + " }", + " }", + " return this;", + "}", + "", + "Example:", + "var my_arr = [\"G\", \"F\", \"C\", \"A\", \"B\", \"E\", \"D\"];", + "my_arr.bubblesort();", + "print(my_arr);", + "", + "{{out}}", + "
    ",
    +        " A,B,C,D,E,F,G",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8003", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "Array.prototype.bubblesort = function() {\n var done = false;\n while (!done) {\n done = true;\n for (var i = 1; i this[i]) {\n done = false;\n [this[i-1], this[i]] = [this[i], this[i-1]]\n }\n }\n }\n return this;\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Cocktail sort", + "type": "Waypoint", + "description": [ + "

    The cocktail shaker sort is an improvement on the Bubble Sort.

    ", + "

    The improvement is basically that values \"bubble\" both directions through the array, because on each iteration the cocktail shaker sort bubble sorts once forwards and once backwards. Pseudocode for the algorithm (from wikipedia):

    ", + "

    function cocktailSort( A : list of sortable items )

    ", + "

    do

    ", + "

    swapped := false

    ", + "

    for each i in 0 to length( A ) - 2 do

    ", + "

    if A[ i ] > A[ i+1 ] then // test whether the two

    ", + "

    // elements are in the wrong

    ", + "

    // order

    ", + "

    swap( A[ i ], A[ i+1 ] ) // let the two elements

    ", + "

    // change places

    ", + "

    swapped := true;

    ", + "

    if swapped = false then

    ", + "

    // we can exit the outer loop here if no swaps occurred.

    ", + "

    break do-while loop;

    ", + "

    swapped := false

    ", + "

    for each i in length( A ) - 2 down to 0 do

    ", + "

    if A[ i ] > A[ i+1 ] then

    ", + "

    swap( A[ i ], A[ i+1 ] )

    ", + "

    swapped := true;

    ", + "

    while swapped; // if no elements have been swapped,

    ", + "

    // then the list is sorted

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + " // Node 5.4.1 tested implementation (ES6)", + "\"use strict\";", + "", + "let arr = [4, 9, 0, 3, 1, 5];", + "let isSorted = true;", + "while (isSorted){", + " for (let i = 0; i< arr.length - 1;i++){", + " if (arr[i] > arr[i + 1])", + " {", + " let temp = arr[i];", + " arr[i] = arr[i + 1];", + " arr[i+1] = temp;", + " isSorted = true;", + " }", + " }", + "", + " if (!isSorted)", + " break;", + " ", + " isSorted = false;", + "", + " for (let j = arr.length - 1; j > 0; j--){", + " if (arr[j-1] > arr[j])", + " {", + " let temp = arr[j];", + " arr[j] = arr[j - 1];", + " arr[j - 1] = temp;", + " isSorted = true;", + " }", + " }", + "}", + "console.log(arr);", + "", + "}", + "", + "", + "{{out}}", + "
    ",
    +        " [0, 1, 3, 4, 5, 9]",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8004", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n // Node 5.4.1 tested implementation (ES6)\n\"use strict\";\n\nlet arr = [4, 9, 0, 3, 1, 5];\nlet isSorted = true;\nwhile (isSorted){\n for (let i = 0; i< arr.length - 1;i++){\n if (arr[i] > arr[i + 1])\n {\n let temp = arr[i];\n arr[i] = arr[i + 1];\n arr[i+1] = temp;\n isSorted = true;\n }\n }\n\n if (!isSorted)\n break;\n \n isSorted = false;\n\n for (let j = arr.length - 1; j > 0; j--){\n if (arr[j-1] > arr[j])\n {\n let temp = arr[j];\n arr[j] = arr[j - 1];\n arr[j - 1] = temp;\n isSorted = true;\n }\n }\n}\nconsole.log(arr);\n\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Comb sort", + "type": "Waypoint", + "description": [ + "Task:", + "

    Implement a comb sort.

    ", + "

    The Comb Sort is a variant of the Bubble Sort.

    Like the Shell sort, the Comb Sort increases the gap used in comparisons and exchanges.

    Dividing the gap by $(1-e^{-\\varphi})^{-1} \\approx 1.247330950103979$ works best, but 1.3 may be more practical.

    ", + "

    Some implementations use the insertion sort once the gap is less than a certain amount.

    ", + "Also see:", + " the Wikipedia article: Comb sort.

    Variants:

    ", + "Combsort11 makes sure the gap ends in (11, 8, 6, 4, 3, 2, 1), which is significantly faster than the other two possible endings.", + "Combsort with different endings changes to a more efficient sort when the data is almost sorted (when the gap is small). Comb sort with a low gap isn't much better than the Bubble Sort.", + "

    Pseudocode:

    ", + "

    function combsort(array input)

    ", + "

    gap := input.size //initialize gap size

    ", + "

    loop until gap = 1 and swaps = 0

    ", + "

    //update the gap value for a next comb. Below is an example

    ", + "

    gap := int(gap / 1.25)

    ", + "

    if gap < 1

    ", + "

    //minimum gap is 1

    ", + "

    gap := 1

    ", + "

    end if

    ", + "

    i := 0

    ", + "

    swaps := 0 //see Bubble Sort for an explanation

    ", + "

    //a single \"comb\" over the input list

    ", + "

    loop until i + gap >= input.size //see Shell sort for similar idea

    ", + "

    if input[i] > input[i+gap]

    ", + "

    swap(input[i], input[i+gap])

    ", + "

    swaps := 1 // Flag a swap has occurred, so the

    ", + "

    // list is not guaranteed sorted

    ", + "

    end if

    ", + "

    i := i + 1

    ", + "

    end loop

    ", + "

    end loop

    ", + "

    end function

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + " // Node 5.4.1 tested implementation (ES6)", + " function is_array_sorted(arr) {", + " var sorted = true;", + " for (var i = 0; i < arr.length - 1; i++) {", + " if (arr[i] > arr[i + 1]) {", + " sorted = false;", + " break;", + " }", + " }", + " return sorted;", + " }", + "", + " // Array to sort", + " var arr = [4, 9, 0, 3, 1, 5];", + "", + " var iteration_count = 0;", + " var gap = arr.length - 2;", + " var decrease_factor = 1.25;", + "", + " // Until array is not sorted, repeat iterations", + " while (!is_array_sorted(arr)) {", + " // If not first gap", + " if (iteration_count > 0)", + " // Calculate gap", + " gap = (gap == 1) ? gap : Math.floor(gap / decrease_factor);", + "", + " // Set front and back elements and increment to a gap", + " var front = 0;", + " var back = gap;", + " while (back <= arr.length - 1) {", + " // If elements are not ordered swap them", + " if (arr[front] > arr[back]) {", + " var temp = arr[front];", + " arr[front] = arr[back];", + " arr[back] = temp;", + " }", + "", + " // Increment and re-run swapping", + " front += 1;", + " back += 1;", + " }", + " iteration_count += 1;", + " }", + "", + " // Print the sorted array", + " console.log(arr);", + "}", + "", + "", + "{{out}}", + "
    ",
    +        " [0, 1, 3, 4, 5, 9]",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8005", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n // Node 5.4.1 tested implementation (ES6)\n function is_array_sorted(arr) {\n var sorted = true;\n for (var i = 0; i < arr.length - 1; i++) {\n if (arr[i] > arr[i + 1]) {\n sorted = false;\n break;\n }\n }\n return sorted;\n }\n\n // Array to sort\n var arr = [4, 9, 0, 3, 1, 5];\n\n var iteration_count = 0;\n var gap = arr.length - 2;\n var decrease_factor = 1.25;\n\n // Until array is not sorted, repeat iterations\n while (!is_array_sorted(arr)) {\n // If not first gap\n if (iteration_count > 0)\n // Calculate gap\n gap = (gap == 1) ? gap : Math.floor(gap / decrease_factor);\n\n // Set front and back elements and increment to a gap\n var front = 0;\n var back = gap;\n while (back <= arr.length - 1) {\n // If elements are not ordered swap them\n if (arr[front] > arr[back]) {\n var temp = arr[front];\n arr[front] = arr[back];\n arr[back] = temp;\n }\n\n // Increment and re-run swapping\n front += 1;\n back += 1;\n }\n iteration_count += 1;\n }\n\n // Print the sorted array\n console.log(arr);\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Counting sort", + "type": "Waypoint", + "description": [ + "

    Implement the Counting sort. This is a way of sorting integers when the minimum and maximum value are known.

    Pseudocode:

    ", + "

    function countingSort(array, min, max):

    ", + "

    count: array of (max - min + 1) elements

    ", + "

    initialize count with 0

    ", + "

    for each number in array do

    ", + "

    count[number - min] := count[number - min] + 1

    ", + "

    done

    ", + "

    z := 0

    ", + "

    for i from min to max do

    ", + "

    while ( count[i - min] > 0 ) do

    ", + "

    array[z] := i

    ", + "

    z := z+1

    ", + "

    count[i - min] := count[i - min] - 1

    ", + "

    done

    ", + "

    done

    The min and max can be computed apart, or be known a priori.

    Note: we know that, given an array of integers, its maximum and minimum values can be always found; but if we imagine the worst case for an array of 32 bit integers, we see that in order to hold the counts, we need an array of 232 elements, i.e., we need, to hold a count value up to 232-1, more or less 4 Gbytes. So the counting sort is more practical when the range is (very) limited and minimum and maximum values are known a priori. (Anyway sparse arrays may limit the impact of the memory usage)

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "var countSort = function(arr, min, max) {", + " var i, z = 0, count = [];", + " ", + " for (i = min; i <= max; i++) {", + " count[i] = 0;", + " }", + " ", + " for (i=0; i < arr.length; i++) {", + " count[arr[i]]++;", + " }", + " ", + " for (i = min; i <= max; i++) {", + " while (count[i]-- > 0) {", + " arr[z++] = i;", + " }", + " }", + " ", + "}", + "", + "Testing:", + "", + "// Line breaks are in HTML", + "", + "var i, ages = [];", + "", + "for (i = 0; i < 100; i++) {", + " ages.push(Math.floor(Math.random() * (141)));", + "}", + "", + "countSort(ages, 0, 140);", + "", + "for (i = 0; i < 100; i++) {", + " document.write(ages[i] + \"
    \");", + "}
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8006", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var countSort = function(arr, min, max) {\n var i, z = 0, count = [];\n \n for (i = min; i <= max; i++) {\n count[i] = 0;\n }\n \n for (i=0; i < arr.length; i++) {\n count[arr[i]]++;\n }\n \n for (i = min; i <= max; i++) {\n while (count[i]-- > 0) {\n arr[z++] = i;\n }\n }\n \n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Gnome sort", + "type": "Waypoint", + "description": [ + "

    Gnome sort is a sorting algorithm which is similar to Insertion sort, except that moving an element to its proper place is accomplished by a series of swaps, as in Bubble Sort.

    The pseudocode for the algorithm is:

    ", + "

    function gnomeSort(a[0..size-1])

    ", + "

    i := 1

    ", + "

    j := 2

    ", + "

    while i < size do

    ", + "

    if a[i-1] <= a[i] then

    ", + "

    // for descending sort, use >= for comparison

    ", + "

    i := j

    ", + "

    j := j + 1

    ", + "

    else

    ", + "

    swap a[i-1] and a[i]

    ", + "

    i := i - 1

    ", + "

    if i = 0 then

    ", + "

    i := j

    ", + "

    j := j + 1

    ", + "

    endif

    ", + "

    endif

    ", + "

    done

    Task: implement the Gnome sort in your language to sort an array (or list) of numbers.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function gnomeSort(a) {", + " function moveBack(i) {", + " for( ; i > 0 && a[i-1] > a[i]; i--) {", + " var t = a[i];", + " a[i] = a[i-1];", + " a[i-1] = t;", + " }", + " }", + " for (var i = 1; i < a.length; i++) {", + " if (a[i-1] > a[i]) moveBack(i);", + " }", + " return a;", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8007", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function gnomeSort(a) {\n function moveBack(i) {\n for( ; i > 0 && a[i-1] > a[i]; i--) {\n var t = a[i];\n a[i] = a[i-1];\n a[i-1] = t;\n }\n }\n for (var i = 1; i < a.length; i++) {\n if (a[i-1] > a[i]) moveBack(i);\n }\n return a;\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Heapsort", + "type": "Waypoint", + "description": [ + "

    Heapsort is an in-place sorting algorithm with worst case and average complexity of O(n logn).

    The basic idea is to turn the array into a binary heap structure, which has the property that it allows efficient retrieval and removal of the maximal element.

    We repeatedly \"remove\" the maximal element from the heap, thus building the sorted list from back to front.

    Heapsort requires random access, so can only be used on an array-like data structure.

    Pseudocode:

    ", + "

    function heapSort(a, count) is

    ", + "

    input: an unordered array a of length count

    (first place a in max-heap order)

    ", + "

    heapify(a, count)

    end := count - 1

    ", + "

    while end > 0 do

    ", + "

    (swap the root(maximum value) of the heap with the

    ", + "

    last element of the heap)

    ", + "

    swap(a[end], a[0])

    ", + "

    (decrement the size of the heap so that the previous

    ", + "

    max value will stay in its proper place)

    ", + "

    end := end - 1

    ", + "

    (put the heap back in max-heap order)

    ", + "

    siftDown(a, 0, end)

    ", + "

    function heapify(a,count) is

    ", + "

    (start is assigned the index in a of the last parent node)

    ", + "

    start := (count - 2) / 2

    while start ≥ 0 do

    ", + "

    (sift down the node at index start to the proper place

    ", + "

    such that all nodes below the start index are in heap

    ", + "

    order)

    ", + "

    siftDown(a, start, count-1)

    ", + "

    start := start - 1

    ", + "

    (after sifting down the root all nodes/elements are in heap order)

    function siftDown(a, start, end) is

    ", + "

    (end represents the limit of how far down the heap to sift)

    ", + "

    root := start

    while root * 2 + 1 ≤ end do (While the root has at least one child)

    ", + "

    child := root * 2 + 1 (root*2+1 points to the left child)

    ", + "

    (If the child has a sibling and the child's value is less than its sibling's...)

    ", + "

    if child + 1 ≤ end and a[child] < a[child + 1] then

    ", + "

    child := child + 1 (... then point to the right child instead)

    ", + "

    if a[root] < a[child] then (out of max-heap order)

    ", + "

    swap(a[root], a[child])

    ", + "

    root := child (repeat to continue sifting down the child now)

    ", + "

    else

    ", + "

    return

    ", + "

    Write a function to sort a collection of integers using heapsort.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8008", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Insertion sort", + "type": "Waypoint", + "description": [ + "

    An O(n2) sorting algorithm which moves elements one at a time into the correct position.

    ", + "

    The algorithm consists of inserting one element at a time into the previously sorted part of the array, moving higher ranked elements up as necessary.

    ", + "

    To start off, the first (or smallest, or any arbitrary) element of the unsorted array is considered to be the sorted part.

    Although insertion sort is an O(n2) algorithm, its simplicity, low overhead, good locality of reference and efficiency make it a good choice in two cases:

    ", + "

    (i) small n,

    ", + "

    (ii) as the final finishing-off algorithm for O(n logn) algorithms such as mergesort and quicksort.

    The algorithm is as follows (from wikipedia):

    ", + "

    function insertionSort(array A)

    ", + "

    for i from 1 to length[A]-1 do

    ", + "

    value := A[i]

    ", + "

    j := i-1

    ", + "

    while j >= 0 and A[j] > value do

    ", + "

    A[j+1] := A[j]

    ", + "

    j := j-1

    ", + "

    done

    ", + "

    A[j+1] = value

    ", + "

    done

    Writing the algorithm for integers will suffice.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "function insertionSort (a) {", + " for (var i = 0; i < a.length; i++) {", + " var k = a[i];", + " for (var j = i; j > 0 && k < a[j - 1]; j--)", + " a[j] = a[j - 1];", + " a[j] = k;", + " }", + " return a;", + "}", + "", + "var a = [4, 65, 2, -31, 0, 99, 83, 782, 1];", + "insertionSort(a);", + "document.write(a.join(\" \"));", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8009", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nfunction insertionSort (a) {\n for (var i = 0; i < a.length; i++) {\n var k = a[i];\n for (var j = i; j > 0 && k < a[j - 1]; j--)\n a[j] = a[j - 1];\n a[j] = k;\n }\n return a;\n}\n\nvar a = [4, 65, 2, -31, 0, 99, 83, 782, 1];\ninsertionSort(a);\ndocument.write(a.join(\" \"));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Merge sort", + "type": "Waypoint", + "description": [ + "

    The merge sort is a recursive sort of order n*log(n).

    It is notable for having a worst case and average complexity of O(n*log(n)), and a best case complexity of O(n) (for pre-sorted input).

    The basic idea is to split the collection into smaller groups by halving it until the groups only have one element or no elements (which are both entirely sorted groups).

    Then merge the groups back together so that their elements are in order.

    This is how the algorithm gets its divide and conquer description.

    ", + "Task:", + "

    Write a function to sort a collection of integers using the merge sort.

    ", + "

    The merge sort algorithm comes in two parts:

    ", + "

    a sort function and

    ", + "

    a merge function

    The functions in pseudocode look like this:

    ", + "

    function mergesort(m)

    ", + "

    var list left, right, result

    ", + "

    if length(m) ≤ 1

    ", + "

    return m

    ", + "

    else

    ", + "

    var middle = length(m) / 2

    ", + "

    for each x in m up to middle - 1

    ", + "

    add x to left

    ", + "

    for each x in m at and after middle

    ", + "

    add x to right

    ", + "

    left = mergesort(left)

    ", + "

    right = mergesort(right)

    ", + "

    if last(left) ≤ first(right)

    ", + "

    append right to left

    ", + "

    return left

    ", + "

    result = merge(left, right)

    ", + "

    return result

    function merge(left,right)

    ", + "

    var list result

    ", + "

    while length(left) > 0 and length(right) > 0

    ", + "

    if first(left) ≤ first(right)

    ", + "

    append first(left) to result

    ", + "

    left = rest(left)

    ", + "

    else

    ", + "

    append first(right) to result

    ", + "

    right = rest(right)

    ", + "

    if length(left) > 0

    ", + "

    append rest(left) to result

    ", + "

    if length(right) > 0

    ", + "

    append rest(right) to result

    ", + "

    return result

    ", + "See also:", + " the Wikipedia entry: merge sort

    Note: better performance can be expected if, rather than recursing until length(m) ≤ 1, an insertion sort is used for length(m) smaller than some threshold larger than 1. However, this complicates the example code, so it is not shown here.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function merge(left, right, arr) {", + " var a = 0;", + "", + " while (left.length && right.length) {", + " arr[a++] = (right[0] < left[0]) ? right.shift() : left.shift();", + " }", + " while (left.length) {", + " arr[a++] = left.shift();", + " }", + " while (right.length) {", + " arr[a++] = right.shift();", + " }", + "}", + "", + "function mergeSort(arr) {", + " var len = arr.length;", + "", + " if (len === 1) { return; }", + "", + " var mid = Math.floor(len / 2),", + " left = arr.slice(0, mid),", + " right = arr.slice(mid);", + "", + " mergeSort(left);", + " mergeSort(right);", + " merge(left, right, arr);", + "}", + "", + "var arr = [1, 5, 2, 7, 3, 9, 4, 6, 8];", + "mergeSort(arr); // arr will now: 1, 2, 3, 4, 5, 6, 7, 8, 9", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc800a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function merge(left, right, arr) {\n var a = 0;\n\n while (left.length && right.length) {\n arr[a++] = (right[0] < left[0]) ? right.shift() : left.shift();\n }\n while (left.length) {\n arr[a++] = left.shift();\n }\n while (right.length) {\n arr[a++] = right.shift();\n }\n}\n\nfunction mergeSort(arr) {\n var len = arr.length;\n\n if (len === 1) { return; }\n\n var mid = Math.floor(len / 2),\n left = arr.slice(0, mid),\n right = arr.slice(mid);\n\n mergeSort(left);\n mergeSort(right);\n merge(left, right, arr);\n}\n\nvar arr = [1, 5, 2, 7, 3, 9, 4, 6, 8];\nmergeSort(arr); // arr will now: 1, 2, 3, 4, 5, 6, 7, 8, 9\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Pancake sort", + "type": "Waypoint", + "description": [ + "Task:", + "

    Sort an array of integers (of any convenient size) into ascending order using Pancake sorting.

    In short, instead of individual elements being sorted, the only operation allowed is to \"flip\" one end of the list, like so:

    ", + "

    Before:

    ", + "

    6 7 8 9 2 5 3 4 1

    ", + "

    After:

    ", + "

    9 8 7 6 2 5 3 4 1

    Only one end of the list can be flipped; this should be the low end, but the high end is okay if it's easier to code or works better, but it must be the same end for the entire solution. (The end flipped can't be arbitrarily changed.)

    Show both the initial, unsorted list and the final sorted list. (Intermediate steps during sorting are optional.) Optimizations are optional (but recommended).

    For more information on pancake sorting, see the Wikipedia entry.

    See also:

    ", + "Number reversal game", + "Topswops" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Array.prototype.pancake_sort = function () {", + " for (var i = this.length - 1; i >= 1; i--) {", + " // find the index of the largest element not yet sorted", + " var max_idx = 0;", + " var max = this[0];", + " for (var j = 1; j <= i; j++) {", + " if (this[j] > max) {", + " max = this[j];", + " max_idx = j;", + " }", + " }", + "", + " if (max_idx == i) ", + " continue; // element already in place", + "", + " var new_slice;", + "", + " // flip this max element to index 0", + " if (max_idx > 0) {", + " new_slice = this.slice(0, max_idx+1).reverse();", + " for (var j = 0; j <= max_idx; j++) ", + " this[j] = new_slice[j];", + " }", + "", + " // then flip the max element to its place", + " new_slice = this.slice(0, i+1).reverse();", + " for (var j = 0; j <= i; j++) ", + " this[j] = new_slice[j];", + " }", + " return this;", + "}", + "ary = [7,6,5,9,8,4,3,1,2,0]", + "sorted = ary.concat().pancake_sort();", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc800b", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "Array.prototype.pancake_sort = function () {\n for (var i = this.length - 1; i >= 1; i--) {\n // find the index of the largest element not yet sorted\n var max_idx = 0;\n var max = this[0];\n for (var j = 1; j <= i; j++) {\n if (this[j] > max) {\n max = this[j];\n max_idx = j;\n }\n }\n\n if (max_idx == i) \n continue; // element already in place\n\n var new_slice;\n\n // flip this max element to index 0\n if (max_idx > 0) {\n new_slice = this.slice(0, max_idx+1).reverse();\n for (var j = 0; j <= max_idx; j++) \n this[j] = new_slice[j];\n }\n\n // then flip the max element to its place\n new_slice = this.slice(0, i+1).reverse();\n for (var j = 0; j <= i; j++) \n this[j] = new_slice[j];\n }\n return this;\n}\nary = [7,6,5,9,8,4,3,1,2,0]\nsorted = ary.concat().pancake_sort();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Permutation sort", + "type": "Waypoint", + "description": [ + "Task:", + "

    Implement a permutation sort, which proceeds by generating the possible permutations

    ", + "

    of the input array/list until discovering the sorted one.

    Pseudocode:

    ", + "

    while not InOrder(list) do

    ", + "

    nextPermutation(list)

    ", + "

    done

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc800c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Quicksort", + "type": "Waypoint", + "description": [ + "Task:", + "

    Sort an array (or list) elements using the quicksort algorithm.

    The elements must have a strict weak order and the index of the array can be of any discrete type.

    For languages where this is not possible, sort an array of integers.

    ", + "

    Quicksort, also known as partition-exchange sort, uses these steps.

    :# Choose any element of the array to be the pivot.

    ", + "

    :# Divide all other elements (except the pivot) into two partitions.

    ", + "

    :#* All elements less than the pivot must be in the first partition.

    ", + "

    :#* All elements greater than the pivot must be in the second partition.

    ", + "

    :# Use recursion to sort both partitions.

    ", + "

    :# Join the first sorted partition, the pivot, and the second sorted partition.

    ", + "

    The best pivot creates partitions of equal length (or lengths differing by 1).

    The worst pivot creates an empty partition (for example, if the pivot is the first or last element of a sorted array).

    The run-time of Quicksort ranges from O(n log n) with the best pivots, to O(n2) with the worst pivots, where n is the number of elements in the array.

    ", + "

    This is a simple quicksort algorithm, adapted from Wikipedia.

    function quicksort(array)

    ", + "

    less, equal, greater := three empty arrays

    ", + "

    if length(array) > 1

    ", + "

    pivot := select any element of array

    ", + "

    for each x in array

    ", + "

    if x < pivot then add x to less

    ", + "

    if x = pivot then add x to equal

    ", + "

    if x > pivot then add x to greater

    ", + "

    quicksort(less)

    ", + "

    quicksort(greater)

    ", + "

    array := concatenate(less, equal, greater)

    A better quicksort algorithm works in place, by swapping elements within the array, to avoid the memory allocation of more arrays.

    function quicksort(array)

    ", + "

    if length(array) > 1

    ", + "

    pivot := select any element of array

    ", + "

    left := first index of array

    ", + "

    right := last index of array

    ", + "

    while left ≤ right

    ", + "

    while array[left] < pivot

    ", + "

    left := left + 1

    ", + "

    while array[right] > pivot

    ", + "

    right := right - 1

    ", + "

    if left ≤ right

    ", + "

    swap array[left] with array[right]

    ", + "

    left := left + 1

    ", + "

    right := right - 1

    ", + "

    quicksort(array from first index to right)

    ", + "

    quicksort(array from left to last index)

    Quicksort has a reputation as the fastest sort. Optimized variants of quicksort are common features of many languages and libraries. One often contrasts quicksort with merge sort, because both sorts have an average time of O(n log n).

    \"On average, mergesort does fewer comparisons than quicksort, so it may be better when complicated comparison routines are used. Mergesort also takes advantage of pre-existing order, so it would be favored for using sort() to merge several sorted arrays. On the other hand, quicksort is often faster for small arrays, and on arrays of a few distinct values, repeated many times.\" — http://perldoc.perl.org/sort.html

    Quicksort is at one end of the spectrum of divide-and-conquer algorithms, with merge sort at the opposite end.

    Quicksort is a conquer-then-divide algorithm, which does most of the work during the partitioning and the recursive calls. The subsequent reassembly of the sorted partitions involves trivial effort.", + "Merge sort is a divide-then-conquer algorithm. The partioning happens in a trivial way, by splitting the input array in half. Most of the work happens during the recursive calls and the merge phase.", + "

    With quicksort, every element in the first partition is less than or equal to every element in the second partition. Therefore, the merge phase of quicksort is so trivial that it needs no mention!

    This task has not specified whether to allocate new arrays, or sort in place. This task also has not specified how to choose the pivot element. (Common ways to are to choose the first element, the middle element, or the median of three elements.) Thus there is a variety among the following implementations.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Imperative===", + "", + "function sort(array, less) {", + "", + " function swap(i, j) {", + " var t = array[i];", + " array[i] = array[j];", + " array[j] = t;", + " }", + "", + " function quicksort(left, right) {", + "", + " if (left < right) {", + " var pivot = array[left + Math.floor((right - right) / 2)],", + " left_new = left,", + " right_new = right;", + "", + " do {", + " while (less(array[left_new], pivot)) {", + " left_new += 1;", + " }", + " while (less(pivot, array[right_new])) {", + " right_new -= 1;", + " }", + " if (left_new <= right_new) {", + " swap(left_new, right_new);", + " left_new += 1;", + " right_new -= 1;", + " }", + " } while (left_new <= right_new);", + "", + " quicksort(left, right_new);", + " quicksort(left_new, right);", + "", + " }", + " }", + "", + " quicksort(0, array.length - 1);", + "", + " return array;", + "}", + "", + "Example:var test_array = [10, 3, 11, 15, 19, 1];", + "var sorted_array = sort(test_array, function(a,b) { return a", + "", + "{{Out}}[ 1, 3, 10, 11, 15, 19 ]", + "", + "===Functional===", + "", + "", + "====ES5====", + "", + "Emphasising clarity more than run-time optimisation (for which Array.sort() would be a better option)", + "", + "(function () {", + " 'use strict';", + "", + " // quickSort :: (Ord a) => [a] -> [a] ", + " function quickSort(xs) {", + "", + " if (xs.length) {", + " var h = xs[0],", + " t = xs.slice(1),", + "", + " lessMore = partition(function (x) {", + " return x <= h;", + " }, t),", + " less = lessMore[0],", + " more = lessMore[1];", + "", + " return [].concat.apply(", + " [], [quickSort(less), h, quickSort(more)]", + " );", + "", + " } else return [];", + " }", + "", + "", + " // partition :: Predicate -> List -> (Matches, nonMatches)", + " // partition :: (a -> Bool) -> [a] -> ([a], [a])", + " function partition(p, xs) {", + " return xs.reduce(function (a, x) {", + " return (", + " a[p(x) ? 0 : 1].push(x),", + " a", + " );", + " }, [[], []]);", + " }", + "", + " return quickSort([11.8, 14.1, 21.3, 8.5, 16.7, 5.7])", + "", + "})();", + "", + "{{Out}}", + "", + "
    [5.7, 8.5, 11.8, 14.1, 16.7, 21.3]
    ", + "", + "====ES6====", + "", + "Array.prototype.quick_sort = function () {", + " if (this.length < 2) { return this; }", + "", + " var pivot = this[Math.round(this.length / 2)];", + "", + " return this.filter(x => x < pivot)", + " .quick_sort()", + " .concat(this.filter(x => x == pivot))", + " .concat(this.filter(x => x > pivot).quick_sort());", + "};", + "", + "", + "Or, expressed in terms of a single partition, rather than two consecutive filters:", + "", + "(() => {", + " 'use strict';", + "", + " // QUICKSORT --------------------------------------------------------------", + "", + " // quickSort :: (Ord a) => [a] -> [a]", + " const quickSort = xs =>", + " xs.length > 1 ? (() => {", + " const", + " h = xs[0],", + " [less, more] = partition(x => x <= h, xs.slice(1));", + " return [].concat.apply(", + " [], [quickSort(less), h, quickSort(more)]", + " );", + " })() : xs;", + "", + "", + " // GENERIC ----------------------------------------------------------------", + "", + " // partition :: Predicate -> List -> (Matches, nonMatches)", + " // partition :: (a -> Bool) -> [a] -> ([a], [a])", + " const partition = (p, xs) =>", + " xs.reduce((a, x) =>", + " p(x) ? [a[0].concat(x), a[1]] : [a[0], a[1].concat(x)], [", + " [],", + " []", + " ]);", + "", + " // TEST -------------------------------------------------------------------", + " return quickSort([11.8, 14.1, 21.3, 8.5, 16.7, 5.7]);", + "})();", + "{{Out}}", + "
    [5.7, 8.5, 11.8, 14.1, 16.7, 21.3]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc800d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function sort(array, less) {\n\n function swap(i, j) {\n var t = array[i];\n array[i] = array[j];\n array[j] = t;\n }\n\n function quicksort(left, right) {\n\n if (left < right) {\n var pivot = array[left + Math.floor((right - right) / 2)],\n left_new = left,\n right_new = right;\n\n do {\n while (less(array[left_new], pivot)) {\n left_new += 1;\n }\n while (less(pivot, array[right_new])) {\n right_new -= 1;\n }\n if (left_new <= right_new) {\n swap(left_new, right_new);\n left_new += 1;\n right_new -= 1;\n }\n } while (left_new <= right_new);\n\n quicksort(left, right_new);\n quicksort(left_new, right);\n\n }\n }\n\n quicksort(0, array.length - 1);\n\n return array;\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Radix sort", + "type": "Waypoint", + "description": [ + "Task:", + "

    Sort an integer array with the radix sort algorithm.

    The primary purpose is to complete the characterization of sort algorithms task.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc800e", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Selection sort", + "type": "Waypoint", + "description": [ + "Task:", + "

    Sort an array (or list) of elements using the Selection sort algorithm.

    ", + "

    It works as follows:

    First find the smallest element in the array and exchange it with the element in the first position, then find the second smallest element and exchange it with the element in the second position, and continue in this way until the entire array is sorted.

    ", + "

    Its asymptotic complexity is O(n2) making it inefficient on large arrays.

    Its primary purpose is for when writing data is very expensive (slow) when compared to reading, eg. writing to flash memory or EEPROM.

    No other sorting algorithm has less data movement.

    ", + "Reference:", + "Wikipedia: Selection sort" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "This algorithm sorts array of numbers.", + "function selectionSort(nums) {", + " var len = nums.length;", + " for(var i = 0; i < len; i++) {", + " var minAt = i;", + " for(var j = i + 1; j < len; j++) {", + " if(nums[j] < nums[minAt])", + " minAt = j;", + " }", + "", + " if(minAt != i) {", + " var temp = nums[i];", + " nums[i] = nums[minAt];", + " nums[minAt] = temp;", + " }", + " }", + " return nums;", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc800f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function selectionSort(nums) {\n var len = nums.length;\n for(var i = 0; i < len; i++) {\n var minAt = i;\n for(var j = i + 1; j < len; j++) {\n if(nums[j] < nums[minAt])\n minAt = j;\n }\n\n if(minAt != i) {\n var temp = nums[i];\n nums[i] = nums[minAt];\n nums[minAt] = temp;\n }\n }\n return nums;\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Shell sort", + "type": "Waypoint", + "description": [ + "Task:", + "

    Sort an array of elements using the Shell sort algorithm, a diminishing increment sort.

    The Shell sort (also known as Shellsort or Shell's method) is named after its inventor, Donald Shell, who published the algorithm in 1959.

    Shell sort is a sequence of interleaved insertion sorts based on an increment sequence.

    ", + "

    The increment size is reduced after each pass until the increment size is 1.

    With an increment size of 1, the sort is a basic insertion sort, but by this time the data is guaranteed to be almost sorted, which is insertion sort's \"best case\".

    Any sequence will sort the data as long as it ends in 1, but some work better than others.

    Empirical studies have shown a geometric increment sequence with a ratio of about 2.2 work well in practice.

    ", + "

    [http://www.cs.princeton.edu/~rs/shell/]

    Other good sequences are found at the On-Line Encyclopedia of Integer Sequences.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function shellSort (a) {", + " for (var h = a.length; h > 0; h = parseInt(h / 2)) {", + " for (var i = h; i < a.length; i++) {", + " var k = a[i];", + " for (var j = i; j >= h && k < a[j - h]; j -= h)", + " a[j] = a[j - h];", + " a[j] = k;", + " }", + " }", + " return a;", + "}", + "", + "var a = [];", + "var n = location.href.match(/\\?(\\d+)|$/)[1] || 10;", + "for (var i = 0; i < n; i++)", + " a.push(parseInt(Math.random() * 100));", + "shellSort(a);", + "document.write(a.join(\" \"));", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8010", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function shellSort (a) {\n for (var h = a.length; h > 0; h = parseInt(h / 2)) {\n for (var i = h; i < a.length; i++) {\n var k = a[i];\n for (var j = i; j >= h && k < a[j - h]; j -= h)\n a[j] = a[j - h];\n a[j] = k;\n }\n }\n return a;\n}\n\nvar a = [];\nvar n = location.href.match(/\\?(\\d+)|$/)[1] || 10;\nfor (var i = 0; i < n; i++)\n a.push(parseInt(Math.random() * 100));\nshellSort(a);\ndocument.write(a.join(\" \"));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Sleep sort", + "type": "Waypoint", + "description": [ + "

    In general, sleep sort works by starting a separate task for each item to be sorted, where each task sleeps for an interval corresponding to the item's sort key, then emits the item. Items are then collected sequentially in time.

    Task: Write a program that implements sleep sort. Have it accept non-negative integers on the command line and print the integers in sorted order. If this is not idomatic in your language or environment, input and output may be done differently. Enhancements for optimization, generalization, practicality, robustness, and so on are not required.

    Sleep sort was presented anonymously on 4chan and has been discussed on Hacker News.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Array.prototype.timeoutSort = function (f) {", + "\tthis.forEach(function (n) {", + "\t\tsetTimeout(function () { f(n) }, 5 * n)", + "\t});", + "}", + "", + "Usage and output:", + "[1, 9, 8, 7, 6, 5, 3, 4, 5, 2, 0].timeoutSort(function(n) { document.write(n + 'br'); })", + "
    ",
    +        "0",
    +        "1",
    +        "2",
    +        "3",
    +        "4",
    +        "5",
    +        "6",
    +        "7",
    +        "8",
    +        "9",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8011", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "Array.prototype.timeoutSort = function (f) {\n\tthis.forEach(function (n) {\n\t\tsetTimeout(function () { f(n) }, 5 * n)\n\t});\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Stooge sort", + "type": "Waypoint", + "description": [ + "Task:", + "

    Show the Stooge Sort for an array of integers.

    ", + "

    The Stooge Sort algorithm is as follows:

    ", + "

    algorithm stoogesort(array L, i = 0, j = length(L)-1)

    ", + "

    if L[j] < L[i] then

    ", + "

    L[i] L[j]

    ", + "

    if j - i > 1 then

    ", + "

    t := (j - i + 1)/3

    ", + "

    stoogesort(L, i , j-t)

    ", + "

    stoogesort(L, i+t, j )

    ", + "

    stoogesort(L, i , j-t)

    ", + "

    return L

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function stoogeSort (array, i, j) {", + " if (j === undefined) {", + " j = array.length - 1;", + " }", + "", + " if (i === undefined) {", + " i = 0;", + " }", + "", + " if (array[j] < array[i]) {", + " var aux = array[i];", + " array[i] = array[j];", + " array[j] = aux;", + " }", + "", + " if (j - i > 1) {", + " var t = Math.floor((j - i + 1) / 3);", + " stoogeSort(array, i, j-t);", + " stoogeSort(array, i+t, j);", + " stoogeSort(array, i, j-t);", + " }", + "};", + "Example:", + "arr = [9,1,3,10,13,4,2];", + "stoogeSort(arr);", + "console.log(arr);", + "{{out}}", + "
    [1, 2, 3, 4, 9, 10, 13]
    ", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8012", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function stoogeSort (array, i, j) {\n if (j === undefined) {\n j = array.length - 1;\n }\n\n if (i === undefined) {\n i = 0;\n }\n\n if (array[j] < array[i]) {\n var aux = array[i];\n array[i] = array[j];\n array[j] = aux;\n }\n\n if (j - i > 1) {\n var t = Math.floor((j - i + 1) / 3);\n stoogeSort(array, i, j-t);\n stoogeSort(array, i+t, j);\n stoogeSort(array, i, j-t);\n }\n};\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sorting algorithms/Strand sort", + "type": "Waypoint", + "description": [ + "Task:", + "

    Implement the Strand sort.

    This is a way of sorting numbers by extracting shorter sequences of already sorted numbers from an unsorted list.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8013", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sort stability", + "type": "Waypoint", + "description": [ + "

    When sorting records in a table by a particular column or field, a stable sort will always retain the relative order of records that have the same key.

    For example, in this table of countries and cities, a stable sort on the second column, the cities, would keep the US Birmingham above the UK Birmingham. (Although an unstable sort might, in this case, place the US Birmingham above the UK Birmingham, a stable sort routine would guarantee it).

    ", + "
    UK  London",
    +        "US  New York",
    +        "US  Birmingham",
    +        "UK  Birmingham
    ", + "

    Similarly, stable sorting on just the first column would generate “UK London” as the first item and “US Birmingham” as the last item (since the order of the elements having the same first word – “UK” or “US” – would be maintained).

    Examine the documentation on any in-built sort routines supplied by a language.", + "Indicate if an in-built routine is supplied", + "If supplied, indicate whether or not the in-built routine is stable.", + "

    (This Wikipedia table shows the stability of some common sort routines).

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "The ECMA standard does not specify what sorting algorithm to use, so it depends upon the implementation.", + "", + "ary = [[\"UK\", \"London\"], [\"US\", \"New York\"], [\"US\", \"Birmingham\"], [\"UK\", \"Birmingham\"]]", + "print(ary);", + "", + "ary.sort(function(a,b){return (a[1]b[1] ? 1 : 0))});", + "print(ary);", + "", + "/* a stable sort will output [\"US\", \"Birmingham\"] before [\"UK\", \"Birmingham\"] */", + "", + "Stable implementations:", + "{{works with|SpiderMonkey|1.8}}", + "{{works with|Firefox|3}}", + "{{works with|Internet Explorer|6}}", + "{{works with|JScript|5.7}}", + "{{works with|OSSP js}}", + "
    UK,London,US,New York,US,Birmingham,UK,Birmingham",
    +        "US,Birmingham,UK,Birmingham,UK,London,US,New York
    ", + "", + "Not stable:", + "{{works with|Rhino|1.7 rel 2}}", + "{{works with|Google Chrome|3.0}}", + "
    UK,London,US,New York,US,Birmingham,UK,Birmingham",
    +        "UK,Birmingham,US,Birmingham,UK,London,US,New York
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8014", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "ary = [[\"UK\", \"London\"], [\"US\", \"New York\"], [\"US\", \"Birmingham\"], [\"UK\", \"Birmingham\"]]\nprint(ary);\n\nary.sort(function(a,b){return (a[1]b[1] ? 1 : 0))});\nprint(ary);\n\n/* a stable sort will output [\"US\", \"Birmingham\"] before [\"UK\", \"Birmingham\"] */\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sort three variables", + "type": "Waypoint", + "description": [ + "Task: ", + "

    Sort (the values of) three variables (X, Y, and Z) that contain any value (numbers and/or literals).

    If that isn't possible in your language, then just sort numbers (and note if they can be floating point, integer, or other).

    ", + "

    I.E.: (for the three variables x, y, and z), where:

    ", + "

    x = 'lions, tigers, and'

    ", + "

    y = 'bears, oh my!'

    ", + "

    z = '(from the \"Wizard of OZ\")'

    After sorting, the three variables would hold:

    ", + "

    x = '(from the \"Wizard of OZ\")'

    ", + "

    y = 'bears, oh my!'

    ", + "

    z = 'lions, tigers, and'

    ", + "

    For numeric value sorting, use:

    I.E.: (for the three variables x, y, and z), where:

    ", + "

    x = 77444

    ", + "

    y = -12

    ", + "

    z = 0

    After sorting, the three variables would hold:

    ", + "

    x = -12

    ", + "

    y = 0

    ", + "

    z = 77444

    The variables should contain some form of a number, but specify if the algorithm

    ", + "

    used can be for floating point or integers. Note any limitations.

    ", + "

    The values may or may not be unique.

    ", + "

    The method used for sorting can be any algorithm; the goal is to use the most idiomatic in the computer programming language used.

    More than one algorithm could be shown if one isn't clearly the better choice.

    ", + "

    One algorithm could be:

    ", + "

    Θ store the three variables x, y, and z

    ", + "

    into an array (or a list) A

    Θ sort (the three elements of) the array A

    Θ extract the three elements from the array and place them in the

    ", + "

    variables x, y, and z in order of extraction

    Show the results of the sort here on this page using at least the values of those shown above.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8015", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sort using a custom comparator", + "type": "Waypoint", + "description": [ + "Task:", + "

    Sort an array (or list) of strings in order of descending length, and in ascending lexicographic order for strings of equal length.

    Use a sorting facility provided by the language/library, combined with your own callback comparison function.

    ", + "

    Note: Lexicographic order is case-insensitive.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "function lengthSorter(a, b) {", + " var result = b.length - a.length;", + " if (result == 0)", + " result = a.localeCompare(b);", + " return result;", + "}", + "", + "var test = [\"Here\", \"are\", \"some\", \"sample\", \"strings\", \"to\", \"be\", \"sorted\"];", + "test.sort(lengthSorter);", + "alert( test.join(' ') ); // strings sample sorted Here some are be to", + "", + "Or, abstracting a little for simpler composition of compound and derived searches (ASC and DESC, secondary sorts):", + "", + "(function () {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS FOR COMPARISONS", + "", + " // Ordering :: ( LT | EQ | GT ) | ( -1 | 0 | 1 )", + "", + " // compare :: a -> a -> Ordering", + " var compare = function (a, b) {", + " return a < b ? -1 : a > b ? 1 : 0;", + " };", + "", + " // mappendOrdering :: Ordering -> Ordering -> Ordering", + " var mappendOrdering = function (a, b) {", + " return a !== 0 ? a : b;", + " };", + "", + " // on :: (b -> b -> c) -> (a -> b) -> a -> a -> c", + " var on = function (f, g) {", + " return function (a, b) {", + " return f(g(a), g(b));", + " };", + " };", + "", + " // flip :: (a -> b -> c) -> b -> a -> c", + " var flip = function (f) {", + " return function (a, b) {", + " return f.apply(null, [b, a]);", + " };", + " };", + "", + " // arrayCopy :: [a] -> [a]", + " var arrayCopy = function (xs) {", + " return xs.slice(0);", + " };", + "", + " // show :: a -> String", + " var show = function (x) {", + " return JSON.stringify(x, null, 2);", + " };", + "", + " // TEST", + " var xs = ['Shanghai', 'Karachi', 'Beijing', 'Sao Paulo', 'Dhaka', 'Delhi', 'Lagos'];", + "", + " var rs = [{", + " name: 'Shanghai',", + " pop: 24.2", + " }, {", + " name: 'Karachi',", + " pop: 23.5", + " }, {", + " name: 'Beijing',", + " pop: 21.5", + " }, {", + " name: 'Sao Paulo',", + " pop: 24.2", + " }, {", + " name: 'Dhaka',", + " pop: 17.0", + " }, {", + " name: 'Delhi',", + " pop: 16.8", + " }, {", + " name: 'Lagos',", + " pop: 16.1", + " }];", + "", + " // population :: Dictionary -> Num", + " var population = function (x) {", + " return x.pop;", + " };", + "", + " // length :: [a] -> Int", + " var length = function (xs) {", + " return xs.length;", + " };", + "", + " // toLower :: String -> String", + " var toLower = function (s) {", + " return s.toLowerCase();", + " };", + "", + " // lengthThenAZ :: String -> String -> ( -1 | 0 | 1)", + " var lengthThenAZ = function (a, b) {", + " return mappendOrdering(", + " on(compare, length)(a, b),", + " on(compare, toLower)(a, b)", + " );", + " };", + "", + " // descLengthThenAZ :: String -> String -> ( -1 | 0 | 1)", + " var descLengthThenAZ = function (a, b) {", + " return mappendOrdering(", + " on(flip(compare), length)(a, b),", + " on(compare, toLower)(a, b)", + " );", + " };", + "", + " return show({", + " default: arrayCopy(xs)", + " .sort(compare),", + "", + " descendingDefault: arrayCopy(xs)", + " .sort(flip(compare)),", + "", + " byLengthThenAZ: arrayCopy(xs)", + " .sort(lengthThenAZ),", + "", + " byDescendingLengthThenZA: arrayCopy(xs)", + " .sort(flip(lengthThenAZ)),", + "", + " byDescendingLengthThenAZ: arrayCopy(xs)", + " .sort(descLengthThenAZ),", + "", + " byPopulation: arrayCopy(rs)", + " .sort(on(compare, population)),", + "", + " byDescendingPopulation: arrayCopy(rs)", + " .sort(on(flip(compare), population))", + " });", + "})();", + "", + "===ES6===", + "(() => {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS FOR COMPARISONS", + "", + " // Ordering :: ( LT | EQ | GT ) | ( -1 | 0 | 1 )", + " // compare :: a -> a -> Ordering", + " const compare = (a, b) => a < b ? -1 : (a > b ? 1 : 0);", + "", + " // mappendOrdering :: Ordering -> Ordering -> Ordering", + " const mappendOrdering = (a, b) => a !== 0 ? a : b;", + "", + " // on :: (b -> b -> c) -> (a -> b) -> a -> a -> c", + " const on = (f, g) => (a, b) => f(g(a), g(b));", + "", + " // flip :: (a -> b -> c) -> b -> a -> c", + " const flip = f => (a, b) => f.apply(null, [b, a]);", + "", + " // arrayCopy :: [a] -> [a]", + " const arrayCopy = (xs) => xs.slice(0);", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x, null, 2);", + "", + "", + " // TEST", + " const xs = ['Shanghai', 'Karachi', 'Beijing', 'Sao Paulo', 'Dhaka', 'Delhi', 'Lagos'];", + "", + " const rs = [{", + " name: 'Shanghai',", + " pop: 24.2", + " }, {", + " name: 'Karachi',", + " pop: 23.5", + " }, {", + " name: 'Beijing',", + " pop: 21.5", + " }, {", + " name: 'Sao Paulo',", + " pop: 24.2", + " }, {", + " name: 'Dhaka',", + " pop: 17.0", + " }, {", + " name: 'Delhi',", + " pop: 16.8", + " }, {", + " name: 'Lagos',", + " pop: 16.1", + " }]", + "", + " // population :: Dictionary -> Num", + " const population = x => x.pop;", + "", + " // length :: [a] -> Int", + " const length = xs => xs.length;", + "", + " // toLower :: String -> String", + " const toLower = s => s.toLowerCase();", + "", + " // lengthThenAZ :: String -> String -> ( -1 | 0 | 1)", + " const lengthThenAZ = (a, b) =>", + " mappendOrdering(", + " on(compare, length)(a, b),", + " on(compare, toLower)(a, b)", + " );", + "", + " // descLengthThenAZ :: String -> String -> ( -1 | 0 | 1)", + " const descLengthThenAZ = (a, b) =>", + " mappendOrdering(", + " on(flip(compare), length)(a, b),", + " on(compare, toLower)(a, b)", + " );", + "", + " return show({", + " default: arrayCopy(xs)", + " .sort(compare),", + "", + " descendingDefault: arrayCopy(xs)", + " .sort(flip(compare)),", + "", + " byLengthThenAZ: arrayCopy(xs)", + " .sort(lengthThenAZ),", + "", + " byDescendingLengthThenZA: arrayCopy(xs)", + " .sort(flip(lengthThenAZ)),", + "", + " byDescendingLengthThenAZ: arrayCopy(xs)", + " .sort(descLengthThenAZ),", + "", + " byPopulation: arrayCopy(rs)", + " .sort(on(compare, population)),", + "", + " byDescendingPopulation: arrayCopy(rs)", + " .sort(on(flip(compare), population))", + " });", + "})();", + "", + "{{Out}}", + "
    {",
    +        "  \"default\": [",
    +        "    \"Beijing\",",
    +        "    \"Delhi\",",
    +        "    \"Dhaka\",",
    +        "    \"Karachi\",",
    +        "    \"Lagos\",",
    +        "    \"Sao Paulo\",",
    +        "    \"Shanghai\"",
    +        "  ],",
    +        "  \"descendingDefault\": [",
    +        "    \"Shanghai\",",
    +        "    \"Sao Paulo\",",
    +        "    \"Lagos\",",
    +        "    \"Karachi\",",
    +        "    \"Dhaka\",",
    +        "    \"Delhi\",",
    +        "    \"Beijing\"",
    +        "  ],",
    +        "  \"byLengthThenAZ\": [",
    +        "    \"Delhi\",",
    +        "    \"Dhaka\",",
    +        "    \"Lagos\",",
    +        "    \"Beijing\",",
    +        "    \"Karachi\",",
    +        "    \"Shanghai\",",
    +        "    \"Sao Paulo\"",
    +        "  ],",
    +        "  \"byDescendingLengthThenZA\": [",
    +        "    \"Sao Paulo\",",
    +        "    \"Shanghai\",",
    +        "    \"Karachi\",",
    +        "    \"Beijing\",",
    +        "    \"Lagos\",",
    +        "    \"Dhaka\",",
    +        "    \"Delhi\"",
    +        "  ],",
    +        "  \"byDescendingLengthThenAZ\": [",
    +        "    \"Sao Paulo\",",
    +        "    \"Shanghai\",",
    +        "    \"Beijing\",",
    +        "    \"Karachi\",",
    +        "    \"Delhi\",",
    +        "    \"Dhaka\",",
    +        "    \"Lagos\"",
    +        "  ],",
    +        "  \"byPopulation\": [",
    +        "    {",
    +        "      \"name\": \"Lagos\",",
    +        "      \"pop\": 16.1",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Delhi\",",
    +        "      \"pop\": 16.8",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Dhaka\",",
    +        "      \"pop\": 17",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Beijing\",",
    +        "      \"pop\": 21.5",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Karachi\",",
    +        "      \"pop\": 23.5",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Shanghai\",",
    +        "      \"pop\": 24.2",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Sao Paulo\",",
    +        "      \"pop\": 24.2",
    +        "    }",
    +        "  ],",
    +        "  \"byDescendingPopulation\": [",
    +        "    {",
    +        "      \"name\": \"Shanghai\",",
    +        "      \"pop\": 24.2",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Sao Paulo\",",
    +        "      \"pop\": 24.2",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Karachi\",",
    +        "      \"pop\": 23.5",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Beijing\",",
    +        "      \"pop\": 21.5",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Dhaka\",",
    +        "      \"pop\": 17",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Delhi\",",
    +        "      \"pop\": 16.8",
    +        "    },",
    +        "    {",
    +        "      \"name\": \"Lagos\",",
    +        "      \"pop\": 16.1",
    +        "    }",
    +        "  ]",
    +        "}
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8016", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function lengthSorter(a, b) {\n var result = b.length - a.length;\n if (result == 0)\n result = a.localeCompare(b);\n return result;\n}\n\nvar test = [\"Here\", \"are\", \"some\", \"sample\", \"strings\", \"to\", \"be\", \"sorted\"];\ntest.sort(lengthSorter);\nalert( test.join(' ') ); // strings sample sorted Here some are be to\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Soundex", + "type": "Waypoint", + "description": [ + "

    Soundex is an algorithm for creating indices for words based on their pronunciation.

    ", + "Task:", + "

    The goal is for homophones to be encoded to the same representation so that they can be matched despite minor differences in spelling (from the WP article).

    ", + "Caution:", + "

    There is a major issue in many of the implementations concerning the separation of two consonants that have the same soundex code! According to the official Rules https://www.archives.gov/research/census/soundex.html. So check for instance if Ashcraft is coded to A-261.

    ", + "If a vowel (A, E, I, O, U) separates two consonants that have the same soundex code, the consonant to the right of the vowel is coded. Tymczak is coded as T-522 (T, 5 for the M, 2 for the C, Z ignored (see \"Side-by-Side\" rule above), 2 for the K). Since the vowel \"A\" separates the Z and K, the K is coded.", + "If \"H\" or \"W\" separate two consonants that have the same soundex code, the consonant to the right of the vowel is not coded. Example: Ashcraft is coded A-261 (A, 2 for the S, C ignored, 6 for the R, 1 for the F). It is not coded A-226." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "==== Version w/o RegExp ====", + "var soundex = function (s) {", + " var a = s.toLowerCase().split('')", + " f = a.shift(),", + " r = '',", + " codes = {", + " a: '', e: '', i: '', o: '', u: '',", + " b: 1, f: 1, p: 1, v: 1,", + " c: 2, g: 2, j: 2, k: 2, q: 2, s: 2, x: 2, z: 2,", + " d: 3, t: 3,", + " l: 4,", + " m: 5, n: 5,", + " r: 6", + " };", + " ", + " r = f +", + " a", + " .map(function (v, i, a) { return codes[v] })", + " .filter(function (v, i, a) { return ((i === 0) ? v !== codes[f] : v !== a[i - 1]); })", + " .join('');", + " ", + " return (r + '000').slice(0, 4).toUpperCase();", + "};", + "", + "var tests = {", + " \"Soundex\": \"S532\",", + " \"Example\": \"E251\",", + " \"Sownteks\": \"S532\",", + " \"Ekzampul\": \"E251\",", + " \"Euler\": \"E460\",", + " \"Gauss\": \"G200\",", + " \"Hilbert\": \"H416\",", + " \"Knuth\": \"K530\",", + " \"Lloyd\": \"L300\",", + " \"Lukasiewicz\": \"L222\",", + " \"Ellery\": \"E460\",", + " \"Ghosh\": \"G200\",", + " \"Heilbronn\": \"H416\",", + " \"Kant\": \"K530\",", + " \"Ladd\": \"L300\",", + " \"Lissajous\": \"L222\",", + " \"Wheaton\": \"W350\",", + " \"Ashcraft\": \"A226\",", + " \"Burroughs\": \"B622\",", + " \"Burrows\": \"B620\",", + " \"O'Hara\": \"O600\"", + " };", + "", + "for (var i in tests)", + " if (tests.hasOwnProperty(i)) {", + " console.log(", + " i +", + " ' \\t' +", + " tests[i] +", + " '\\t' +", + " soundex(i) +", + " '\\t' +", + " (soundex(i) === tests[i])", + " );", + "}", + "", + "// Soundex S532 S532 true", + "// Example E251 E251 true", + "// Sownteks S532 S532 true", + "// Ekzampul E251 E251 true", + "// Euler E460 E460 true", + "// Gauss G200 G200 true", + "// Hilbert H416 H416 true", + "// Knuth K530 K530 true", + "// Lloyd L300 L300 true", + "// Lukasiewicz L222 L222 true", + "// Ellery E460 E460 true", + "// Ghosh G200 G200 true", + "// Heilbronn H416 H416 true", + "// Kant K530 K530 true", + "// Ladd L300 L300 true", + "// Lissajous L222 L222 true", + "// Wheaton W350 W350 true", + "// Ashcraft A226 A226 true", + "// Burroughs B622 B622 true", + "// Burrows B620 B620 true", + "// O'Hara O600 O600 true", + "", + "", + "==== Extended version w/ RegExp ====", + "", + "Note: This version differs from the one above in the following way. According to U.S. National Archives Website, consecutive consonants which map to the same code are not condensed to a single occurrence of the code if they are separated by vowels, but separating W and H do not thus intervene. Therefore Ashcraft is coded A261 and Burroughs is coded B620 rather than A226 and B622", + "", + "", + "function soundex(t) {", + " t = t.toUpperCase().replace(/[^A-Z]/g, '');", + " return (t[0] || '0') + t.replace(/[HW]/g, '')", + " .replace(/[BFPV]/g, '1')", + " .replace(/[CGJKQSXZ]/g, '2')", + " .replace(/[DT]/g, '3')", + " .replace(/[L]/g, '4')", + " .replace(/[MN]/g, '5')", + " .replace(/[R]/g, '6')", + " .replace(/(.)\\1+/g, '$1')", + " .substr(1)", + " .replace(/[AEOIUHWY]/g, '')", + " .concat('000')", + " .substr(0, 3);", + "}", + "", + "// tests", + "[ [\"Example\", \"E251\"], [\"Sownteks\", \"S532\"], [\"Lloyd\", \"L300\"], [\"12346\", \"0000\"],", + " [\"4-H\", \"H000\"], [\"Ashcraft\", \"A261\"], [\"Ashcroft\", \"A261\"], [\"auerbach\", \"A612\"],", + " [\"bar\", \"B600\"], [\"barre\", \"B600\"], [\"Baragwanath\", \"B625\"], [\"Burroughs\", \"B620\"],", + " [\"Burrows\", \"B620\"], [\"C.I.A.\", \"C000\"], [\"coöp\", \"C100\"], [\"D-day\", \"D000\"],", + " [\"d jay\", \"D200\"], [\"de la Rosa\", \"D462\"], [\"Donnell\", \"D540\"], [\"Dracula\", \"D624\"],", + " [\"Drakula\", \"D624\"], [\"Du Pont\", \"D153\"], [\"Ekzampul\", \"E251\"], [\"example\", \"E251\"],", + " [\"Ellery\", \"E460\"], [\"Euler\", \"E460\"], [\"F.B.I.\", \"F000\"], [\"Gauss\", \"G200\"],", + " [\"Ghosh\", \"G200\"], [\"Gutierrez\", \"G362\"], [\"he\", \"H000\"], [\"Heilbronn\", \"H416\"],", + " [\"Hilbert\", \"H416\"], [\"Jackson\", \"J250\"], [\"Johnny\", \"J500\"], [\"Jonny\", \"J500\"],", + " [\"Kant\", \"K530\"], [\"Knuth\", \"K530\"], [\"Ladd\", \"L300\"], [\"Lloyd\", \"L300\"],", + " [\"Lee\", \"L000\"], [\"Lissajous\", \"L222\"], [\"Lukasiewicz\", \"L222\"], [\"naïve\", \"N100\"],", + " [\"Miller\", \"M460\"], [\"Moses\", \"M220\"], [\"Moskowitz\", \"M232\"], [\"Moskovitz\", \"M213\"],", + " [\"O'Conner\", \"O256\"], [\"O'Connor\", \"O256\"], [\"O'Hara\", \"O600\"], [\"O'Mally\", \"O540\"],", + " [\"Peters\", \"P362\"], [\"Peterson\", \"P362\"], [\"Pfister\", \"P236\"], [\"R2-D2\", \"R300\"],", + " [\"rÄ≈sumÅ∙\", \"R250\"], [\"Robert\", \"R163\"], [\"Rupert\", \"R163\"], [\"Rubin\", \"R150\"],", + " [\"Soundex\", \"S532\"], [\"sownteks\", \"S532\"], [\"Swhgler\", \"S460\"], [\"'til\", \"T400\"],", + " [\"Tymczak\", \"T522\"], [\"Uhrbach\", \"U612\"], [\"Van de Graaff\", \"V532\"],", + " [\"VanDeusen\", \"V532\"], [\"Washington\", \"W252\"], [\"Wheaton\", \"W350\"],", + " [\"Williams\", \"W452\"], [\"Woolcock\", \"W422\"]", + "].forEach(function(v) {", + " var a = v[0], t = v[1], d = soundex(a);", + " if (d !== t) {", + " console.log('soundex(\"' + a + '\") was ' + d + ' should be ' + t);", + " }", + "}); ", + "", + "===ES6===", + "", + "Allowing for both Simple Soundex (first example above) and NARA Soundex (second example above)", + "(Reusing set of tests from second contribution)", + "", + "(() => {", + " 'use strict';", + "", + " // Simple Soundex or NARA Soundex (if blnNara = true)", + "", + " // soundex :: Bool -> String -> String", + " const soundex = (blnNara, name) => {", + "", + " // code :: Char -> Char", + " const code = c => ['AEIOU', 'BFPV', 'CGJKQSXZ', 'DT', 'L', 'MN', 'R', 'HW']", + " .reduce((a, x, i) =>", + " a ? a : (x.indexOf(c) !== -1 ? i.toString() : a), '');", + "", + " // isAlpha :: Char -> Boolean", + " const isAlpha = c => {", + " const d = c.charCodeAt(0);", + " return d > 64 && d < 91;", + " };", + "", + " const s = name.toUpperCase()", + " .split('')", + " .filter(isAlpha);", + "", + " return (s[0] || '0') +", + " s.map(code)", + " .join('')", + " .replace(/7/g, blnNara ? '' : '7')", + " .replace(/(.)\\1+/g, '$1')", + " .substr(1)", + " .replace(/[07]/g, '')", + " .concat('000')", + " .substr(0, 3);", + " };", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " const curry = f => a => b => f(a, b),", + " [simpleSoundex, naraSoundex] = [false, true]", + " .map(bln => curry(soundex)(bln));", + "", + " // TEST", + " return [", + " [\"Example\", \"E251\"],", + " [\"Sownteks\", \"S532\"],", + " [\"Lloyd\", \"L300\"],", + " [\"12346\", \"0000\"],", + " [\"4-H\", \"H000\"],", + " [\"Ashcraft\", \"A261\"],", + " [\"Ashcroft\", \"A261\"],", + " [\"auerbach\", \"A612\"],", + " [\"bar\", \"B600\"],", + " [\"barre\", \"B600\"],", + " [\"Baragwanath\", \"B625\"],", + " [\"Burroughs\", \"B620\"],", + " [\"Burrows\", \"B620\"],", + " [\"C.I.A.\", \"C000\"],", + " [\"coöp\", \"C100\"],", + " [\"D-day\", \"D000\"],", + " [\"d jay\", \"D200\"],", + " [\"de la Rosa\", \"D462\"],", + " [\"Donnell\", \"D540\"],", + " [\"Dracula\", \"D624\"],", + " [\"Drakula\", \"D624\"],", + " [\"Du Pont\", \"D153\"],", + " [\"Ekzampul\", \"E251\"],", + " [\"example\", \"E251\"],", + " [\"Ellery\", \"E460\"],", + " [\"Euler\", \"E460\"],", + " [\"F.B.I.\", \"F000\"],", + " [\"Gauss\", \"G200\"],", + " [\"Ghosh\", \"G200\"],", + " [\"Gutierrez\", \"G362\"],", + " [\"he\", \"H000\"],", + " [\"Heilbronn\", \"H416\"],", + " [\"Hilbert\", \"H416\"],", + " [\"Jackson\", \"J250\"],", + " [\"Johnny\", \"J500\"],", + " [\"Jonny\", \"J500\"],", + " [\"Kant\", \"K530\"],", + " [\"Knuth\", \"K530\"],", + " [\"Ladd\", \"L300\"],", + " [\"Lloyd\", \"L300\"],", + " [\"Lee\", \"L000\"],", + " [\"Lissajous\", \"L222\"],", + " [\"Lukasiewicz\", \"L222\"],", + " [\"naïve\", \"N100\"],", + " [\"Miller\", \"M460\"],", + " [\"Moses\", \"M220\"],", + " [\"Moskowitz\", \"M232\"],", + " [\"Moskovitz\", \"M213\"],", + " [\"O'Conner\", \"O256\"],", + " [\"O'Connor\", \"O256\"],", + " [\"O'Hara\", \"O600\"],", + " [\"O'Mally\", \"O540\"],", + " [\"Peters\", \"P362\"],", + " [\"Peterson\", \"P362\"],", + " [\"Pfister\", \"P236\"],", + " [\"R2-D2\", \"R300\"],", + " [\"rÄ≈sumÅ∙\", \"R250\"],", + " [\"Robert\", \"R163\"],", + " [\"Rupert\", \"R163\"],", + " [\"Rubin\", \"R150\"],", + " [\"Soundex\", \"S532\"],", + " [\"sownteks\", \"S532\"],", + " [\"Swhgler\", \"S460\"],", + " [\"'til\", \"T400\"],", + " [\"Tymczak\", \"T522\"],", + " [\"Uhrbach\", \"U612\"],", + " [\"Van de Graaff\", \"V532\"],", + " [\"VanDeusen\", \"V532\"],", + " [\"Washington\", \"W252\"],", + " [\"Wheaton\", \"W350\"],", + " [\"Williams\", \"W452\"],", + " [\"Woolcock\", \"W422\"]", + " ].reduce((a, [name, naraCode]) => {", + " const naraTest = naraSoundex(name),", + " simpleTest = simpleSoundex(name);", + "", + " const logNara = naraTest !== naraCode ? (", + " `${name} was ${naraTest} should be ${naraCode}`", + " ) : '',", + " logDelta = (naraTest !== simpleTest ? (", + " `${name} -> NARA: ${naraTest} vs Simple: ${simpleTest}`", + " ) : '');", + "", + " return logNara.length || logDelta.length ? (", + " a + [logNara, logDelta].join('\\n')", + " ) : a;", + " }, '');", + "})();", + "", + "{{Out}}", + "
    Ashcraft -> NARA: A261 vs Simple: A226",
    +        "Ashcroft -> NARA: A261 vs Simple: A226",
    +        "Burroughs -> NARA: B620 vs Simple: B622",
    +        "Swhgler -> NARA: S460 vs Simple: S246
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8017", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var soundex = function (s) {\n var a = s.toLowerCase().split('')\n f = a.shift(),\n r = '',\n codes = {\n a: '', e: '', i: '', o: '', u: '',\n b: 1, f: 1, p: 1, v: 1,\n c: 2, g: 2, j: 2, k: 2, q: 2, s: 2, x: 2, z: 2,\n d: 3, t: 3,\n l: 4,\n m: 5, n: 5,\n r: 6\n };\n \n r = f +\n a\n .map(function (v, i, a) { return codes[v] })\n .filter(function (v, i, a) { return ((i === 0) ? v !== codes[f] : v !== a[i - 1]); })\n .join('');\n \n return (r + '000').slice(0, 4).toUpperCase();\n};\n\nvar tests = {\n \"Soundex\": \"S532\",\n \"Example\": \"E251\",\n \"Sownteks\": \"S532\",\n \"Ekzampul\": \"E251\",\n \"Euler\": \"E460\",\n \"Gauss\": \"G200\",\n \"Hilbert\": \"H416\",\n \"Knuth\": \"K530\",\n \"Lloyd\": \"L300\",\n \"Lukasiewicz\": \"L222\",\n \"Ellery\": \"E460\",\n \"Ghosh\": \"G200\",\n \"Heilbronn\": \"H416\",\n \"Kant\": \"K530\",\n \"Ladd\": \"L300\",\n \"Lissajous\": \"L222\",\n \"Wheaton\": \"W350\",\n \"Ashcraft\": \"A226\",\n \"Burroughs\": \"B622\",\n \"Burrows\": \"B620\",\n \"O'Hara\": \"O600\"\n };\n\nfor (var i in tests)\n if (tests.hasOwnProperty(i)) {\n console.log(\n i +\n ' \\t' +\n tests[i] +\n '\\t' +\n soundex(i) +\n '\\t' +\n (soundex(i) === tests[i])\n );\n}\n\n// Soundex S532 S532 true\n// Example E251 E251 true\n// Sownteks S532 S532 true\n// Ekzampul E251 E251 true\n// Euler E460 E460 true\n// Gauss G200 G200 true\n// Hilbert H416 H416 true\n// Knuth K530 K530 true\n// Lloyd L300 L300 true\n// Lukasiewicz L222 L222 true\n// Ellery E460 E460 true\n// Ghosh G200 G200 true\n// Heilbronn H416 H416 true\n// Kant K530 K530 true\n// Ladd L300 L300 true\n// Lissajous L222 L222 true\n// Wheaton W350 W350 true\n// Ashcraft A226 A226 true\n// Burroughs B622 B622 true\n// Burrows B620 B620 true\n// O'Hara O600 O600 true\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Spiral matrix", + "type": "Waypoint", + "description": [ + "Task:", + "

    Produce a spiral array.

    ", + "

    A spiral array is a square arrangement of the first N2 natural numbers, where the

    ", + "numbers increase sequentially as you go around the edges of the array spiraling inwards.", + "

    For example, given 5, produce this array:

    ", + "
    ",
    +        " 0  1  2  3  4",
    +        "15 16 17 18  5",
    +        "14 23 24 19  6",
    +        "13 22 21 20  7",
    +        "12 11 10  9  8",
    +        "
    ", + "Related tasks:", + " Zig-zag matrix ", + " Identity_matrix", + " Ulam_spiral_(for_primes)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Imperative===", + "", + "spiralArray = function (edge) {", + " var arr = Array(edge),", + " x = 0, y = edge,", + " total = edge * edge--,", + " dx = 1, dy = 0,", + " i = 0, j = 0;", + " while (y) arr[--y] = [];", + " while (i < total) {", + " arr[y][x] = i++;", + " x += dx; y += dy;", + " if (++j == edge) {", + " if (dy < 0) {x++; y++; edge -= 2}", + " j = dx; dx = -dy; dy = j; j = 0;", + " }", + " }", + " return arr;", + "}", + "", + "// T E S T:", + "arr = spiralArray(edge = 5);", + "for (y= 0; y < edge; y++) console.log(arr[y].join(\" \"));", + "", + "{{out}}", + "
    ",
    +        "0 1 2 3 4",
    +        "15 16 17 18 5",
    +        "14 23 24 19 6",
    +        "13 22 21 20 7",
    +        "12 11 10 9 8
    ", + "", + "===Functional===", + "", + "====ES5====", + "", + "Translating one of the Haskell versions:", + "", + "(function (n) {", + "", + " // Spiral: the first row plus a smaller spiral rotated 90 degrees clockwise", + " function spiral(lngRows, lngCols, nStart) {", + " return lngRows ? [range(nStart, (nStart + lngCols) - 1)].concat(", + " transpose(", + " spiral(lngCols, lngRows - 1, nStart + lngCols)", + " ).map(reverse)", + " ) : [", + " []", + " ];", + " }", + "", + " // rows and columns transposed (for 90 degree rotation)", + " function transpose(lst) {", + " return lst.length > 1 ? lst[0].map(function (_, col) {", + " return lst.map(function (row) {", + " return row[col];", + " });", + " }) : lst;", + " }", + "", + " // elements in reverse order (for 90 degree rotation)", + " function reverse(lst) {", + " return lst.length > 1 ? lst.reduceRight(function (acc, x) {", + " return acc.concat(x);", + " }, []) : lst;", + " }", + "", + " // [m..n]", + " function range(m, n) {", + " return Array.apply(null, Array(n - m + 1)).map(function (x, i) {", + " return m + i;", + " });", + " }", + "", + " // TESTING", + " ", + " var lstSpiral = spiral(n, n, 0);", + "", + "", + " // OUTPUT FORMATTING - JSON and wikiTable", + " function wikiTable(lstRows, blnHeaderRow, strStyle) {", + " return '{| class=\"wikitable\" ' + (", + " strStyle ? 'style=\"' + strStyle + '\"' : ''", + " ) + lstRows.map(function (lstRow, iRow) {", + " var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|');", + "", + " return '\\n|-\\n' + strDelim + ' ' + lstRow.map(function (v) {", + " return typeof v === 'undefined' ? ' ' : v;", + " }).join(' ' + strDelim + strDelim + ' ');", + " }).join('') + '\\n|}';", + " }", + "", + " return [", + " wikiTable(", + "", + " lstSpiral,", + "", + " false,", + " 'text-align:center;width:12em;height:12em;table-layout:fixed;'", + " ),", + " ", + " JSON.stringify(lstSpiral)", + " ].join('\\n\\n');", + "", + "})(5);", + "", + "Output:", + "", + "{| class=\"wikitable\" style=\"text-align:center;width:12em;height:12em;table-layout:fixed;\"", + "|-", + "| 0 || 1 || 2 || 3 || 4", + "|-", + "| 15 || 16 || 17 || 18 || 5", + "|-", + "| 14 || 23 || 24 || 19 || 6", + "|-", + "| 13 || 22 || 21 || 20 || 7", + "|-", + "| 12 || 11 || 10 || 9 || 8", + "|}", + "", + "[[0,1,2,3,4],[15,16,17,18,5],[14,23,24,19,6],[13,22,21,20,7],[12,11,10,9,8]]", + "", + "", + "====ES6====", + "", + "(n => {", + "", + " // spiral :: the first row plus a smaller spiral rotated 90 degrees clockwise", + " // spiral :: Int -> Int -> Int -> [[Int]]", + " function spiral(lngRows, lngCols, nStart) {", + " return lngRows ? [range(nStart, (nStart + lngCols) - 1)]", + " .concat(", + " transpose(", + " spiral(lngCols, lngRows - 1, nStart + lngCols)", + " )", + " .map(reverse)", + " ) : [[]];", + " }", + "", + " // transpose :: [[a]] -> [[a]]", + " function transpose(xs) {", + " return xs[0]", + " .map((_, iCol) => xs", + " .map((row) => row[iCol]));", + " }", + "", + " // reverse :: [a] -> [a]", + " function reverse(xs) {", + " return xs.slice(0)", + " .reverse();", + " }", + "", + " // range(intFrom, intTo, optional intStep)", + " // Int -> Int -> Maybe Int -> [Int]", + " function range(m, n, step) {", + " let d = (step || 1) * (n >= m ? 1 : -1);", + "", + " return Array.from({", + " length: Math.floor((n - m) / d) + 1", + " }, (_, i) => m + (i * d));", + " }", + "", + "", + "", + " // TESTING", + "", + " // replicate :: Int -> String -> String", + " function replicate(n, a) {", + " var v = [a],", + " o = '';", + "", + " if (n < 1) return o;", + " while (n > 1) {", + " if (n & 1) o = o + v;", + " n >>= 1;", + " v = v + v;", + " }", + " return o + v;", + " }", + "", + "", + " return spiral(n, n, 0)", + " .map(", + " xs => xs.map(x => {", + " let s = `${x}`;", + " return replicate(4 - s.length, ' ') + s;", + " })", + " .join('')", + " )", + " .join('\\n');", + "", + "})(5);", + "", + "", + "
     0   1   2   3   4",
    +        "15  16  17  18   5",
    +        "14  23  24  19   6",
    +        "13  22  21  20   7",
    +        "12  11  10   9   8
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc801c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "spiralArray = function (edge) {\n var arr = Array(edge),\n x = 0, y = edge,\n total = edge * edge--,\n dx = 1, dy = 0,\n i = 0, j = 0;\n while (y) arr[--y] = [];\n while (i < total) {\n arr[y][x] = i++;\n x += dx; y += dy;\n if (++j == edge) {\n if (dy < 0) {x++; y++; edge -= 2}\n j = dx; dx = -dy; dy = j; j = 0;\n }\n }\n return arr;\n}\n\n// T E S T:\narr = spiralArray(edge = 5);\nfor (y= 0; y < edge; y++) console.log(arr[y].join(\" \"));\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Split a character string based on change of character", + "type": "Waypoint", + "description": [ + "

    ", + "

    Task:", + "

    Split a (character) string into comma (plus a blank) delimited

    ", + "

    strings based on a change of character (left to right).

    Show the output here (use the 1st example below).

    ", + "

    Blanks should be treated as any other character (except

    ", + "

    they are problematic to display clearly). The same applies

    ", + "

    to commas.

    ", + "

    For instance, the string:

    ", + "

    gHHH5YY++///\\

    ", + "

    should be split and show:

    ", + "

    g, HHH, 5, YY, ++, ///, \\

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES6===", + "{{Trans|Haskell}}", + "(() => {", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // concat :: [[a]] -> [a] | [String] -> String", + " const concat = xs =>", + " xs.length > 0 ? (() => {", + " const unit = typeof xs[0] === 'string' ? '' : [];", + " return unit.concat.apply(unit, xs);", + " })() : [];", + "", + " // group :: Eq a => [a] -> [[a]]", + " const group = xs => groupBy((a, b) => a === b, xs);", + "", + " // groupBy :: (a -> a -> Bool) -> [a] -> [[a]]", + " const groupBy = (f, xs) => {", + " const dct = xs.slice(1)", + " .reduce((a, x) => {", + " const", + " h = a.active.length > 0 ? a.active[0] : undefined,", + " blnGroup = h !== undefined && f(h, x);", + " return {", + " active: blnGroup ? a.active.concat([x]) : [x],", + " sofar: blnGroup ? a.sofar : a.sofar.concat([a.active])", + " };", + " }, {", + " active: xs.length > 0 ? [xs[0]] : [],", + " sofar: []", + " });", + " return dct.sofar.concat(dct.active.length > 0 ? [dct.active] : []);", + " };", + "", + " // intercalate :: String -> [a] -> String", + " const intercalate = (s, xs) => xs.join(s);", + "", + " // map :: (a -> b) -> [a] -> [b]", + " const map = (f, xs) => xs.map(f);", + "", + " // show :: a -> String", + " const show = (...x) =>", + " JSON.stringify.apply(", + " null, x.length > 1 ? [x[0], null, x[1]] : x", + " );", + "", + " // stringChars :: String -> [Char]", + " const stringChars = s => s.split('');", + "", + "", + " // TEST -------------------------------------------------------------------", + " return show(", + " intercalate(', ',", + " map(concat, group(stringChars('gHHH5YY++///\\\\')))", + " )", + " );", + "", + " // -> \"g, HHH, 5, YY, ++, ///, \\\\\"", + "})();", + "{{Out}}", + "
    g, HHH, 5, YY, ++, ///, \\
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc801d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n // GENERIC FUNCTIONS ------------------------------------------------------\n\n // concat :: [[a]] -> [a] | [String] -> String\n const concat = xs =>\n xs.length > 0 ? (() => {\n const unit = typeof xs[0] === 'string' ? '' : [];\n return unit.concat.apply(unit, xs);\n })() : [];\n\n // group :: Eq a => [a] -> [[a]]\n const group = xs => groupBy((a, b) => a === b, xs);\n\n // groupBy :: (a -> a -> Bool) -> [a] -> [[a]]\n const groupBy = (f, xs) => {\n const dct = xs.slice(1)\n .reduce((a, x) => {\n const\n h = a.active.length > 0 ? a.active[0] : undefined,\n blnGroup = h !== undefined && f(h, x);\n return {\n active: blnGroup ? a.active.concat([x]) : [x],\n sofar: blnGroup ? a.sofar : a.sofar.concat([a.active])\n };\n }, {\n active: xs.length > 0 ? [xs[0]] : [],\n sofar: []\n });\n return dct.sofar.concat(dct.active.length > 0 ? [dct.active] : []);\n };\n\n // intercalate :: String -> [a] -> String\n const intercalate = (s, xs) => xs.join(s);\n\n // map :: (a -> b) -> [a] -> [b]\n const map = (f, xs) => xs.map(f);\n\n // show :: a -> String\n const show = (...x) =>\n JSON.stringify.apply(\n null, x.length > 1 ? [x[0], null, x[1]] : x\n );\n\n // stringChars :: String -> [Char]\n const stringChars = s => s.split('');\n\n\n // TEST -------------------------------------------------------------------\n return show(\n intercalate(', ',\n map(concat, group(stringChars('gHHH5YY++///\\\\')))\n )\n );\n\n // -> \"g, HHH, 5, YY, ++, ///, \\\\\"\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Stable marriage problem", + "type": "Waypoint", + "description": [ + "

    Solve the Stable marriage problem using the Gale/Shapley algorithm.

    ", + "

    Problem description

    ", + "

    Given an equal number of men and women to be paired for marriage, each man ranks all the women in order of his preference and each woman ranks all the men in order of her preference.

    A stable set of engagements for marriage is one where no man prefers a woman over the one he is engaged to, where that other woman also prefers that man over the one she is engaged to. I.e. with consulting marriages, there would be no reason for the engagements between the people to change.

    Gale and Shapley proved that there is a stable set of engagements for any set of preferences and the first link above gives their algorithm for finding a set of stable engagements.

    ", + "

    Task Specifics

    ", + "

    Given ten males:

    ", + "

    abe, bob, col, dan, ed, fred, gav, hal, ian, jon

    ", + "

    And ten females:

    ", + "

    abi, bea, cath, dee, eve, fay, gay, hope, ivy, jan

    And a complete list of ranked preferences, where the most liked is to the left:

    ", + "

    abe: abi, eve, cath, ivy, jan, dee, fay, bea, hope, gay

    ", + "

    bob: cath, hope, abi, dee, eve, fay, bea, jan, ivy, gay

    ", + "

    col: hope, eve, abi, dee, bea, fay, ivy, gay, cath, jan

    ", + "

    dan: ivy, fay, dee, gay, hope, eve, jan, bea, cath, abi

    ", + "

    ed: jan, dee, bea, cath, fay, eve, abi, ivy, hope, gay

    ", + "

    fred: bea, abi, dee, gay, eve, ivy, cath, jan, hope, fay

    ", + "

    gav: gay, eve, ivy, bea, cath, abi, dee, hope, jan, fay

    ", + "

    hal: abi, eve, hope, fay, ivy, cath, jan, bea, gay, dee

    ", + "

    ian: hope, cath, dee, gay, bea, abi, fay, ivy, jan, eve

    ", + "

    jon: abi, fay, jan, gay, eve, bea, dee, cath, ivy, hope

    abi: bob, fred, jon, gav, ian, abe, dan, ed, col, hal

    ", + "

    bea: bob, abe, col, fred, gav, dan, ian, ed, jon, hal

    ", + "

    cath: fred, bob, ed, gav, hal, col, ian, abe, dan, jon

    ", + "

    dee: fred, jon, col, abe, ian, hal, gav, dan, bob, ed

    ", + "

    eve: jon, hal, fred, dan, abe, gav, col, ed, ian, bob

    ", + "

    fay: bob, abe, ed, ian, jon, dan, fred, gav, col, hal

    ", + "

    gay: jon, gav, hal, fred, bob, abe, col, ed, dan, ian

    ", + "

    hope: gav, jon, bob, abe, ian, dan, hal, ed, col, fred

    ", + "

    ivy: ian, col, hal, gav, fred, bob, abe, ed, jon, dan

    ", + "

    jan: ed, hal, gav, abe, bob, jon, col, ian, fred, dan

    Use the Gale Shapley algorithm to find a stable set of engagements", + "Perturb this set of engagements to form an unstable set of engagements then check this new set for stability.

    References

    ", + " The Stable Marriage Problem. (Eloquent description and background information).", + "Gale-Shapley Algorithm Demonstration.", + "Another Gale-Shapley Algorithm Demonstration.", + "Stable Marriage Problem - Numberphile (Video).", + "Stable Marriage Problem (the math bit) (Video).", + "The Stable Marriage Problem and School Choice. (Excellent exposition)" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function Person(name) {", + "", + " var candidateIndex = 0;", + "", + " this.name = name;", + " this.fiance = null;", + " this.candidates = [];", + "", + " this.rank = function(p) {", + " for (i = 0; i < this.candidates.length; i++)", + " if (this.candidates[i] === p) return i;", + " return this.candidates.length + 1;", + " }", + "", + " this.prefers = function(p) {", + " return this.rank(p) < this.rank(this.fiance);", + " }", + "", + " this.nextCandidate = function() {", + " if (candidateIndex >= this.candidates.length) return null;", + " return this.candidates[candidateIndex++];", + " }", + "", + " this.engageTo = function(p) {", + " if (p.fiance) p.fiance.fiance = null;", + " p.fiance = this;", + " if (this.fiance) this.fiance.fiance = null;", + " this.fiance = p;", + " }", + "", + " this.swapWith = function(p) {", + " console.log(\"%s & %s swap partners\", this.name, p.name);", + " var thisFiance = this.fiance;", + " var pFiance = p.fiance;", + " this.engageTo(pFiance);", + " p.engageTo(thisFiance);", + " }", + "}", + "", + "function isStable(guys, gals) {", + " for (var i = 0; i < guys.length; i++)", + " for (var j = 0; j < gals.length; j++)", + " if (guys[i].prefers(gals[j]) && gals[j].prefers(guys[i]))", + " return false;", + " return true;", + "}", + "", + "function engageEveryone(guys) {", + " var done;", + " do {", + " done = true;", + " for (var i = 0; i < guys.length; i++) {", + " var guy = guys[i];", + " if (!guy.fiance) {", + " done = false;", + " var gal = guy.nextCandidate();", + " if (!gal.fiance || gal.prefers(guy))", + " guy.engageTo(gal);", + " }", + " }", + " } while (!done);", + "}", + "", + "function doMarriage() {", + "", + " var abe = new Person(\"Abe\");", + " var bob = new Person(\"Bob\");", + " var col = new Person(\"Col\");", + " var dan = new Person(\"Dan\");", + " var ed = new Person(\"Ed\");", + " var fred = new Person(\"Fred\");", + " var gav = new Person(\"Gav\");", + " var hal = new Person(\"Hal\");", + " var ian = new Person(\"Ian\");", + " var jon = new Person(\"Jon\");", + " var abi = new Person(\"Abi\");", + " var bea = new Person(\"Bea\");", + " var cath = new Person(\"Cath\");", + " var dee = new Person(\"Dee\");", + " var eve = new Person(\"Eve\");", + " var fay = new Person(\"Fay\");", + " var gay = new Person(\"Gay\");", + " var hope = new Person(\"Hope\");", + " var ivy = new Person(\"Ivy\");", + " var jan = new Person(\"Jan\");", + "", + " abe.candidates = [abi, eve, cath, ivy, jan, dee, fay, bea, hope, gay];", + " bob.candidates = [cath, hope, abi, dee, eve, fay, bea, jan, ivy, gay];", + " col.candidates = [hope, eve, abi, dee, bea, fay, ivy, gay, cath, jan];", + " dan.candidates = [ivy, fay, dee, gay, hope, eve, jan, bea, cath, abi];", + " ed.candidates = [jan, dee, bea, cath, fay, eve, abi, ivy, hope, gay];", + " fred.candidates = [bea, abi, dee, gay, eve, ivy, cath, jan, hope, fay];", + " gav.candidates = [gay, eve, ivy, bea, cath, abi, dee, hope, jan, fay];", + " hal.candidates = [abi, eve, hope, fay, ivy, cath, jan, bea, gay, dee];", + " ian.candidates = [hope, cath, dee, gay, bea, abi, fay, ivy, jan, eve];", + " jon.candidates = [abi, fay, jan, gay, eve, bea, dee, cath, ivy, hope];", + " abi.candidates = [bob, fred, jon, gav, ian, abe, dan, ed, col, hal];", + " bea.candidates = [bob, abe, col, fred, gav, dan, ian, ed, jon, hal];", + " cath.candidates = [fred, bob, ed, gav, hal, col, ian, abe, dan, jon];", + " dee.candidates = [fred, jon, col, abe, ian, hal, gav, dan, bob, ed];", + " eve.candidates = [jon, hal, fred, dan, abe, gav, col, ed, ian, bob];", + " fay.candidates = [bob, abe, ed, ian, jon, dan, fred, gav, col, hal];", + " gay.candidates = [jon, gav, hal, fred, bob, abe, col, ed, dan, ian];", + " hope.candidates = [gav, jon, bob, abe, ian, dan, hal, ed, col, fred];", + " ivy.candidates = [ian, col, hal, gav, fred, bob, abe, ed, jon, dan];", + " jan.candidates = [ed, hal, gav, abe, bob, jon, col, ian, fred, dan];", + "", + " var guys = [abe, bob, col, dan, ed, fred, gav, hal, ian, jon];", + " var gals = [abi, bea, cath, dee, eve, fay, gay, hope, ivy, jan];", + "", + " engageEveryone(guys);", + "", + " for (var i = 0; i < guys.length; i++) {", + " console.log(\"%s is engaged to %s\", guys[i].name, guys[i].fiance.name);", + " }", + " console.log(\"Stable = %s\", isStable(guys, gals) ? \"Yes\" : \"No\");", + " jon.swapWith(fred);", + " console.log(\"Stable = %s\", isStable(guys, gals) ? \"Yes\" : \"No\");", + "}", + "", + "doMarriage();", + "", + "", + "{{out}}", + "
    Abe is engaged to Ivy",
    +        "Bob is engaged to Cath",
    +        "Col is engaged to Dee",
    +        "Dan is engaged to Fay",
    +        "Ed is engaged to Jan",
    +        "Fred is engaged to Bea",
    +        "Gav is engaged to Gay",
    +        "Hal is engaged to Eve",
    +        "Ian is engaged to Hope",
    +        "Jon is engaged to Abi",
    +        "Stable = Yes",
    +        "Jon & Fred swap partners",
    +        "Stable = No
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc801f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function Person(name) {\n\n var candidateIndex = 0;\n\n this.name = name;\n this.fiance = null;\n this.candidates = [];\n\n this.rank = function(p) {\n for (i = 0; i < this.candidates.length; i++)\n if (this.candidates[i] === p) return i;\n return this.candidates.length + 1;\n }\n\n this.prefers = function(p) {\n return this.rank(p) < this.rank(this.fiance);\n }\n\n this.nextCandidate = function() {\n if (candidateIndex >= this.candidates.length) return null;\n return this.candidates[candidateIndex++];\n }\n\n this.engageTo = function(p) {\n if (p.fiance) p.fiance.fiance = null;\n p.fiance = this;\n if (this.fiance) this.fiance.fiance = null;\n this.fiance = p;\n }\n\n this.swapWith = function(p) {\n console.log(\"%s & %s swap partners\", this.name, p.name);\n var thisFiance = this.fiance;\n var pFiance = p.fiance;\n this.engageTo(pFiance);\n p.engageTo(thisFiance);\n }\n}\n\nfunction isStable(guys, gals) {\n for (var i = 0; i < guys.length; i++)\n for (var j = 0; j < gals.length; j++)\n if (guys[i].prefers(gals[j]) && gals[j].prefers(guys[i]))\n return false;\n return true;\n}\n\nfunction engageEveryone(guys) {\n var done;\n do {\n done = true;\n for (var i = 0; i < guys.length; i++) {\n var guy = guys[i];\n if (!guy.fiance) {\n done = false;\n var gal = guy.nextCandidate();\n if (!gal.fiance || gal.prefers(guy))\n guy.engageTo(gal);\n }\n }\n } while (!done);\n}\n\nfunction doMarriage() {\n\n var abe = new Person(\"Abe\");\n var bob = new Person(\"Bob\");\n var col = new Person(\"Col\");\n var dan = new Person(\"Dan\");\n var ed = new Person(\"Ed\");\n var fred = new Person(\"Fred\");\n var gav = new Person(\"Gav\");\n var hal = new Person(\"Hal\");\n var ian = new Person(\"Ian\");\n var jon = new Person(\"Jon\");\n var abi = new Person(\"Abi\");\n var bea = new Person(\"Bea\");\n var cath = new Person(\"Cath\");\n var dee = new Person(\"Dee\");\n var eve = new Person(\"Eve\");\n var fay = new Person(\"Fay\");\n var gay = new Person(\"Gay\");\n var hope = new Person(\"Hope\");\n var ivy = new Person(\"Ivy\");\n var jan = new Person(\"Jan\");\n\n abe.candidates = [abi, eve, cath, ivy, jan, dee, fay, bea, hope, gay];\n bob.candidates = [cath, hope, abi, dee, eve, fay, bea, jan, ivy, gay];\n col.candidates = [hope, eve, abi, dee, bea, fay, ivy, gay, cath, jan];\n dan.candidates = [ivy, fay, dee, gay, hope, eve, jan, bea, cath, abi];\n ed.candidates = [jan, dee, bea, cath, fay, eve, abi, ivy, hope, gay];\n fred.candidates = [bea, abi, dee, gay, eve, ivy, cath, jan, hope, fay];\n gav.candidates = [gay, eve, ivy, bea, cath, abi, dee, hope, jan, fay];\n hal.candidates = [abi, eve, hope, fay, ivy, cath, jan, bea, gay, dee];\n ian.candidates = [hope, cath, dee, gay, bea, abi, fay, ivy, jan, eve];\n jon.candidates = [abi, fay, jan, gay, eve, bea, dee, cath, ivy, hope];\n abi.candidates = [bob, fred, jon, gav, ian, abe, dan, ed, col, hal];\n bea.candidates = [bob, abe, col, fred, gav, dan, ian, ed, jon, hal];\n cath.candidates = [fred, bob, ed, gav, hal, col, ian, abe, dan, jon];\n dee.candidates = [fred, jon, col, abe, ian, hal, gav, dan, bob, ed];\n eve.candidates = [jon, hal, fred, dan, abe, gav, col, ed, ian, bob];\n fay.candidates = [bob, abe, ed, ian, jon, dan, fred, gav, col, hal];\n gay.candidates = [jon, gav, hal, fred, bob, abe, col, ed, dan, ian];\n hope.candidates = [gav, jon, bob, abe, ian, dan, hal, ed, col, fred];\n ivy.candidates = [ian, col, hal, gav, fred, bob, abe, ed, jon, dan];\n jan.candidates = [ed, hal, gav, abe, bob, jon, col, ian, fred, dan];\n\n var guys = [abe, bob, col, dan, ed, fred, gav, hal, ian, jon];\n var gals = [abi, bea, cath, dee, eve, fay, gay, hope, ivy, jan];\n\n engageEveryone(guys);\n\n for (var i = 0; i < guys.length; i++) {\n console.log(\"%s is engaged to %s\", guys[i].name, guys[i].fiance.name);\n }\n console.log(\"Stable = %s\", isStable(guys, gals) ? \"Yes\" : \"No\");\n jon.swapWith(fred);\n console.log(\"Stable = %s\", isStable(guys, gals) ? \"Yes\" : \"No\");\n}\n\ndoMarriage();\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Stack", + "type": "Waypoint", + "description": [ + "

    A stack is a container of elements with last in, first out access policy. Sometimes it also called LIFO.

    The stack is accessed through its top.

    The basic stack operations are:

    push stores a new element onto the stack top;", + " pop returns the last pushed stack element, while removing it from the stack;", + " empty tests if the stack contains no elements.", + "

    Sometimes the last pushed stack element is made accessible for immutable access (for read) or mutable access (for write):

    top (sometimes called peek to keep with the p theme) returns the topmost element without modifying the stack.", + "

    Stacks allow a very simple hardware implementation.

    They are common in almost all processors.

    In programming, stacks are also very popular for their way (LIFO) of resource management, usually memory.

    Nested scopes of language objects are naturally implemented by a stack (sometimes by multiple stacks).

    This is a classical way to implement local variables of a re-entrant or recursive subprogram. Stacks are also used to describe a formal computational framework.

    See stack machine.

    Many algorithms in pattern matching, compiler construction (e.g. recursive descent parsers), and machine learning (e.g. based on tree traversal) have a natural representation in terms of stacks.

    ", + "Task:", + "

    Create a stack supporting the basic operations: push, pop, empty.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "The built-in Array class already has stack primitives.", + "var stack = [];", + "stack.push(1)", + "stack.push(2,3);", + "print(stack.pop()); // 3", + "print(stack.length); // 2, stack empty if 0", + "Here's a constructor that wraps the array:", + "function Stack() {", + " this.data = new Array();", + "", + " this.push = function(element) {this.data.push(element)}", + " this.pop = function() {return this.data.pop()}", + " this.empty = function() {return this.data.length == 0}", + " this.peek = function() {return this.data[this.data.length - 1]}", + "}", + "Here's an example using the revealing module pattern instead of prototypes.", + "", + "function makeStack() {", + " var stack = [];", + "", + " var popStack = function () {", + " return stack.pop();", + " };", + " var pushStack = function () {", + " return stack.push.apply(stack, arguments);", + " };", + " var isEmpty = function () {", + " return stack.length === 0;", + " };", + " var peekStack = function () {", + " return stack[stack.length-1];", + " };", + " ", + " return {", + " pop: popStack,", + " push: pushStack,", + " isEmpty: isEmpty,", + " peek: peekStack,", + " top: peekStack", + " };", + "}", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8020", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var stack = [];\nstack.push(1)\nstack.push(2,3);\nprint(stack.pop()); // 3\nprint(stack.length); // 2, stack empty if 0\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Stair-climbing puzzle", + "type": "Waypoint", + "description": [ + "

    From Chung-Chieh Shan (LtU):

    Your stair-climbing robot has a very simple low-level API: the \"step\" function takes no argument and attempts to climb one step as a side effect. Unfortunately, sometimes the attempt fails and the robot clumsily falls one step instead. The \"step\" function detects what happens and returns a boolean flag: true on success, false on failure.

    Write a function \"step_up\" that climbs one step up [from the initial position] (by repeating \"step\" attempts if necessary). Assume that the robot is not already at the top of the stairs, and neither does it ever reach the bottom of the stairs. How small can you make \"step_up\"? Can you avoid using variables (even immutable ones) and numbers?

    Here's a pseudo-code of a simple recursive solution without using variables:

    ", + "
    ",
    +        "func step_up()",
    +        "{",
    +        "    if not step() {",
    +        "        step_up();",
    +        "        step_up();",
    +        "    }",
    +        "}",
    +        "
    ", + "

    Inductive proof that step_up() steps up one step, if it terminates:

    ", + "Base case (if the step() call returns true): it stepped up one step. QED", + "Inductive case (if the step() call returns false): Assume that recursive calls to step_up() step up one step. It stepped down one step (because step() returned false), but now we step up two steps using two step_up() calls. QED", + "

    The second (tail) recursion above can be turned into an iteration, as follows:

    ", + "
    ",
    +        "func step_up()",
    +        "{",
    +        "    while not step() {",
    +        "        step_up();",
    +        "    }",
    +        "}",
    +        "
    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8022", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "State name puzzle", + "type": "Waypoint", + "description": [ + "

    Background

    This task is inspired by Mark Nelson's DDJ Column \"Wordplay\" and one of the weekly puzzle challenges from Will Shortz on NPR Weekend Edition [http://www.npr.org/templates/story/story.php?storyId=9264290] and originally attributed to David Edelheit.

    The challenge was to take the names of two U.S. States, mix them all together, then rearrange the letters to form the names of two different U.S. States (so that all four state names differ from one another).

    What states are these?

    ", + "

    The problem was reissued on the Unicon Discussion Web which includes several solutions with analysis. Several techniques may be helpful and you may wish to refer to Gödel numbering, equivalence relations, and equivalence classes. The basic merits of these were discussed in the Unicon Discussion Web.

    A second challenge in the form of a set of fictitious new states was also presented.

    Task:

    ", + "

    Write a program to solve the challenge using both the original list of states and the fictitious list.

    Caveats:

    ", + "case and spacing aren't significant - just letters (harmonize case)", + "don't expect the names to be in any order - such as being sorted", + "don't rely on names to be unique (eliminate duplicates - meaning if Iowa appears twice you can only use it once)", + "

    Comma separated list of state names used in the original puzzle:

    ", + "
    ",
    +        "    \"Alabama\", \"Alaska\", \"Arizona\", \"Arkansas\",",
    +        "    \"California\", \"Colorado\", \"Connecticut\",",
    +        "    \"Delaware\",    ",
    +        "    \"Florida\", \"Georgia\", \"Hawaii\",",
    +        "    \"Idaho\", \"Illinois\", \"Indiana\", \"Iowa\",",
    +        "    \"Kansas\", \"Kentucky\", \"Louisiana\",",
    +        "    \"Maine\", \"Maryland\", \"Massachusetts\", \"Michigan\",",
    +        "    \"Minnesota\", \"Mississippi\", \"Missouri\", \"Montana\",",
    +        "    \"Nebraska\", \"Nevada\", \"New Hampshire\", \"New Jersey\",",
    +        "    \"New Mexico\", \"New York\", \"North Carolina\", \"North Dakota\",",
    +        "    \"Ohio\", \"Oklahoma\", \"Oregon\",",
    +        "    \"Pennsylvania\", \"Rhode Island\",",
    +        "    \"South Carolina\", \"South Dakota\", \"Tennessee\", \"Texas\",",
    +        "    \"Utah\", \"Vermont\", \"Virginia\",",
    +        "    \"Washington\", \"West Virginia\", \"Wisconsin\", \"Wyoming\"",
    +        "
    ", + "

    Comma separated list of additional fictitious state names to be added to the original (Includes a duplicate):

    ", + "
    ",
    +        "\"New Kory\", \"Wen Kory\", \"York New\", \"Kory New\", \"New Kory\"",
    +        "
    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8024", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Stem-and-leaf plot", + "type": "Waypoint", + "description": [ + "

    Create a well-formatted stem-and-leaf plot from the following data set, where the leaves are the last digits:

    12 127 28 42 39 113 42 18 44 118 44 37 113 124 37 48 127 36 29 31 125 139 131 115 105 132 104 123 35 113 122 42 117 119 58 109 23 105 63 27 44 105 99 41 128 121 116 125 32 61 37 127 29 113 121 58 114 126 53 114 96 25 109 7 31 141 46 13 27 43 117 116 27 7 68 40 31 115 124 42 128 52 71 118 117 38 27 106 33 117 116 111 40 119 47 105 57 122 109 124 115 43 120 43 27 27 18 28 48 125 107 114 34 133 45 120 30 127 31 116 146

    ", + "

    The primary intent of this task is the presentation of information. It is acceptable to hardcode the data set or characteristics of it (such as what the stems are) in the example, insofar as it is impractical to make the example generic to any data set. For example, in a computation-less language like HTML the data set may be entirely prearranged within the example; the interesting characteristics are how the proper visual formatting is arranged.

    If possible, the output should not be a bitmap image. Monospaced plain text is acceptable, but do better if you can. It may be a window, i.e. not a file.

    ", + "

    Note: If you wish to try multiple data sets, you might try this generator.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "It turns out that HTML+CSS renders the plot quite attractively.", + "", + "", + "", + "", + "stem and leaf plot", + "", + "", + "", + "", + "", + "
    ", + "", + "", + "", + "", + "
    ", + "", + "The output looks like: ", + "", + "[[File:Stemplot.png]]", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8027", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "null\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Stern-Brocot sequence", + "type": "Waypoint", + "description": [ + "

    For this task, the Stern-Brocot sequence is to be generated by an algorithm similar to that employed in generating the Fibonacci sequence.

    The first and second members of the sequence are both 1:", + "* 1, 1", + "Start by considering the second member of the sequence", + "Sum the considered member of the sequence and its precedent, (1 + 1) = 2, and append it to the end of the sequence:", + "* 1, 1, 2", + "Append the considered member of the sequence to the end of the sequence:", + "* 1, 1, 2, 1", + "Consider the next member of the series, (the third member i.e. 2)", + "GOTO 3 ", + "* ", + "* ─── Expanding another loop we get: ───", + "*", + "Sum the considered member of the sequence and its precedent, (2 + 1) = 3, and append it to the end of the sequence:", + "* 1, 1, 2, 1, 3", + "Append the considered member of the sequence to the end of the sequence:", + "* 1, 1, 2, 1, 3, 2", + "Consider the next member of the series, (the fourth member i.e. 1)The task is to:", + "Create a function/method/subroutine/procedure/... to generate the Stern-Brocot sequence of integers using the method outlined above.", + "Show the first fifteen members of the sequence. (This should be: 1, 1, 2, 1, 3, 2, 3, 1, 4, 3, 5, 2, 5, 3, 4)", + "Show the (1-based) index of where the numbers 1-to-10 first appears in the sequence.", + "Show the (1-based) index of where the number 100 first appears in the sequence.", + "Check that the greatest common divisor of all the two consecutive members of the series up to the 1000th member, is always one.", + "Show your output on this page.", + "Ref:", + "Infinite Fractions - Numberphile (Video).", + "Trees, Teeth, and Time: The mathematics of clock making. ", + "A002487 The On-Line Encyclopedia of Integer Sequences.Related Tasks:", + "Continued fraction/Arithmetic" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8028", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Straddling checkerboard", + "type": "Waypoint", + "description": [ + "

    Implement functions to encrypt and decrypt a message using the straddling checkerboard method. The checkerboard should take a 28 character alphabet (A-Z plus a full stop and an escape character) and two different numbers representing the blanks in the first row. The output will be a series of decimal digits.

    Numbers should be encrypted by inserting the escape character before each digit, then including the digit unencrypted. This should be reversed for decryption.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "", + "Output:
    One night-it was on the twentieth of March, 1888-I was returning.",
    +        "34045747525284613427502840425027537379697175891898898898584619028294547488",
    +        "ONENIGHTITWASONTHETWENTIETHOFMARCH1888IWASRETURNING.
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8029", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Stream Merge", + "type": "Waypoint", + "description": [ + " 2-stream merge", + "

    Read two sorted streams of items from external source (e.g. disk, or network), and write one stream of sorted items to external sink.

    ", + "

    Common algorithm: keep 1 buffered item from each source, select minimal of them, write it, fetch another item from that stream from which the written item was.

    N-stream merge", + "

    The same as above, but reading from N sources.

    ", + "

    Common algorithm: same as above, but keep buffered items and their source descriptors in a heap.

    ", + "

    Assume streams are very big. You must not suck them whole in the memory, but read them as streams.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc802a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "String interpolation (included)", + "type": "Waypoint", + "description": [ + "

    Given a string and defined variables or values, string interpolation is the replacement of defined character sequences in the string by values or variable values.

    ", + "

    For example, given an original string of \"Mary had a X lamb.\", a value of \"big\", and if the language replaces X in its interpolation routine, then the result of its interpolation would be the string \"Mary had a big lamb\".

    (Languages usually include an infrequently used character or sequence of characters to indicate what is to be replaced such as \"%\", or \"#\" rather than \"X\").

    The task is to: ", + "Use your languages inbuilt string interpolation abilities to interpolate a string missing the text \"little\" which is held in a variable, to produce the output string \"Mary had a little lamb\".", + "If possible, give links to further documentation on your languages string interpolation features.", + "

    Note: The task is not to create a string interpolation routine, but to show a language's built-in capability.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "var original = \"Mary had a X lamb\";", + "var little = \"little\";", + "var replaced = original.replace(\"X\", little); //does not change the original string", + "", + "Or,", + "", + "// ECMAScript 6", + "var X = \"little\";", + "var replaced = `Mary had a ${X} lamb`;", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc802f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var original = \"Mary had a X lamb\";\nvar little = \"little\";\nvar replaced = original.replace(\"X\", little); //does not change the original string\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "String matching", + "type": "Waypoint", + "description": [ + "Task:", + "

    Given two strings, demonstrate the following three types of string matching:

    :# Determining if the first string starts with second string

    ", + "

    :# Determining if the first string contains the second string at any location

    ", + "

    :# Determining if the first string ends with the second string

    ", + "

    Optional requirements:

    ", + "

    :# Print the location of the match for part 2

    ", + "

    :# Handle multiple occurrences of a string for part 2.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "var stringA = \"tacoloco\"", + " , stringB = \"co\"", + " , q1, q2, q2multi, m", + " , q2matches = []", + "", + "// stringA starts with stringB", + "q1 = stringA.substring(0, stringB.length) == stringB", + "", + "// stringA contains stringB", + "q2 = stringA.indexOf(stringB)", + "", + "// multiple matches", + "q2multi = new RegExp(stringB,'g')", + "", + "while(m = q2multi.exec(stringA)){", + "\tq2matches.push(m.index)", + "}", + "", + "// stringA ends with stringB", + "q3 = stringA.substr(-stringB.length) == stringB", + "", + "console.log(\"1: Does '\"+stringA+\"' start with '\"+stringB+\"'? \" + ( q1 ? \"Yes.\" : \"No.\"))", + "console.log(\"2: Is '\"+stringB+\"' contained in '\"+stringA+\"'? \" + (~q2 ? \"Yes, at index \"+q2+\".\" : \"No.\"))", + "if (~q2 && q2matches.length > 1){", + "\tconsole.log(\" In fact, it happens \"+q2matches.length+\" times within '\"+stringA+\"', at index\"+(q2matches.length > 1 ? \"es\" : \"\")+\" \"+q2matches.join(', ')+\".\")", + "}", + "console.log(\"3: Does '\"+stringA+\"' end with '\"+stringB+\"'? \" + ( q3 ? \"Yes.\" : \"No.\"))", + "", + "{{out}}", + "
    1: Does 'tacoloco' start with 'co'? No.",
    +        "2: Is 'co' contained in 'tacoloco'? Yes, at index 2.",
    +        "   In fact, it happens 2 times within 'tacoloco', at indexes 2, 6.",
    +        "3: Does 'tacoloco' end with 'co'? Yes.
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8031", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var stringA = \"tacoloco\"\n , stringB = \"co\"\n , q1, q2, q2multi, m\n , q2matches = []\n\n// stringA starts with stringB\nq1 = stringA.substring(0, stringB.length) == stringB\n\n// stringA contains stringB\nq2 = stringA.indexOf(stringB)\n\n// multiple matches\nq2multi = new RegExp(stringB,'g')\n\nwhile(m = q2multi.exec(stringA)){\n\tq2matches.push(m.index)\n}\n\n// stringA ends with stringB\nq3 = stringA.substr(-stringB.length) == stringB\n\nconsole.log(\"1: Does '\"+stringA+\"' start with '\"+stringB+\"'? \" + ( q1 ? \"Yes.\" : \"No.\"))\nconsole.log(\"2: Is '\"+stringB+\"' contained in '\"+stringA+\"'? \" + (~q2 ? \"Yes, at index \"+q2+\".\" : \"No.\"))\nif (~q2 && q2matches.length > 1){\n\tconsole.log(\" In fact, it happens \"+q2matches.length+\" times within '\"+stringA+\"', at index\"+(q2matches.length > 1 ? \"es\" : \"\")+\" \"+q2matches.join(', ')+\".\")\n}\nconsole.log(\"3: Does '\"+stringA+\"' end with '\"+stringB+\"'? \" + ( q3 ? \"Yes.\" : \"No.\"))\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Strip a set of characters from a string", + "type": "Waypoint", + "description": [ + "Task:", + "

    Create a function that strips a set of characters from a string.

    ", + "

    The function should take two arguments:

    ", + "

    ::# a string to be stripped

    ", + "

    ::# a string containing the set of characters to be stripped

    ", + "

    The returned string should contain the first string, stripped of any characters in the second argument:

    ", + "

    print stripchars(\"She was a soul stripper. She took my heart!\",\"aei\")

    ", + "

    Sh ws soul strppr. Sh took my hrt!

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "function stripchars(string, chars) {", + " return string.replace(RegExp('['+chars+']','g'), '');", + "}", + "", + "===ES6===", + "", + "Reversing the order of the arguments, to simplify any currying:", + "", + "(() => {", + " 'use strict';", + "", + " // stripChars :: String -> String -> String", + " const stripChars = (strNeedles, strHayStack) =>", + " strHayStack.replace(RegExp(`[${strNeedles}]`, 'g'), '');", + "", + " // GENERIC FUNCTION", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " const curry = f => a => b => f(a, b);", + "", + " // TEST FUNCTION", + "", + " const noAEI = curry(stripChars)('aeiAEI');", + "", + " // TEST", + " return noAEI('She was a soul stripper. She took my heart!');", + "", + " // 'Sh ws soul strppr. Sh took my hrt!'", + "})();", + "", + "{{Out}}", + "
    'Sh ws  soul strppr. Sh took my hrt!'
    ", + "", + "Alternatively, we could also do this without a regex:", + "", + "(() => {", + " 'use strict';", + "", + " // stripChars :: String -> String -> String", + " const stripChars = (strNeedles, strHayStack) =>", + " strHayStack.split('')", + " .filter(x => !elem(x, strNeedles))", + " .join('');", + "", + " // GENERIC FUNCTIONS", + "", + " // elem :: Eq a => a -> [a] -> Bool", + " const elem = (x, xs) => xs.indexOf(x) !== -1;", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " const curry = f => a => b => f(a, b);", + "", + " // TEST FUNCTION", + "", + " const noAEI = curry(stripChars)('aeiAEI');", + "", + " ", + " // TEST", + " return noAEI('She was a soul stripper. She took my heart!');", + "", + " // 'Sh ws soul strppr. Sh took my hrt!'", + "})();", + "", + "{{Out}}", + "
    'Sh ws  soul strppr. Sh took my hrt!'
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8033", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function stripchars(string, chars) {\n return string.replace(RegExp('['+chars+']','g'), '');\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Strip block comments", + "type": "Waypoint", + "description": [ + "

    A block comment begins with a beginning delimiter and ends with a ending delimiter, including the delimiters. These delimiters are often multi-character sequences.

    ", + "Task:", + "

    Strip block comments from program text (of a programming language much like classic C).

    Your demos should at least handle simple, non-nested and multi-line block comment delimiters.

    The block comment delimiters are the two-character sequence:

    ", + "

    ::* /* (beginning delimiter)

    ", + "

    ::* */ (ending delimiter)

    ", + "

    Sample text for stripping:

    ", + "
    ",
    +        "  /**",
    +        "   * Some comments",
    +        "   * longer comments here that we can parse.",
    +        "   *",
    +        "   * Rahoo ",
    +        "   */",
    +        "   function subroutine() {",
    +        "    a = /* inline comment */ b + c ;",
    +        "   }",
    +        "   /*/ <-- tricky comments */   /**",
    +        "    * Another comment.",
    +        "    */",
    +        "    function something() {",
    +        "    }",
    +        "
    Extra credit:", + "

    Ensure that the stripping code is not hard-coded to the particular delimiters described above, but instead allows the caller to specify them. (If your language supports them, optional parameters may be useful for this.)

    ", + "Related task:", + " Strip comments from a string" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8034", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Strip comments from a string", + "type": "Waypoint", + "description": [ + "

    The task is to remove text that follow any of a set of comment markers, (in these examples either a hash or a semicolon) from a string or input line.

    ", + "

    Whitespace debacle: There is some confusion about whether to remove any whitespace from the input line.

    As of 2 September 2011, at least 8 languages (C, C++, Java, Perl, Python, Ruby, sed, UNIX Shell) were incorrect, out of 36 total languages, because they did not trim whitespace by 29 March 2011 rules. Some other languages might be incorrect for the same reason.

    Please discuss this issue at .

    From 29 March 2011, this task required that: \"The comment marker and any whitespace at the beginning or ends of the resultant line should be removed. A line without comments should be trimmed of any leading or trailing whitespace before being produced as a result.\" The task had 28 languages, which did not all meet this new requirement.", + "From 28 March 2011, this task required that: \"Whitespace before the comment marker should be removed.\"", + "From 30 October 2010, this task did not specify whether or not to remove whitespace.", + "

    The following examples will be truncated to either \"apples, pears \" or \"apples, pears\".

    (This example has flipped between \"apples, pears \" and \"apples, pears\" in the past.)

    ",
    +        "apples, pears # and bananas",
    +        "apples, pears ; and bananas",
    +        "
    ", + "Related task:", + " Strip block comments" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "function stripComments(s) {", + " var re1 = /^\\s+|\\s+$/g; // Strip leading and trailing spaces", + " var re2 = /\\s*[#;].+$/g; // Strip everything after # or ; to the end of the line, including preceding spaces", + " return s.replace(re1,'').replace(re2,'');", + "}", + "", + "", + "var s1 = 'apples, pears # and bananas';", + "var s2 = 'apples, pears ; and bananas';", + "", + "alert(stripComments(s1) + '\\n' + stripComments(s2));", + "", + "", + "A more efficient version that caches the regular expressions in a closure:", + "", + "var stripComments = (function () {", + " var re1 = /^\\s+|\\s+$/g;", + " var re2 = /\\s*[#;].+$/g;", + " return function (s) {", + " return s.replace(re1,'').replace(re2,'');", + " };", + "}());", + "", + "A difference with the two versions is that in the first, all declarations are processed before code is executed so the function declaration can be after the code that calls it. However in the second example, the expression creating the function must be executed before the function is available, so it must be before the code that calls it.", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8035", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function stripComments(s) {\n var re1 = /^\\s+|\\s+$/g; // Strip leading and trailing spaces\n var re2 = /\\s*[#;].+$/g; // Strip everything after # or ; to the end of the line, including preceding spaces\n return s.replace(re1,'').replace(re2,'');\n}\n\n\nvar s1 = 'apples, pears # and bananas';\nvar s2 = 'apples, pears ; and bananas';\n\nalert(stripComments(s1) + '\\n' + stripComments(s2));\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Strip control codes and extended characters from a string", + "type": "Waypoint", + "description": [ + "

    The task is to strip control codes and extended characters from a string. The solution should demonstrate how to achieve each of the following results:

    a string with control codes stripped (but extended characters not stripped)", + "a string with control codes and extended characters stripped

    In ASCII, the control codes have decimal codes 0 through to 31 and 127. On an ASCII based system, if the control codes are stripped, the resultant string would have all of its characters within the range of 32 to 126 decimal on the ASCII table.

    On a non-ASCII based system, we consider characters that do not have a corresponding glyph on the ASCII table (within the ASCII range of 32 to 126 decimal) to be an extended character for the purpose of this task.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES 5===", + "", + "(function (strTest) {", + "", + " // s -> s", + " function strip(s) {", + " return s.split('').filter(function (x) {", + " var n = x.charCodeAt(0);", + " ", + " return 31 < n && 127 > n;", + " }).join('');", + " }", + "", + " return strip(strTest);", + "", + "})(\"\\ba\\x00b\\n\\rc\\fd\\xc3\");", + "", + "{{Out}}", + "", + "\"abcd\"", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8036", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function (strTest) {\n\n // s -> s\n function strip(s) {\n return s.split('').filter(function (x) {\n var n = x.charCodeAt(0);\n \n return 31 < n && 127 > n;\n }).join('');\n }\n\n return strip(strTest);\n\n})(\"\\ba\\x00b\\n\\rc\\fd\\xc3\");\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Subleq", + "type": "Waypoint", + "description": [ + "

    Subleq is an example of a One-Instruction Set Computer (OISC).

    It is named after its only instruction, which is SUbtract and Branch if Less than or EQual to zero.

    ", + "Task

    Your task is to create an interpreter which emulates such a machine.

    ", + "

    The machine's memory consists of an array of signed integers. Any reasonable word size is fine, but the memory must be able to hold negative as well as positive numbers.

    Execution begins with the instruction pointer aimed at the first word, which is address 0. It proceeds as follows:

    Let A, B, and C be the value stored in the three consecutive words in memory starting at the instruction pointer.", + "Advance the instruction pointer 3 words to point at the address after the one containing C. ", + "If A is -1, then a character is read from standard input and its code point stored in the address given by B. C is unused.", + "If B is -1, then the number contained in the address given by A is interpreted as a code point and the corresponding character output. C is again unused.", + "Otherwise, both A and B are treated as the addresses of memory locations. The number contained in the address given by A is subtracted from the number at the address given by B (and the result stored back in address B). If the result is zero or negative, the value C becomes the new instruction pointer.", + "If the instruction pointer becomes negative, execution halts.", + "Other negative addresses besides -1 may be treated as equivalent to -1, or generate an error, as you see fit.

    Your solution should accept a program to execute on the machine, separately from the input fed to the program itself. This program should be in raw subleq \"machine code\" - whitespace-separated decimal numbers, with no symbolic names or other assembly-level extensions, to be loaded into memory starting at address 0. Show the output of your solution when fed this \"Hello, world!\" program. (Note that the example assumes ASCII or a superset of it, such as any of the Latin-N character sets or Unicode. You may translate it into another character set if your implementation is on a non-ASCiI-compatible environment.)

    15 17 -1 17 -1 -1 16 1 -1 16 3 -1 15 15 0 0 -1 72 101 108 108 111 44 32 119 111 114 108 100 33 10 0

    Which corresponds to something like this in a hypothetical assembler language:

    start:",
    +        "    zero, message, -1",
    +        "    message, -1, -1",
    +        "    neg1, start+1, -1",
    +        "    neg1, start+3, -1",
    +        "    zero, zero, start",
    +        "zero: 0",
    +        "neg1: -1",
    +        "message: \"Hello, world!\\n\\0\"
    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8038", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Substring", + "type": "Waypoint", + "description": [ + "

    In this task display a substring:

    starting from n characters in and of m length;", + "starting from n characters in, up to the end of the string;", + "whole string minus last character;", + "starting from a known character within the string and of m length;", + "starting from a known substring within the string and of m length.", + "

    If the program uses UTF-8 or UTF-16, it must work on any valid Unicode code point,

    ", + "

    whether in the Basic Multilingual Plane or above it.

    The program must reference logical characters (code points), not 8-bit code units for UTF-8 or 16-bit code units for UTF-16.

    Programs for other encodings (such as 8-bit ASCII, or EUC-JP) are not required to handle all Unicode characters.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "The String object has two similar methods: substr and substring.", + "*substr(start, [len]) returns a substring beginning at a specified location and having a specified length.", + "*substring(start, [end]) returns a string containing the substring from start up to, ''but not including'', end.", + "", + "var str = \"abcdefgh\";", + "", + "var n = 2;", + "var m = 3;", + "", + "// * starting from n characters in and of m length;", + "str.substr(n, m); // => \"cde\"", + "", + "// * starting from n characters in, up to the end of the string;", + "str.substr(n); // => \"cdefgh\"", + "str.substring(n); // => \"cdefgh\"", + "", + "// * whole string minus last character;", + "str.substring(0, str.length - 1); // => \"abcdefg\"", + "", + "// * starting from a known character within the string and of m length;", + "str.substr(str.indexOf('b'), m); // => \"bcd\"", + "", + "// * starting from a known substring within the string and of m length. ", + "str.substr(str.indexOf('bc'), m); // => \"bcd\"", + "", + "", + "Or, in terms of some familiar functional primitives, translating broadly from Haskell:", + "", + "(function () {", + " 'use strict';", + "", + " // take :: Int -> Text -> Text", + " function take(n, s) {", + " return s.substr(0, n);", + " }", + "", + " // drop :: Int -> Text -> Text", + " function drop(n, s) {", + " return s.substr(n);", + " }", + "", + "", + " // init :: Text -> Text", + " function init(s) {", + " var n = s.length;", + " return (n > 0 ? s.substr(0, n - 1) : undefined);", + " }", + " ", + " // breakOn :: Text -> Text -> (Text, Text)", + " function breakOn(strPattern, s) {", + " var i = s.indexOf(strPattern);", + " return i === -1 ? [strPattern, ''] : [s.substr(0, i), s.substr(i)];", + " }", + " ", + "", + " var str = '一二三四五六七八九十';", + "", + "", + " return JSON.stringify({", + " ", + " 'from n in, of m length': (function (n, m) {", + " return take(m, drop(n, str));", + " })(4, 3),", + " ", + " ", + " 'from n in, up to end' :(function (n) {", + " return drop(n, str);", + " })(3),", + " ", + " ", + " 'all but last' : init(str),", + " ", + " ", + " 'from matching char, of m length' : (function (pattern, s, n) {", + " return take(n, breakOn(pattern, s)[1]);", + " })('五', str, 3),", + " ", + " ", + " 'from matching string, of m length':(function (pattern, s, n) {", + " return take(n, breakOn(pattern, s)[1]);", + " })('六七', str, 4)", + " ", + " }, null, 2);", + "", + "})();", + "", + "{{Out}}", + "", + "{", + " \"from n in, of m length\": \"五六七\",", + " \"from n in, up to end\": \"四五六七八九十\",", + " \"all but last\": \"一二三四五六七八九\",", + " \"from matching char, of m length\": \"五六七\",", + " \"from matching string, of m length\": \"六七八九\"", + "}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8039", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var str = \"abcdefgh\";\n\nvar n = 2;\nvar m = 3;\n\n// * starting from n characters in and of m length;\nstr.substr(n, m); // => \"cde\"\n\n// * starting from n characters in, up to the end of the string;\nstr.substr(n); // => \"cdefgh\"\nstr.substring(n); // => \"cdefgh\"\n\n// * whole string minus last character;\nstr.substring(0, str.length - 1); // => \"abcdefg\"\n\n// * starting from a known character within the string and of m length;\nstr.substr(str.indexOf('b'), m); // => \"bcd\"\n\n// * starting from a known substring within the string and of m length. \nstr.substr(str.indexOf('bc'), m); // => \"bcd\"\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Substring/Top and tail", + "type": "Waypoint", + "description": [ + "

    The task is to demonstrate how to remove the first and last characters from a string.

    The solution should demonstrate how to obtain the following results:

    String with first character removed", + "String with last character removed", + "String with both the first and last characters removed", + "

    If the program uses UTF-8 or UTF-16, it must work on any valid Unicode code point, whether in the Basic Multilingual Plane or above it.

    The program must reference logical characters (code points), not 8-bit code units for UTF-8 or 16-bit code units for UTF-16.

    Programs for other encodings (such as 8-bit ASCII, or EUC-JP) are not required to handle all Unicode characters.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "alert(\"knight\".slice(1)); // strip first character", + "alert(\"socks\".slice(0, -1)); // strip last character", + "alert(\"brooms\".slice(1, -1)); // strip both first and last characters", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc803a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "alert(\"knight\".slice(1)); // strip first character\nalert(\"socks\".slice(0, -1)); // strip last character\nalert(\"brooms\".slice(1, -1)); // strip both first and last characters\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sudoku", + "type": "Waypoint", + "description": [ + "Task:", + "

    Solve a partially filled-in normal 9x9 Sudoku grid and display the result in a human-readable format.

    ", + "

    Algorithmics of Sudoku may help implement this.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "====ES6====", + "", + "//-------------------------------------------[ Dancing Links and Algorithm X ]--", + "/**", + " * The doubly-doubly circularly linked data object.", + " * Data object X", + " */", + "class DoX {", + " /**", + " * @param {string} V", + " * @param {!DoX=} H", + " */", + " constructor(V, H) {", + " this.V = V;", + " this.L = this;", + " this.R = this;", + " this.U = this;", + " this.D = this;", + " this.S = 1;", + " this.H = H || this;", + " H && (H.S += 1);", + " }", + "}", + "", + "/**", + " * Helper function to help build a horizontal doubly linked list.", + " * @param {!DoX} e An existing node in the list.", + " * @param {!DoX} n A new node to add to the right of the existing node.", + " * @return {!DoX}", + " */", + "const addRight = (e, n) => {", + " n.R = e.R;", + " n.L = e;", + " e.R.L = n;", + " return e.R = n;", + "};", + "", + "/**", + " * Helper function to help build a vertical doubly linked list.", + " * @param {!DoX} e An existing node in the list.", + " * @param {!DoX} n A new node to add below the existing node.", + " */", + "const addBelow = (e, n) => {", + " n.D = e.D;", + " n.U = e;", + " e.D.U = n;", + " return e.D = n;", + "};", + "", + "/**", + " * Verbatim copy of DK's search algorithm. The meat of the DLX algorithm.", + " * @param {!DoX} h The root node.", + " * @param {!Array} s The solution array.", + " */", + "const search = function(h, s) {", + " if (h.R == h) {", + " printSol(s);", + " } else {", + " let c = chooseColumn(h);", + " cover(c);", + " for (let r = c.D; r != c; r = r.D) {", + " s.push(r);", + " for (let j = r.R; r !=j; j = j.R) {", + " cover(j.H);", + " }", + " search(h, s);", + " r = s.pop();", + " for (let j = r.R; j != r; j = j.R) {", + " uncover(j.H);", + " }", + " }", + " uncover(c);", + " }", + "};", + "", + "/**", + " * Verbatim copy of DK's algorithm for choosing the next column object.", + " * @param {!DoX} h", + " * @return {!DoX}", + " */", + "const chooseColumn = h => {", + " let s = Number.POSITIVE_INFINITY;", + " let c = h;", + " for(let j = h.R; j != h; j = j.R) {", + " if (j.S < s) {", + " c = j;", + " s = j.S;", + " }", + " }", + " return c;", + "};", + "", + "", + "/**", + " * Verbatim copy of DK's cover algorithm", + " * @param {!DoX} c", + " */", + "const cover = c => {", + " c.L.R = c.R;", + " c.R.L = c.L;", + " for (let i = c.D; i != c; i = i.D) {", + " for (let j = i.R; j != i; j = j.R) {", + " j.U.D = j.D;", + " j.D.U = j.U;", + " j.H.S = j.H.S - 1;", + " }", + " }", + "};", + "", + "/**", + " * Verbatim copy of DK's cover algorithm", + " * @param {!DoX} c", + " */", + "const uncover = c => {", + " for (let i = c.U; i != c; i = i.U) {", + " for (let j = i.L; i != j; j = j.L) {", + " j.H.S = j.H.S + 1;", + " j.U.D = j;", + " j.D.U = j;", + " }", + " }", + " c.L.R = c;", + " c.R.L = c;", + "};", + "", + "//-----------------------------------------------------------[ Print Helpers ]--", + "/**", + " * Given the standard string format of a grid, print a formatted view of it.", + " * @param {!string|!Array} a", + " */", + "const printGrid = function(a) {", + "", + " const getChar = c => {", + " let r = Number(c);", + " if (isNaN(r)) { return c }", + "", + " let o = 48;", + " if (r > 9 && r < 36) { o = 55 }", + " if (r >= 36) { o = 61 }", + " return String.fromCharCode(r + o)", + " };", + "", + " a = 'string' == typeof a ? a.split('') : a;", + "", + " let U = Math.sqrt(a.length);", + " let N = Math.sqrt(U);", + " let line = new Array(N).fill('+').reduce((p, c) => {", + " p.push(... Array.from(new Array(1 + N*2).fill('-')));", + " p.push(c);", + " return p;", + " }, ['\\n+']).join('') + '\\n';", + "", + " a = a.reduce(function(p, c, i) {", + " let d = i && !(i % U), G = i && !(i % N);", + " i = !(i % (U * N));", + " d && !i && (p += '|\\n| ');", + " d && i && (p += '|');", + " i && (p = '' + p + line + '| ');", + " return '' + p + (G && !d ? '| ' : '') + getChar(c) + ' ';", + " }, '') + '|' + line;", + " console.log(a);", + "", + "};", + "", + "/**", + " * Given a search solution, print the resultant grid.", + " * @param {!Array} a An array of data objects", + " */", + "const printSol = a => {", + " printGrid(a.reduce((p, c) => {", + " let [i, v] = c.V.split(':');", + " p[i * 1] = v;", + " return p;", + " }, new Array(a.length).fill('.')));", + "};", + "", + "//----------------------------------------------[ Grid to Exact cover Matrix ]--", + "/**", + " * Helper to get some meta about the grid.", + " * @param {!string} s The standard string representation of a grid.", + " * @return {!Array}", + " */", + "const gridMeta = s => {", + " const g = s.split('');", + " const cellCount = g.length;", + " const tokenCount = Math.sqrt(cellCount);", + " const N = Math.sqrt(tokenCount);", + " const g2D = g.map(e => isNaN(e * 1) ?", + " new Array(tokenCount).fill(1).map((_, i) => i + 1) :", + " [e * 1]);", + " return [cellCount, N, tokenCount, g2D];", + "};", + "", + "/**", + " * Given a cell grid index, return the row, column and box indexes.", + " * @param {!number} n The n-value of the grid. 3 for a 9x9 sudoku.", + " * @return {!function(!number): !Array}", + " */", + "const indexesN = n => i => {", + " let c = Math.floor(i / (n * n));", + " i %= n * n;", + " return [c, i, Math.floor(c / n) * n + Math.floor(i / n)];", + "};", + "", + "/**", + " * Given a puzzle string, reduce it to an exact-cover matrix and use", + " * Donald Knuth's DLX algorithm to solve it.", + " * @param puzString", + " */", + "const reduceGrid = puzString => {", + "", + " printGrid(puzString);", + " const [", + " numCells, // The total number of cells in a grid (81 for a 9x9 grid)", + " N, // the 'n' value of the grid. (3 for a 9x9 grid)", + " U, // The total number of unique tokens to be placed.", + " g2D // A 2D array representation of the grid, with each element", + " // being an array of candidates for a cell. Known cells are", + " // single element arrays.", + " ] = gridMeta(puzString);", + "", + " const getIndex = indexesN(N);", + "", + " /**", + " * The DLX Header row.", + " * Its length is 4 times the grid's size. This is to be able to encode", + " * each of the 4 Sudoku constrains, onto each of the cells of the grid.", + " * The array is initialised with unlinked DoX nodes, but in the next step", + " * those nodes are all linked.", + " * @type {!Array.}", + " */", + " const headRow = new Array(4 * numCells)", + " .fill('')", + " .map((_, i) => new DoX(`H${i}`));", + "", + " /**", + " * The header row root object. This is circularly linked to be to the left", + " * of the first header object in the header row array.", + " * It is used as the entry point into the DLX algorithm.", + " * @type {!DoX}", + " */", + " let H = new DoX('ROOT');", + " headRow.reduce((p, c) => addRight(p, c), H);", + "", + " /**", + " * Transposed the sudoku puzzle into a exact cover matrix, so it can be passed", + " * to the DLX algorithm to solve.", + " */", + " for (let i = 0; i < numCells; i++) {", + " const [ri, ci, bi] = getIndex(i);", + " g2D[i].forEach(num => {", + " let id = `${i}:${num}`;", + " let candIdx = num - 1;", + "", + " // The 4 columns that we will populate.", + " const A = headRow[i];", + " const B = headRow[numCells + candIdx + (ri * U)];", + " const C = headRow[(numCells * 2) + candIdx + (ci * U)];", + " const D = headRow[(numCells * 3) + candIdx + (bi * U)];", + "", + " // The Row-Column Constraint", + " let rcc = addBelow(A.U, new DoX(id, A));", + "", + " // The Row-Number Constraint", + " let rnc = addBelow(B.U, addRight(rcc, new DoX(id, B)));", + "", + " // The Column-Number Constraint", + " let cnc = addBelow(C.U, addRight(rnc, new DoX(id, C)));", + "", + " // The Block-Number Constraint", + " addBelow(D.U, addRight(cnc, new DoX(id, D)));", + " });", + " }", + " search(H, []);", + "};", + "", + "", + "[", + " '819..5.....2...75..371.4.6.4..59.1..7..3.8..2..3.62..7.5.7.921..64...9.....2..438',", + " '53..247....2...8..1..7.39.2..8.72.49.2.98..7.79.....8.....3.5.696..1.3...5.69..1.',", + " '..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..',", + " '394..267....3..4..5..69..2..45...9..6.......7..7...58..1..67..8..9..8....264..735',", + " '97.3...6..6.75.........8.5.......67.....3.....539..2..7...25.....2.1...8.4...73..',", + " '4......6.5...8.9..3....1....2.7....1.9.....4.8....3.5....2....7..6.5...8.1......6',", + " '85...24..72......9..4.........1.7..23.5...9...4...........8..7..17..........36.4.',", + " '..1..5.7.92.6.......8...6...9..2.4.1.........3.4.8..9...7...3.......7.69.1.8..7..',", + " '.9...4..7.....79..8........4.58.....3.......2.....97.6........4..35.....2..6...8.',", + " '12.3....435....1....4........54..2..6...7.........8.9...31..5.......9.7.....6...8',", + " '9..2..5...4..6..3...3.....6...9..2......5..8...7..4..37.....1...5..2..4...1..6..9',", + " '1....7.9..3..2...8..96..5....53..9...1..8...26....4...3......1..4......7..7...3..',", + " '12.4..3..3...1..5...6...1..7...9.....4.6.3.....3..2...5...8.7....7.....5.......98',", + " '..............3.85..1.2.......5.7.....4...1...9.......5......73..2.1........4...9',", + " '.......39.....1..5..3.5.8....8.9...6.7...2...1..4.......9.8..5..2....6..4..7.....',", + " '....839..1......3...4....7..42.3....6.......4....7..1..2........8...92.....25...6',", + " '..3......4...8..36..8...1...4..6..73...9..........2..5..4.7..686........7..6..5..'", + "].forEach(reduceGrid);", + "", + "// Or of you want to create all the grids of a particular n-size.", + "// I run out of stack space at n = 9", + "let n = 2;", + "let s = new Array(Math.pow(n, 4)).fill('.').join('');", + "reduceGrid(s);", + "", + "", + "
    +-------+-------+-------+",
    +        "| . . 3 | . . . | . . . |",
    +        "| 4 . . | . 8 . | . 3 6 |",
    +        "| . . 8 | . . . | 1 . . |",
    +        "+-------+-------+-------+",
    +        "| . 4 . | . 6 . | . 7 3 |",
    +        "| . . . | 9 . . | . . . |",
    +        "| . . . | . . 2 | . . 5 |",
    +        "+-------+-------+-------+",
    +        "| . . 4 | . 7 . | . 6 8 |",
    +        "| 6 . . | . . . | . . . |",
    +        "| 7 . . | 6 . . | 5 . . |",
    +        "+-------+-------+-------+",
    +        "",
    +        "+-------+-------+-------+",
    +        "| 1 2 3 | 4 5 6 | 7 8 9 |",
    +        "| 4 5 7 | 1 8 9 | 2 3 6 |",
    +        "| 9 6 8 | 3 2 7 | 1 5 4 |",
    +        "+-------+-------+-------+",
    +        "| 2 4 9 | 5 6 1 | 8 7 3 |",
    +        "| 5 7 6 | 9 3 8 | 4 1 2 |",
    +        "| 8 3 1 | 7 4 2 | 6 9 5 |",
    +        "+-------+-------+-------+",
    +        "| 3 1 4 | 2 7 5 | 9 6 8 |",
    +        "| 6 9 5 | 8 1 4 | 3 2 7 |",
    +        "| 7 8 2 | 6 9 3 | 5 4 1 |",
    +        "+-------+-------+-------+",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc803c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "//-------------------------------------------[ Dancing Links and Algorithm X ]--\n/**\n * The doubly-doubly circularly linked data object.\n * Data object X\n */\nclass DoX {\n /**\n * @param {string} V\n * @param {!DoX=} H\n */\n constructor(V, H) {\n this.V = V;\n this.L = this;\n this.R = this;\n this.U = this;\n this.D = this;\n this.S = 1;\n this.H = H || this;\n H && (H.S += 1);\n }\n}\n\n/**\n * Helper function to help build a horizontal doubly linked list.\n * @param {!DoX} e An existing node in the list.\n * @param {!DoX} n A new node to add to the right of the existing node.\n * @return {!DoX}\n */\nconst addRight = (e, n) => {\n n.R = e.R;\n n.L = e;\n e.R.L = n;\n return e.R = n;\n};\n\n/**\n * Helper function to help build a vertical doubly linked list.\n * @param {!DoX} e An existing node in the list.\n * @param {!DoX} n A new node to add below the existing node.\n */\nconst addBelow = (e, n) => {\n n.D = e.D;\n n.U = e;\n e.D.U = n;\n return e.D = n;\n};\n\n/**\n * Verbatim copy of DK's search algorithm. The meat of the DLX algorithm.\n * @param {!DoX} h The root node.\n * @param {!Array} s The solution array.\n */\nconst search = function(h, s) {\n if (h.R == h) {\n printSol(s);\n } else {\n let c = chooseColumn(h);\n cover(c);\n for (let r = c.D; r != c; r = r.D) {\n s.push(r);\n for (let j = r.R; r !=j; j = j.R) {\n cover(j.H);\n }\n search(h, s);\n r = s.pop();\n for (let j = r.R; j != r; j = j.R) {\n uncover(j.H);\n }\n }\n uncover(c);\n }\n};\n\n/**\n * Verbatim copy of DK's algorithm for choosing the next column object.\n * @param {!DoX} h\n * @return {!DoX}\n */\nconst chooseColumn = h => {\n let s = Number.POSITIVE_INFINITY;\n let c = h;\n for(let j = h.R; j != h; j = j.R) {\n if (j.S < s) {\n c = j;\n s = j.S;\n }\n }\n return c;\n};\n\n\n/**\n * Verbatim copy of DK's cover algorithm\n * @param {!DoX} c\n */\nconst cover = c => {\n c.L.R = c.R;\n c.R.L = c.L;\n for (let i = c.D; i != c; i = i.D) {\n for (let j = i.R; j != i; j = j.R) {\n j.U.D = j.D;\n j.D.U = j.U;\n j.H.S = j.H.S - 1;\n }\n }\n};\n\n/**\n * Verbatim copy of DK's cover algorithm\n * @param {!DoX} c\n */\nconst uncover = c => {\n for (let i = c.U; i != c; i = i.U) {\n for (let j = i.L; i != j; j = j.L) {\n j.H.S = j.H.S + 1;\n j.U.D = j;\n j.D.U = j;\n }\n }\n c.L.R = c;\n c.R.L = c;\n};\n\n//-----------------------------------------------------------[ Print Helpers ]--\n/**\n * Given the standard string format of a grid, print a formatted view of it.\n * @param {!string|!Array} a\n */\nconst printGrid = function(a) {\n\n const getChar = c => {\n let r = Number(c);\n if (isNaN(r)) { return c }\n\n let o = 48;\n if (r > 9 && r < 36) { o = 55 }\n if (r >= 36) { o = 61 }\n return String.fromCharCode(r + o)\n };\n\n a = 'string' == typeof a ? a.split('') : a;\n\n let U = Math.sqrt(a.length);\n let N = Math.sqrt(U);\n let line = new Array(N).fill('+').reduce((p, c) => {\n p.push(... Array.from(new Array(1 + N*2).fill('-')));\n p.push(c);\n return p;\n }, ['\\n+']).join('') + '\\n';\n\n a = a.reduce(function(p, c, i) {\n let d = i && !(i % U), G = i && !(i % N);\n i = !(i % (U * N));\n d && !i && (p += '|\\n| ');\n d && i && (p += '|');\n i && (p = '' + p + line + '| ');\n return '' + p + (G && !d ? '| ' : '') + getChar(c) + ' ';\n }, '') + '|' + line;\n console.log(a);\n\n};\n\n/**\n * Given a search solution, print the resultant grid.\n * @param {!Array} a An array of data objects\n */\nconst printSol = a => {\n printGrid(a.reduce((p, c) => {\n let [i, v] = c.V.split(':');\n p[i * 1] = v;\n return p;\n }, new Array(a.length).fill('.')));\n};\n\n//----------------------------------------------[ Grid to Exact cover Matrix ]--\n/**\n * Helper to get some meta about the grid.\n * @param {!string} s The standard string representation of a grid.\n * @return {!Array}\n */\nconst gridMeta = s => {\n const g = s.split('');\n const cellCount = g.length;\n const tokenCount = Math.sqrt(cellCount);\n const N = Math.sqrt(tokenCount);\n const g2D = g.map(e => isNaN(e * 1) ?\n new Array(tokenCount).fill(1).map((_, i) => i + 1) :\n [e * 1]);\n return [cellCount, N, tokenCount, g2D];\n};\n\n/**\n * Given a cell grid index, return the row, column and box indexes.\n * @param {!number} n The n-value of the grid. 3 for a 9x9 sudoku.\n * @return {!function(!number): !Array}\n */\nconst indexesN = n => i => {\n let c = Math.floor(i / (n * n));\n i %= n * n;\n return [c, i, Math.floor(c / n) * n + Math.floor(i / n)];\n};\n\n/**\n * Given a puzzle string, reduce it to an exact-cover matrix and use\n * Donald Knuth's DLX algorithm to solve it.\n * @param puzString\n */\nconst reduceGrid = puzString => {\n\n printGrid(puzString);\n const [\n numCells, // The total number of cells in a grid (81 for a 9x9 grid)\n N, // the 'n' value of the grid. (3 for a 9x9 grid)\n U, // The total number of unique tokens to be placed.\n g2D // A 2D array representation of the grid, with each element\n // being an array of candidates for a cell. Known cells are\n // single element arrays.\n ] = gridMeta(puzString);\n\n const getIndex = indexesN(N);\n\n /**\n * The DLX Header row.\n * Its length is 4 times the grid's size. This is to be able to encode\n * each of the 4 Sudoku constrains, onto each of the cells of the grid.\n * The array is initialised with unlinked DoX nodes, but in the next step\n * those nodes are all linked.\n * @type {!Array.}\n */\n const headRow = new Array(4 * numCells)\n .fill('')\n .map((_, i) => new DoX(`H${i}`));\n\n /**\n * The header row root object. This is circularly linked to be to the left\n * of the first header object in the header row array.\n * It is used as the entry point into the DLX algorithm.\n * @type {!DoX}\n */\n let H = new DoX('ROOT');\n headRow.reduce((p, c) => addRight(p, c), H);\n\n /**\n * Transposed the sudoku puzzle into a exact cover matrix, so it can be passed\n * to the DLX algorithm to solve.\n */\n for (let i = 0; i < numCells; i++) {\n const [ri, ci, bi] = getIndex(i);\n g2D[i].forEach(num => {\n let id = `${i}:${num}`;\n let candIdx = num - 1;\n\n // The 4 columns that we will populate.\n const A = headRow[i];\n const B = headRow[numCells + candIdx + (ri * U)];\n const C = headRow[(numCells * 2) + candIdx + (ci * U)];\n const D = headRow[(numCells * 3) + candIdx + (bi * U)];\n\n // The Row-Column Constraint\n let rcc = addBelow(A.U, new DoX(id, A));\n\n // The Row-Number Constraint\n let rnc = addBelow(B.U, addRight(rcc, new DoX(id, B)));\n\n // The Column-Number Constraint\n let cnc = addBelow(C.U, addRight(rnc, new DoX(id, C)));\n\n // The Block-Number Constraint\n addBelow(D.U, addRight(cnc, new DoX(id, D)));\n });\n }\n search(H, []);\n};\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sum and product of an array", + "type": "Waypoint", + "description": [ + "

    Compute the sum and product of an array of integers.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "var array = [1, 2, 3, 4, 5],", + " sum = 0,", + " prod = 1,", + " i;", + "for (i = 0; i < array.length; i += 1) {", + " sum += array[i];", + " prod *= array[i];", + "}", + "alert(sum + ' ' + prod);", + "", + "", + "{{Works with|Javascript|1.8}}", + "Where supported, the reduce method can also be used:", + "var array = [1, 2, 3, 4, 5],", + " sum = array.reduce(function (a, b) {", + " return a + b;", + " }, 0),", + " prod = array.reduce(function (a, b) {", + " return a * b;", + " }, 1);", + "alert(sum + ' ' + prod);", + "", + "===ES6===", + "(() => {", + " 'use strict';", + "", + " // sum :: (Num a) => [a] -> a", + " const sum = xs => xs.reduce((a, x) => a + x, 0);", + "", + " // product :: (Num a) => [a] -> a", + " const product = xs => xs.reduce((a, x) => a * x, 1);", + "", + "", + " // TEST", + " // show :: a -> String", + " const show = x => JSON.stringify(x, null, 2);", + "", + " return show(", + " [sum, product]", + " .map(f => f([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))", + " );", + "})();", + "", + "{{Out}}", + "
    [",
    +        "  55,",
    +        "  3628800",
    +        "]
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc803d", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var array = [1, 2, 3, 4, 5],\n sum = 0,\n prod = 1,\n i;\nfor (i = 0; i < array.length; i += 1) {\n sum += array[i];\n prod *= array[i];\n}\nalert(sum + ' ' + prod);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sum and Product Puzzle", + "type": "Waypoint", + "description": [ + "

    Solve the \"Impossible Puzzle\":

    {{quote|

    ", + "

    X and Y are two different whole numbers greater than 1. Their sum is no greater than 100, and Y is greater than X. S and P are two mathematicians (and consequently perfect logicians); S knows the sum X+Y and P knows the product X*Y. Both S and P know all the information in this paragraph.

    The following conversation occurs:

    S says \"P does not know X and Y.\"", + "P says \"Now I know X and Y.\"", + "S says \"Now I also know X and Y!\"", + "

    What are X and Y?

    ", + "

    }}

    ", + "

    It can be hard to wrap one's head around what the three lines of dialog between S (the \"sum guy\") and P (the \"product guy\") convey about the values of X and Y.

    ", + "

    So for your convenience, here's a break-down:

    {|

    ", + "

    |-

    ", + "

    !

    ", + "

    ! Quote

    ", + "

    ! Implied fact

    ", + "

    |-

    ", + "

    ! 1)

    ", + "

    | S says \"P does not know X and Y.\"

    ", + "

    | For every possible sum decomposition of the number X+Y, the product has in turn more than one product decomposition.

    ", + "

    |-

    ", + "

    ! 2)

    ", + "

    | P says \"Now I know X and Y.\"

    ", + "

    | The number X*Y has only one product decomposition for which fact 1 is true.

    ", + "

    |-

    ", + "

    ! 3)

    ", + "

    | S says \"Now I also know X and Y.\"

    ", + "

    | The number X+Y has only one sum decomposition for which fact 2 is true.

    ", + "

    |}

    Terminology:

    ", + "\"sum decomposition\" of a number = Any pair of positive integers (A, B) so that A+B equals the number. Here, with the additional constraint 2 ≤ A < B.", + "\"product decomposition\" of a number = Any pair of positive integers (A, B) so that A*B equals the number. Here, with the additional constraint 2 ≤ A < B.

    Your program can solve the puzzle by considering all possible pairs (X, Y) in the range 2 ≤ X < Y ≤ 98, and then successively eliminating candidates based on the three facts. It turns out only one solution remains!

    ", + "

    See the Python example for an implementation that uses this approach with a few optimizations.

    ", + " Wikipedia: Sum and Product Puzzle
    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "{{Trans|Haskell}}", + "(function () {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " var concatMap = function concatMap(f, xs) {", + " return [].concat.apply([], xs.map(f));", + " },", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " curry = function curry(f) {", + " return function (a) {", + " return function (b) {", + " return f(a, b);", + " };", + " };", + " },", + "", + " // intersectBy :: (a - > a - > Bool) - > [a] - > [a] - > [a]", + " intersectBy = function intersectBy(eq, xs, ys) {", + " return xs.length && ys.length ? xs.filter(function (x) {", + " return ys.some(curry(eq)(x));", + " }) : [];", + " },", + "", + " // range :: Int -> Int -> Maybe Int -> [Int]", + " range = function range(m, n, step) {", + " var d = (step || 1) * (n >= m ? 1 : -1);", + " return Array.from({", + " length: Math.floor((n - m) / d) + 1", + " }, function (_, i) {", + " return m + i * d;", + " });", + " };", + "", + " // PROBLEM FUNCTIONS", + "", + " // add, mul :: (Int, Int) -> Int", + " var add = function add(xy) {", + " return xy[0] + xy[1];", + " },", + " mul = function mul(xy) {", + " return xy[0] * xy[1];", + " };", + "", + " // sumEq, mulEq :: (Int, Int) -> [(Int, Int)]", + " var sumEq = function sumEq(p) {", + " var addP = add(p);", + " return s1.filter(function (q) {", + " return add(q) === addP;", + " });", + " },", + " mulEq = function mulEq(p) {", + " var mulP = mul(p);", + " return s1.filter(function (q) {", + " return mul(q) === mulP;", + " });", + " };", + "", + " // pairEQ :: ((a, a) -> (a, a)) -> Bool", + " var pairEQ = function pairEQ(a, b) {", + " return a[0] === b[0] && a[1] === b[1];", + " };", + "", + " // MAIN", + "", + " // xs :: [Int]", + " var xs = range(1, 100);", + "", + " // s1 s2, s3, s4 :: [(Int, Int)]", + " var s1 = concatMap(function (x) {", + " return concatMap(function (y) {", + " return 1 < x && x < y && x + y < 100 ? [", + " [x, y]", + " ] : [];", + " }, xs);", + " }, xs),", + "", + " s2 = s1.filter(function (p) {", + " return sumEq(p).every(function (q) {", + " return mulEq(q).length > 1;", + " });", + " }),", + "", + " s3 = s2.filter(function (p) {", + " return intersectBy(pairEQ, mulEq(p), s2).length === 1;", + " }),", + "", + " s4 = s3.filter(function (p) {", + " return intersectBy(pairEQ, sumEq(p), s3).length === 1;", + " });", + "", + " return s4;", + "})();", + "", + "", + "{{Out}}", + "[[4, 13]]", + "(Finished in 0.69s)", + "", + "", + "===ES6===", + "", + "{{Trans|Haskell}}", + "(() => {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " let concatMap = (f, xs) => [].concat.apply([], xs.map(f)),", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " curry = f => a => b => f(a, b),", + "", + " // intersectBy :: (a - > a - > Bool) - > [a] - > [a] - > [a]", + " intersectBy = (eq, xs, ys) => (xs.length && ys.length) ?", + " xs.filter(x => ys.some(curry(eq)(x))) : [],", + "", + " // range :: Int -> Int -> Maybe Int -> [Int]", + " range = (m, n, step) => {", + " let d = (step || 1) * (n >= m ? 1 : -1);", + " return Array.from({", + " length: Math.floor((n - m) / d) + 1", + " }, (_, i) => m + (i * d));", + " };", + "", + " // PROBLEM FUNCTIONS", + "", + " // add, mul :: (Int, Int) -> Int", + " let add = xy => xy[0] + xy[1],", + " mul = xy => xy[0] * xy[1];", + "", + " // sumEq, mulEq :: (Int, Int) -> [(Int, Int)]", + " let sumEq = p => {", + " let addP = add(p);", + " return s1.filter(q => add(q) === addP);", + " },", + " mulEq = p => {", + " let mulP = mul(p)", + " return s1.filter(q => mul(q) === mulP);", + " };", + "", + " // pairEQ :: ((a, a) -> (a, a)) -> Bool", + " let pairEQ = (a, b) => (a[0] === b[0]) && (a[1] === b[1]);", + "", + "", + " // MAIN", + "", + " // xs :: [Int]", + " let xs = range(1, 100);", + "", + " // s1 s2, s3, s4 :: [(Int, Int)]", + " let s1 = concatMap(x =>", + " concatMap(y =>", + " ((1 < x) && (x < y) && (x + y) < 100) ? [", + " [x, y]", + " ] : [],", + " xs), xs),", + " s2 = s1.filter(", + " p => sumEq(p)", + " .every(", + " q => mulEq(q)", + " .length > 1", + " )", + " ),", + " s3 = s2.filter(", + " p => intersectBy(", + " pairEQ, mulEq(p), s2", + " )", + " .length === 1", + " );", + "", + " return s3.filter(", + " p => intersectBy(", + " pairEQ, sumEq(p), s3", + " )", + " .length === 1", + " );", + "", + "})();", + "", + "{{Out}}", + "[[4, 13]]", + "(Finished in 0.77s)", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc803e", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function () {\n 'use strict';\n\n // GENERIC FUNCTIONS\n\n // concatMap :: (a -> [b]) -> [a] -> [b]\n var concatMap = function concatMap(f, xs) {\n return [].concat.apply([], xs.map(f));\n },\n\n // curry :: ((a, b) -> c) -> a -> b -> c\n curry = function curry(f) {\n return function (a) {\n return function (b) {\n return f(a, b);\n };\n };\n },\n\n // intersectBy :: (a - > a - > Bool) - > [a] - > [a] - > [a]\n intersectBy = function intersectBy(eq, xs, ys) {\n return xs.length && ys.length ? xs.filter(function (x) {\n return ys.some(curry(eq)(x));\n }) : [];\n },\n\n // range :: Int -> Int -> Maybe Int -> [Int]\n range = function range(m, n, step) {\n var d = (step || 1) * (n >= m ? 1 : -1);\n return Array.from({\n length: Math.floor((n - m) / d) + 1\n }, function (_, i) {\n return m + i * d;\n });\n };\n\n // PROBLEM FUNCTIONS\n\n // add, mul :: (Int, Int) -> Int\n var add = function add(xy) {\n return xy[0] + xy[1];\n },\n mul = function mul(xy) {\n return xy[0] * xy[1];\n };\n\n // sumEq, mulEq :: (Int, Int) -> [(Int, Int)]\n var sumEq = function sumEq(p) {\n var addP = add(p);\n return s1.filter(function (q) {\n return add(q) === addP;\n });\n },\n mulEq = function mulEq(p) {\n var mulP = mul(p);\n return s1.filter(function (q) {\n return mul(q) === mulP;\n });\n };\n\n // pairEQ :: ((a, a) -> (a, a)) -> Bool\n var pairEQ = function pairEQ(a, b) {\n return a[0] === b[0] && a[1] === b[1];\n };\n\n // MAIN\n\n // xs :: [Int]\n var xs = range(1, 100);\n\n // s1 s2, s3, s4 :: [(Int, Int)]\n var s1 = concatMap(function (x) {\n return concatMap(function (y) {\n return 1 < x && x < y && x + y < 100 ? [\n [x, y]\n ] : [];\n }, xs);\n }, xs),\n\n s2 = s1.filter(function (p) {\n return sumEq(p).every(function (q) {\n return mulEq(q).length > 1;\n });\n }),\n\n s3 = s2.filter(function (p) {\n return intersectBy(pairEQ, mulEq(p), s2).length === 1;\n }),\n\n s4 = s3.filter(function (p) {\n return intersectBy(pairEQ, sumEq(p), s3).length === 1;\n });\n\n return s4;\n})();\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sum digits of an integer", + "type": "Waypoint", + "description": [ + "Task:", + "

    Take a Natural Number in a given base and return the sum of its digits:

    ", + "

    * 110 sums to 1

    ", + "

    * 123410 sums to 10

    ", + "

    * fe16 sums to 29

    ", + "

    * f0e16 sums to 29

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===Imperative===", + "", + "function sumDigits(n) {", + "\tn += ''", + "\tfor (var s=0, i=0, e=n.length; i')", + "", + "{{out}}", + "
    ",
    +        "1 sum to 1",
    +        "12345 sum to 15",
    +        "254 sum to 11",
    +        "fe sum to 29",
    +        "f0e sum to 29",
    +        "999ABCXYZ sum to 162",
    +        "
    ", + "", + "===Functional (ES 5)===", + "", + "(function () {", + " 'use strict';", + "", + " // digitsSummed :: (Int | String) -> Int", + " function digitsSummed(number) {", + " ", + " // 10 digits + 26 alphabetics", + " // give us glyphs for up to base 36", + " var intMaxBase = 36;", + " ", + " return number", + " .toString()", + " .split('')", + " .reduce(function (a, digit) { ", + " return a + parseInt(digit, intMaxBase);", + " }, 0);", + " }", + "", + " // TEST", + "", + " return [1, 12345, 0xfe, 'fe', 'f0e', '999ABCXYZ']", + " .map(function (x) {", + " return x + ' -> ' + digitsSummed(x);", + " })", + " .join('\\n');", + "", + "})();", + "", + "", + "", + "
    1 -> 1",
    +        "12345 -> 15",
    +        "254 -> 11",
    +        "fe -> 29",
    +        "f0e -> 29",
    +        "999ABCXYZ -> 162
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc803f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function sumDigits(n) {\n\tn += ''\n\tfor (var s=0, i=0, e=n.length; i')\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sum multiples of 3 and 5", + "type": "Waypoint", + "description": [ + "Task:", + "

    The objective is to write a function that finds the sum of all positive multiples of 3 or 5 below n.

    Show output for n = 1000.

    ", + "

    Extra credit: do this efficiently for n = 1e20 or higher.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "", + "JavaScript is better equipped for flexibility than for scale. The value of Number.MAX_SAFE_INTEGER is 9007199254740991, or 2^53 - 1 – resulting from an IEEE 754 double-precision floating point representation of numeric values).", + "", + "As ''Number.MAX_SAFE_INTEGER < 1E20'' evaluates to ''true'', the most obvious JS attack on a solution for 1E20 might involve some string processing … ", + "", + "At more modest scales, however, we can generalise a little to allow for an arbitrary list of integer factors, and write a simple generate, filter and sum approach:", + "", + "(function (lstFactors, intExponent) {", + "", + " // [n] -> n -> n", + " function sumMultiplesBelow(lstIntegers, limit) {", + " return range(1, limit - 1).filter(function (x) {", + " return isMultiple(lstIntegers, x);", + " }).reduce(function (a, n) {", + " return a + n;", + " }, 0)", + " }", + "", + " // [n] -> n -> bool", + " function isMultiple(lst, n) {", + " var i = lng;", + " while (i--)", + " if (n % (lst[i]) === 0) return true;", + " return false;", + " }", + "", + " // [m..n]", + " function range(m, n) {", + " var a = Array(n - m + 1),", + " i = n + 1;", + " while (i--) a[i - 1] = i;", + " return a;", + " }", + "", + "", + " /* TESTING */", + "", + " // [[a]] -> bool -> s -> s", + " function wikiTable(lstRows, blnHeaderRow, strStyle) {", + " return '{| class=\"wikitable\" ' + (", + " strStyle ? 'style=\"' + strStyle + '\"' : ''", + " ) + lstRows.map(function (lstRow, iRow) {", + " var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|');", + "", + " return '\\n|-\\n' + strDelim + ' ' + lstRow.map(function (v) {", + " return typeof v === 'undefined' ? ' ' : v;", + " }).join(' ' + strDelim + strDelim + ' ');", + " }).join('') + '\\n|}';", + " }", + "", + " var lng = lstFactors.length,", + " lstSorted = lstFactors.slice(0).sort();", + "", + " var lstTable = [['Below', 'Sum']].concat(", + " range(1, intExponent).map(function (x) {", + " var pwr = Math.pow(10, x);", + "", + " return ['10^' + x, sumMultiplesBelow(lstSorted, pwr)];", + " })", + " );", + "", + " return 'For ' + JSON.stringify(lstFactors) + ':\\n\\n' +", + " wikiTable(lstTable, true) + '\\n\\n' +", + " JSON.stringify(lstTable);", + "", + "})([3, 5], 8);", + "", + "", + "For [3,5]:", + "", + "{| class=\"wikitable\" ", + "|-", + "! Below !! Sum", + "|-", + "| 10^1 || 23", + "|-", + "| 10^2 || 2318", + "|-", + "| 10^3 || 233168", + "|-", + "| 10^4 || 23331668", + "|-", + "| 10^5 || 2333316668", + "|-", + "| 10^6 || 233333166668", + "|-", + "| 10^7 || 23333331666668", + "|-", + "| 10^8 || 2333333316666668", + "|}", + "", + " [[\"Below\",\"Sum\"],[\"10^1\",23],[\"10^2\",2318],[\"10^3\",233168],", + " [\"10^4\",23331668],[\"10^5\",2333316668],[\"10^6\",233333166668],", + " [\"10^7\",23333331666668],[\"10^8\",2333333316666668]]", + "====With wheel increments====", + "function sm35(n){", + "\tvar s=0, inc=[3,2,1,3,1,2,3]", + "\tfor (var j=6, i=0; i", + "====With triangular numbers====", + "function sm35(n){", + "\treturn tri(n,3) + tri(n,5) - tri(n,15)", + "\tfunction tri(n, f) {", + "\t\tn = Math.floor((n-1) / f)", + "\t\treturn f * n * (n+1) / 2", + "\t}", + "}", + "'''This:'''", + "for (var i=1, n=10; i<9; n*=10, i+=1) {", + "\tdocument.write(10, '', i, ' ', sm35(n), '
    ')", + "}
    ", + "{{out}}", + " 101 23", + " 102 2318", + " 103 233168", + " 104 23331668", + " 105 2333316668", + " 106 233333166668", + " 107 23333331666668", + " 108 2333333316666668", + "", + "", + "===ES6===", + "", + "(() => {", + "", + " // Area under straight line", + " // between first multiple and last.", + "", + " // sumMults :: Int -> Int -> Int", + " const sumMults = (n, factor) => {", + " const n1 = quot(n - 1, factor);", + " return quot(factor * n1 * (n1 + 1), 2);", + " };", + "", + " // sum35 :: Int -> Int", + " const sum35 = n => sumMults(n, 3) + sumMults(n, 5) - sumMults(n, 15);", + "", + "", + " // GENERIC ----------------------------------------------------------------", + "", + " // enumFromTo :: Int -> Int -> [Int]", + " const enumFromTo = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // Integral a => a -> a -> a", + " const quot = (n, m) => Math.floor(n / m);", + "", + " // TEST -------------------------------------------------------------------", + "", + " // Sums for 10^1 thru 10^8", + " return enumFromTo(1, 8)", + " .map(n => Math.pow(10, n))", + " .reduce((a, x) => (", + " a[x.toString()] = sum35(x),", + " a", + " ), {});", + "})();", + "{{Out}}", + "{\"10\":23, \"100\":2318, \"1000\":233168, \"10000\":23331668,", + "\"100000\":2333316668, \"1000000\":233333166668, \"10000000\":23333331666668,", + "\"100000000\":2333333316666668}", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8040", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + " Number.MAX_SAFE_INTEGER\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sum of a series", + "type": "Waypoint", + "description": [ + "

    Compute the nth term of a series, i.e. the sum of the n first terms of the corresponding sequence.

    Informally this value, or its limit when n tends to infinity, is also called the sum of the series, thus the title of this task.

    For this task, use:

    ", + "

    ::::: $S_n = \\sum_{k=1}^n \\frac{1}{k^2}$

    ", + "

    : and compute $S_{1000}$

    ", + "

    This approximates the zeta function for S=2, whose exact value

    ::::: $\\zeta(2) = {\\pi^2\\over 6}$

    is the solution of the Basel problem.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "function sum(a,b,fn) {", + " var s = 0;", + " for ( ; a <= b; a++) s += fn(a);", + " return s;", + "}", + " ", + " sum(1,1000, function(x) { return 1/(x*x) } ) // 1.64393456668156", + "", + "or, in a functional idiom:", + "", + "(function () {", + "", + " function sum(fn, lstRange) {", + " return lstRange.reduce(", + " function (lngSum, x) {", + " return lngSum + fn(x);", + " }, 0", + " );", + " }", + "", + " function range(m, n) {", + " return Array.apply(null, Array(n - m + 1)).map(function (x, i) {", + " return m + i;", + " });", + " }", + "", + "", + " return sum(", + " function (x) {", + " return 1 / (x * x);", + " },", + " range(1, 1000)", + " );", + "", + "})();", + "", + "{{Out}}", + "", + "1.6439345666815615", + "", + "===ES6===", + "{{Trans|Haskell}}", + "(() => {", + " 'use strict';", + "", + " // seriesSum :: Num a => (a -> a) -> [a] -> a", + " const seriesSum = (f, xs) =>", + " xs.reduce((a, x) => a + f(x), 0);", + "", + "", + " // GENERIC ------------------------------------------", + "", + " // range :: Int -> Int -> [Int]", + " const range = (m, n) =>", + " Array.from({", + " length: Math.floor(n - m) + 1", + " }, (_, i) => m + i);", + "", + " // TEST ----------------------------------------------", + "", + " return seriesSum(x => 1 / (x * x), range(1, 1000));", + "})();", + "", + "{{Out}}", + "1.6439345666815615", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8041", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function sum(a,b,fn) {\n var s = 0;\n for ( ; a <= b; a++) s += fn(a);\n return s;\n}\n \n sum(1,1000, function(x) { return 1/(x*x) } ) // 1.64393456668156\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sum of squares", + "type": "Waypoint", + "description": [ + "Task:", + "

    Write a program to find the sum of squares of a numeric vector.

    The program should work on a zero-length vector (with an answer of 0).

    ", + "Related task:", + " Mean" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "function sumsq(array) {", + " var sum = 0;", + " var i, iLen;", + "", + " for (i = 0, iLen = array.length; i < iLen; i++) {", + " sum += array[i] * array[i];", + " }", + " return sum;", + "}", + "", + "alert(sumsq([1,2,3,4,5])); // 55", + "", + "An alternative using a while loop and Math.pow", + "", + "function sumsq(array) {", + " var sum = 0, ", + " i = array.length;", + "", + " while (i--) sum += Math.pow(array[i], 2);", + "", + " return sum;", + "}", + "", + "alert(sumsq([1,2,3,4,5])); // 55", + "", + "", + "{{libheader|Functional}}Functional.reduce(\"x+y*y\", 0, [1,2,3,4,5])", + "", + "map (JS 1.6) and reduce (JS 1.8)", + "", + "[3,1,4,1,5,9].map(function (n) { return Math.pow(n,2); }).reduce(function (sum,n) { return sum+n; });", + "", + "===ES6===", + "", + "Two ways of composing a sumOfSquares function", + "(() => {", + " 'use strict';", + "", + " // squared :: Num a => a -> a", + " const squared = x => Math.pow(x, 2);", + "", + " // sum :: (Num a) => [a] -> a", + " const sum = xs => xs.reduce((a, x) => a + x, 0);", + "", + " // sumOfSquares :: Num a => [a] -> a", + " const sumOfSquares = xs => sum(xs.map(squared));", + "", + " // sumOfSquares2 :: Num a => [a] -> a", + " const sumOfSquares2 = xs =>", + " xs.reduce((a, x) => a + squared(x), 0);", + "", + " return [sumOfSquares, sumOfSquares2]", + " .map(f => f([3, 1, 4, 1, 5, 9]))", + " .join('\\n');", + "})();", + "", + "{{Out}}", + "
    133",
    +        "133
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8042", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function sumsq(array) {\n var sum = 0;\n var i, iLen;\n\n for (i = 0, iLen = array.length; i < iLen; i++) {\n sum += array[i] * array[i];\n }\n return sum;\n}\n\nalert(sumsq([1,2,3,4,5])); // 55\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sum to 100", + "type": "Waypoint", + "description": [ + "Task:", + "

    Find solutions to the sum to one hundred puzzle.

    ", + "

    Add (insert) the mathematical

    ", + "

    operators + or (plus

    ", + "

    or minus) before any of the digits in the

    ", + "decimal numeric string 123456789 such that the", + "

    resulting mathematical expression adds up to a

    ", + "particular sum (in this iconic case, 100).", + "

    Example:

    ", + "

    123 + 4 - 5 + 67 - 89 = 100

    Show all output here.

    ", + "

    * Show all solutions that sum to 100

    ", + "

    * Show the sum that has the maximum number of solutions (from zero to infinity*)

    ", + "

    * Show the lowest positive sum that can't be expressed (has no solutions), using the rules for this task

    ", + "

    * Show the ten highest numbers that can be expressed using the rules for this task (extra credit)

    ", + "

    An example of a sum that can't be expressed (within the rules of this task) is: 5074

    ", + "which, of course, is not the lowest positive sum that can't be expressed.", + "

    * (where infinity would be a relatively small 123,456,789)

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "{{Trans|Haskell}}", + "(function () {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS ----------------------------------------------------", + "", + " // permutationsWithRepetition :: Int -> [a] -> [[a]]", + " var permutationsWithRepetition = function (n, as) {", + " return as.length > 0 ?", + " foldl1(curry(cartesianProduct)(as), replicate(n, as)) : [];", + " };", + "", + " // cartesianProduct :: [a] -> [b] -> [[a, b]]", + " var cartesianProduct = function (xs, ys) {", + " return [].concat.apply([], xs.map(function (x) {", + " return [].concat.apply([], ys.map(function (y) {", + " return [", + " [x].concat(y)", + " ];", + " }));", + " }));", + " };", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " var curry = function (f) {", + " return function (a) {", + " return function (b) {", + " return f(a, b);", + " };", + " };", + " };", + "", + " // flip :: (a -> b -> c) -> b -> a -> c", + " var flip = function (f) {", + " return function (a, b) {", + " return f.apply(null, [b, a]);", + " };", + " };", + "", + " // foldl1 :: (a -> a -> a) -> [a] -> a", + " var foldl1 = function (f, xs) {", + " return xs.length > 0 ? xs.slice(1)", + " .reduce(f, xs[0]) : [];", + " };", + "", + " // replicate :: Int -> a -> [a]", + " var replicate = function (n, a) {", + " var v = [a],", + " o = [];", + " if (n < 1) return o;", + " while (n > 1) {", + " if (n & 1) o = o.concat(v);", + " n >>= 1;", + " v = v.concat(v);", + " }", + " return o.concat(v);", + " };", + "", + " // group :: Eq a => [a] -> [[a]]", + " var group = function (xs) {", + " return groupBy(function (a, b) {", + " return a === b;", + " }, xs);", + " };", + "", + " // groupBy :: (a -> a -> Bool) -> [a] -> [[a]]", + " var groupBy = function (f, xs) {", + " var dct = xs.slice(1)", + " .reduce(function (a, x) {", + " var h = a.active.length > 0 ? a.active[0] : undefined,", + " blnGroup = h !== undefined && f(h, x);", + "", + " return {", + " active: blnGroup ? a.active.concat(x) : [x],", + " sofar: blnGroup ? a.sofar : a.sofar.concat([a.active])", + " };", + " }, {", + " active: xs.length > 0 ? [xs[0]] : [],", + " sofar: []", + " });", + " return dct.sofar.concat(dct.active.length > 0 ? [dct.active] : []);", + " };", + "", + " // compare :: a -> a -> Ordering", + " var compare = function (a, b) {", + " return a < b ? -1 : a > b ? 1 : 0;", + " };", + "", + " // on :: (b -> b -> c) -> (a -> b) -> a -> a -> c", + " var on = function (f, g) {", + " return function (a, b) {", + " return f(g(a), g(b));", + " };", + " };", + "", + " // nub :: [a] -> [a]", + " var nub = function (xs) {", + " return nubBy(function (a, b) {", + " return a === b;", + " }, xs);", + " };", + "", + " // nubBy :: (a -> a -> Bool) -> [a] -> [a]", + " var nubBy = function (p, xs) {", + " var x = xs.length ? xs[0] : undefined;", + "", + " return x !== undefined ? [x].concat(nubBy(p, xs.slice(1)", + " .filter(function (y) {", + " return !p(x, y);", + " }))) : [];", + " };", + "", + " // find :: (a -> Bool) -> [a] -> Maybe a", + " var find = function (f, xs) {", + " for (var i = 0, lng = xs.length; i < lng; i++) {", + " if (f(xs[i], i)) return xs[i];", + " }", + " return undefined;", + " };", + "", + " // Int -> [a] -> [a]", + " var take = function (n, xs) {", + " return xs.slice(0, n);", + " };", + "", + " // unlines :: [String] -> String", + " var unlines = function (xs) {", + " return xs.join('\\n');", + " };", + "", + " // show :: a -> String", + " var show = function (x) {", + " return JSON.stringify(x);", + " }; //, null, 2);", + "", + " // head :: [a] -> a", + " var head = function (xs) {", + " return xs.length ? xs[0] : undefined;", + " };", + "", + " // tail :: [a] -> [a]", + " var tail = function (xs) {", + " return xs.length ? xs.slice(1) : undefined;", + " };", + "", + " // length :: [a] -> Int", + " var length = function (xs) {", + " return xs.length;", + " };", + "", + " // SIGNED DIGIT SEQUENCES (mapped to sums and to strings)", + "", + " // data Sign :: [ 0 | 1 | -1 ] = ( Unsigned | Plus | Minus )", + " // asSum :: [Sign] -> Int", + " var asSum = function (xs) {", + " var dct = xs.reduceRight(function (a, sign, i) {", + " var d = i + 1; // zero-based index to [1-9] positions", + " if (sign !== 0) {", + " // Sum increased, digits cleared", + " return {", + " digits: [],", + " n: a.n + sign * parseInt([d].concat(a.digits)", + " .join(''), 10)", + " };", + " } else return { // Digits extended, sum unchanged", + " digits: [d].concat(a.digits),", + " n: a.n", + " };", + " }, {", + " digits: [],", + " n: 0", + " });", + " return dct.n + (", + " dct.digits.length > 0 ? parseInt(dct.digits.join(''), 10) : 0", + " );", + " };", + "", + " // data Sign :: [ 0 | 1 | -1 ] = ( Unsigned | Plus | Minus )", + " // asString :: [Sign] -> String", + " var asString = function (xs) {", + " var ns = xs.reduce(function (a, sign, i) {", + " var d = (i + 1)", + " .toString();", + " return sign === 0 ? a + d : a + (sign > 0 ? ' +' : ' -') + d;", + " }, '');", + "", + " return ns[0] === '+' ? tail(ns) : ns;", + " };", + "", + " // SUM T0 100 ------------------------------------------------------------", + "", + " // universe :: [[Sign]]", + " var universe = permutationsWithRepetition(9, [0, 1, -1])", + " .filter(function (x) {", + " return x[0] !== 1;", + " });", + "", + " // allNonNegativeSums :: [Int]", + " var allNonNegativeSums = universe.map(asSum)", + " .filter(function (x) {", + " return x >= 0;", + " })", + " .sort();", + "", + " // uniqueNonNegativeSums :: [Int]", + " var uniqueNonNegativeSums = nub(allNonNegativeSums);", + "", + " return [\"Sums to 100:\\n\", unlines(universe.filter(function (x) {", + " return asSum(x) === 100;", + " })", + " .map(asString)),", + "", + " \"\\n\\n10 commonest sums (sum, followed by number of routes to it):\\n\",", + " show(take(10, group(allNonNegativeSums)", + " .sort(on(flip(compare), length))", + " .map(function (xs) {", + " return [xs[0], xs.length];", + " }))),", + "", + " \"\\n\\nFirst positive integer not expressible as a sum of this kind:\\n\",", + " show(find(function (x, i) {", + " return x !== i;", + " }, uniqueNonNegativeSums.sort(compare)) - 1), // zero-based index", + "", + " \"\\n10 largest sums:\\n\",", + " show(take(10, uniqueNonNegativeSums.sort(flip(compare))))", + " ].join('\\n') + '\\n';", + "})();", + "", + "{{Out}}", + "(Run in Atom editor, through Script package)", + "
    Sums to 100:",
    +        "",
    +        "123 +45 -67 +8 -9",
    +        "123 +4 -5 +67 -89",
    +        "123 -45 -67 +89",
    +        "123 -4 -5 -6 -7 +8 -9",
    +        "12 +3 +4 +5 -6 -7 +89",
    +        "12 +3 -4 +5 +67 +8 +9",
    +        "12 -3 -4 +5 -6 +7 +89",
    +        "1 +23 -4 +56 +7 +8 +9",
    +        "1 +23 -4 +5 +6 +78 -9",
    +        "1 +2 +34 -5 +67 -8 +9",
    +        "1 +2 +3 -4 +5 +6 +78 +9",
    +        " -1 +2 -3 +4 +5 +6 +78 +9",
    +        "",
    +        "",
    +        "10 commonest sums (sum, followed by number of routes to it):",
    +        "",
    +        "[[9,46],[27,44],[1,43],[15,43],[21,43],[45,42],[3,41],[5,40],[17,39],[7,39]]",
    +        "",
    +        "",
    +        "First positive integer not expressible as a sum of this kind:",
    +        "",
    +        "211",
    +        "",
    +        "10 largest sums:",
    +        "",
    +        "[123456789,23456790,23456788,12345687,12345669,3456801,3456792,3456790,3456788,3456786]",
    +        "",
    +        "[Finished in 0.381s]
    ", + "", + "===ES6===", + "{{Trans|Haskell}}", + "(() => {", + " 'use strict';", + "", + " // GENERIC FUNCTIONS ----------------------------------------------------", + "", + " // permutationsWithRepetition :: Int -> [a] -> [[a]]", + " const permutationsWithRepetition = (n, as) =>", + " as.length > 0 ? (", + " foldl1(curry(cartesianProduct)(as), replicate(n, as))", + " ) : [];", + "", + " // cartesianProduct :: [a] -> [b] -> [[a, b]]", + " const cartesianProduct = (xs, ys) =>", + " [].concat.apply([], xs.map(x =>", + " [].concat.apply([], ys.map(y => [[x].concat(y)]))));", + "", + " // curry :: ((a, b) -> c) -> a -> b -> c", + " const curry = f => a => b => f(a, b);", + "", + " // flip :: (a -> b -> c) -> b -> a -> c", + " const flip = f => (a, b) => f.apply(null, [b, a]);", + "", + " // foldl1 :: (a -> a -> a) -> [a] -> a", + " const foldl1 = (f, xs) =>", + " xs.length > 0 ? xs.slice(1)", + " .reduce(f, xs[0]) : [];", + "", + " // replicate :: Int -> a -> [a]", + " const replicate = (n, a) => {", + " let v = [a],", + " o = [];", + " if (n < 1) return o;", + " while (n > 1) {", + " if (n & 1) o = o.concat(v);", + " n >>= 1;", + " v = v.concat(v);", + " }", + " return o.concat(v);", + " };", + "", + " // group :: Eq a => [a] -> [[a]]", + " const group = xs => groupBy((a, b) => a === b, xs);", + "", + " // groupBy :: (a -> a -> Bool) -> [a] -> [[a]]", + " const groupBy = (f, xs) => {", + " const dct = xs.slice(1)", + " .reduce((a, x) => {", + " const", + " h = a.active.length > 0 ? a.active[0] : undefined,", + " blnGroup = h !== undefined && f(h, x);", + "", + " return {", + " active: blnGroup ? a.active.concat(x) : [x],", + " sofar: blnGroup ? a.sofar : a.sofar.concat([a.active])", + " };", + " }, {", + " active: xs.length > 0 ? [xs[0]] : [],", + " sofar: []", + " });", + " return dct.sofar.concat(dct.active.length > 0 ? [dct.active] : []);", + " };", + "", + " // compare :: a -> a -> Ordering", + " const compare = (a, b) => a < b ? -1 : (a > b ? 1 : 0);", + "", + " // on :: (b -> b -> c) -> (a -> b) -> a -> a -> c", + " const on = (f, g) => (a, b) => f(g(a), g(b));", + "", + " // nub :: [a] -> [a]", + " const nub = xs => nubBy((a, b) => a === b, xs);", + "", + " // nubBy :: (a -> a -> Bool) -> [a] -> [a]", + " const nubBy = (p, xs) => {", + " const x = xs.length ? xs[0] : undefined;", + "", + " return x !== undefined ? [x].concat(", + " nubBy(p, xs.slice(1)", + " .filter(y => !p(x, y)))", + " ) : [];", + " };", + "", + " // find :: (a -> Bool) -> [a] -> Maybe a", + " const find = (f, xs) => {", + " for (var i = 0, lng = xs.length; i < lng; i++) {", + " if (f(xs[i], i)) return xs[i];", + " }", + " return undefined;", + " }", + "", + " // Int -> [a] -> [a]", + " const take = (n, xs) => xs.slice(0, n);", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x); //, null, 2);", + "", + " // head :: [a] -> a", + " const head = xs => xs.length ? xs[0] : undefined;", + "", + " // tail :: [a] -> [a]", + " const tail = xs => xs.length ? xs.slice(1) : undefined;", + "", + " // length :: [a] -> Int", + " const length = xs => xs.length;", + "", + "", + " // SIGNED DIGIT SEQUENCES (mapped to sums and to strings)", + "", + " // data Sign :: [ 0 | 1 | -1 ] = ( Unsigned | Plus | Minus )", + " // asSum :: [Sign] -> Int", + " const asSum = xs => {", + " const dct = xs.reduceRight((a, sign, i) => {", + " const d = i + 1; // zero-based index to [1-9] positions", + " if (sign !== 0) { // Sum increased, digits cleared", + " return {", + " digits: [],", + " n: a.n + (sign * parseInt([d].concat(a.digits)", + " .join(''), 10))", + " };", + " } else return { // Digits extended, sum unchanged", + " digits: [d].concat(a.digits),", + " n: a.n", + " };", + " }, {", + " digits: [],", + " n: 0", + " });", + " return dct.n + (dct.digits.length > 0 ? (", + " parseInt(dct.digits.join(''), 10)", + " ) : 0);", + " };", + "", + " // data Sign :: [ 0 | 1 | -1 ] = ( Unsigned | Plus | Minus )", + " // asString :: [Sign] -> String", + " const asString = xs => {", + " const ns = xs.reduce((a, sign, i) => {", + " const d = (i + 1)", + " .toString();", + " return (sign === 0 ? (", + " a + d", + " ) : (a + (sign > 0 ? ' +' : ' -') + d));", + " }, '');", + "", + " return ns[0] === '+' ? tail(ns) : ns;", + " };", + "", + "", + " // SUM T0 100 ------------------------------------------------------------", + "", + " // universe :: [[Sign]]", + " const universe = permutationsWithRepetition(9, [0, 1, -1])", + " .filter(x => x[0] !== 1);", + "", + " // allNonNegativeSums :: [Int]", + " const allNonNegativeSums = universe.map(asSum)", + " .filter(x => x >= 0)", + " .sort();", + "", + " // uniqueNonNegativeSums :: [Int]", + " const uniqueNonNegativeSums = nub(allNonNegativeSums);", + "", + "", + " return [", + " \"Sums to 100:\\n\",", + " unlines(universe.filter(x => asSum(x) === 100)", + " .map(asString)),", + "", + " \"\\n\\n10 commonest sums (sum, followed by number of routes to it):\\n\",", + " show(take(10, group(allNonNegativeSums)", + " .sort(on(flip(compare), length))", + " .map(xs => [xs[0], xs.length]))),", + "", + " \"\\n\\nFirst positive integer not expressible as a sum of this kind:\\n\",", + " show(find(", + " (x, i) => x !== i,", + " uniqueNonNegativeSums.sort(compare)", + " ) - 1), // i is the the zero-based Array index.", + "", + " \"\\n10 largest sums:\\n\",", + " show(take(10, uniqueNonNegativeSums.sort(flip(compare))))", + " ].join('\\n') + '\\n';", + "})();", + "", + "{{Out}}", + "(Run in Atom editor, through Script package)", + "
    Sums to 100:",
    +        "",
    +        "123 +45 -67 +8 -9",
    +        "123 +4 -5 +67 -89",
    +        "123 -45 -67 +89",
    +        "123 -4 -5 -6 -7 +8 -9",
    +        "12 +3 +4 +5 -6 -7 +89",
    +        "12 +3 -4 +5 +67 +8 +9",
    +        "12 -3 -4 +5 -6 +7 +89",
    +        "1 +23 -4 +56 +7 +8 +9",
    +        "1 +23 -4 +5 +6 +78 -9",
    +        "1 +2 +34 -5 +67 -8 +9",
    +        "1 +2 +3 -4 +5 +6 +78 +9",
    +        " -1 +2 -3 +4 +5 +6 +78 +9",
    +        "",
    +        "",
    +        "10 commonest sums (sum, followed by number of routes to it):",
    +        "",
    +        "[[9,46],[27,44],[1,43],[15,43],[21,43],[45,42],[3,41],[5,40],[17,39],[7,39]]",
    +        "",
    +        "",
    +        "First positive integer not expressible as a sum of this kind:",
    +        "",
    +        "211",
    +        "",
    +        "10 largest sums:",
    +        "",
    +        "[123456789,23456790,23456788,12345687,12345669,3456801,3456792,3456790,3456788,3456786]",
    +        "",
    +        "[Finished in 0.382s]
    ", + "", + "===ES3 (JScript)===", + "{{Works with|Microsoft Windows Script Host}}", + "{{Trans|AWK}}", + "SumTo100();", + "", + "function SumTo100()", + "{ ", + " var ", + " ADD = 0, ", + " SUB = 1, ", + " JOIN = 2;", + " ", + " var ", + " nexpr = 13122; ", + "", + " function out(something) ", + " { ", + " WScript.Echo(something); ", + " }", + "", + " function evaluate(code)", + " {", + " var ", + " value = 0, ", + " number = 0, ", + " power = 1;", + "", + " for ( var k = 9; k >= 1; k-- )", + " {", + " number = power*k + number;", + " switch( code % 3 )", + " {", + " case ADD: value = value + number; number = 0; power = 1; break;", + " case SUB: value = value - number; number = 0; power = 1; break;", + " case JOIN: power = power * 10 ; break;", + " }", + " code = Math.floor(code/3);", + " }", + " return value; ", + " }", + "", + " function print(code)", + " {", + " var ", + " s = \"\";", + " var ", + " a = 19683,", + " b = 6561; ", + " ", + " for ( var k = 1; k <= 9; k++ )", + " {", + " switch( Math.floor( (code % a) / b ) ){", + " case ADD: if ( k > 1 ) s = s + '+'; break;", + " case SUB: s = s + '-'; break;", + " }", + " a = b;", + " b = Math.floor(b/3);", + " s = s + String.fromCharCode(0x30+k);", + " } ", + " out(evaluate(code) + \" = \" + s);", + " }", + " ", + " function comment(commentString)", + " {", + " out(\"\");", + " out(commentString);", + " out(\"\"); ", + " }", + " ", + " comment(\"Show all solutions that sum to 100\");", + " for ( var i = 0; i < nexpr; i++) ", + " if ( evaluate(i) == 100 ) ", + " print(i); ", + " ", + " comment(\"Show the sum that has the maximum number of solutions\"); ", + " var stat = {};", + " for ( var i = 0; i < nexpr; i++ )", + " {", + " var sum = evaluate(i);", + " if (stat[sum])", + " stat[sum]++;", + " else", + " stat[sum] = 1;", + " }", + " ", + " var best = 0;", + " var nbest = -1;", + " for ( var i = 0; i < nexpr; i++ )", + " {", + " var sum = evaluate(i);", + " if ( sum > 0 )", + " if ( stat[sum] > nbest )", + " {", + " best = i; ", + " nbest = stat[sum];", + " }", + " }", + " out(\"\" + evaluate(best) + \" has \" + nbest + \" solutions\");", + " ", + " comment(\"Show the lowest positive number that can't be expressed\");", + " for ( var i = 0; i <= 123456789; i++ )", + " {", + " for ( var j = 0; j < nexpr; j++) ", + " if ( i == evaluate(j) ) break; ", + " if ( i != evaluate(j) ) break;", + " }", + " out(i);", + " ", + " comment(\"Show the ten highest numbers that can be expressed\");", + " var limit = 123456789 + 1;", + " for ( i = 1; i <= 10; i++ ) ", + " {", + " var best = 0;", + " for ( var j = 0; j < nexpr; j++)", + " {", + " var test = evaluate(j);", + " if ( test < limit && test > best ) ", + " best = test;", + " }", + " for ( var j = 0; j < nexpr; j++)", + " if ( evaluate(j) == best ) print(j);", + " limit = best;", + " }", + " ", + "}", + "", + "{{Out}}", + "
    Show all solutions that sum to 100",
    +        "",
    +        "100 = 1+2+3-4+5+6+78+9",
    +        "100 = 1+2+34-5+67-8+9",
    +        "100 = 1+23-4+5+6+78-9",
    +        "100 = 1+23-4+56+7+8+9",
    +        "100 = 12+3+4+5-6-7+89",
    +        "100 = 12+3-4+5+67+8+9",
    +        "100 = 12-3-4+5-6+7+89",
    +        "100 = 123+4-5+67-89",
    +        "100 = 123+45-67+8-9",
    +        "100 = 123-4-5-6-7+8-9",
    +        "100 = 123-45-67+89",
    +        "100 = -1+2-3+4+5+6+78+9",
    +        "",
    +        "Show the sum that has the maximum number of solutions",
    +        "",
    +        "9 has 46 solutions",
    +        "",
    +        "Show the lowest positive number that can't be expressed",
    +        "",
    +        "211",
    +        "",
    +        "Show the ten highest numbers that can be expressed",
    +        "",
    +        "123456789 = 123456789",
    +        "23456790 = 1+23456789",
    +        "23456788 = -1+23456789",
    +        "12345687 = 12345678+9",
    +        "12345669 = 12345678-9",
    +        "3456801 = 12+3456789",
    +        "3456792 = 1+2+3456789",
    +        "3456790 = -1+2+3456789",
    +        "3456788 = 1-2+3456789",
    +        "3456786 = -1-2+3456789
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8043", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function () {\n 'use strict';\n\n // GENERIC FUNCTIONS ----------------------------------------------------\n\n // permutationsWithRepetition :: Int -> [a] -> [[a]]\n var permutationsWithRepetition = function (n, as) {\n return as.length > 0 ?\n foldl1(curry(cartesianProduct)(as), replicate(n, as)) : [];\n };\n\n // cartesianProduct :: [a] -> [b] -> [[a, b]]\n var cartesianProduct = function (xs, ys) {\n return [].concat.apply([], xs.map(function (x) {\n return [].concat.apply([], ys.map(function (y) {\n return [\n [x].concat(y)\n ];\n }));\n }));\n };\n\n // curry :: ((a, b) -> c) -> a -> b -> c\n var curry = function (f) {\n return function (a) {\n return function (b) {\n return f(a, b);\n };\n };\n };\n\n // flip :: (a -> b -> c) -> b -> a -> c\n var flip = function (f) {\n return function (a, b) {\n return f.apply(null, [b, a]);\n };\n };\n\n // foldl1 :: (a -> a -> a) -> [a] -> a\n var foldl1 = function (f, xs) {\n return xs.length > 0 ? xs.slice(1)\n .reduce(f, xs[0]) : [];\n };\n\n // replicate :: Int -> a -> [a]\n var replicate = function (n, a) {\n var v = [a],\n o = [];\n if (n < 1) return o;\n while (n > 1) {\n if (n & 1) o = o.concat(v);\n n >>= 1;\n v = v.concat(v);\n }\n return o.concat(v);\n };\n\n // group :: Eq a => [a] -> [[a]]\n var group = function (xs) {\n return groupBy(function (a, b) {\n return a === b;\n }, xs);\n };\n\n // groupBy :: (a -> a -> Bool) -> [a] -> [[a]]\n var groupBy = function (f, xs) {\n var dct = xs.slice(1)\n .reduce(function (a, x) {\n var h = a.active.length > 0 ? a.active[0] : undefined,\n blnGroup = h !== undefined && f(h, x);\n\n return {\n active: blnGroup ? a.active.concat(x) : [x],\n sofar: blnGroup ? a.sofar : a.sofar.concat([a.active])\n };\n }, {\n active: xs.length > 0 ? [xs[0]] : [],\n sofar: []\n });\n return dct.sofar.concat(dct.active.length > 0 ? [dct.active] : []);\n };\n\n // compare :: a -> a -> Ordering\n var compare = function (a, b) {\n return a < b ? -1 : a > b ? 1 : 0;\n };\n\n // on :: (b -> b -> c) -> (a -> b) -> a -> a -> c\n var on = function (f, g) {\n return function (a, b) {\n return f(g(a), g(b));\n };\n };\n\n // nub :: [a] -> [a]\n var nub = function (xs) {\n return nubBy(function (a, b) {\n return a === b;\n }, xs);\n };\n\n // nubBy :: (a -> a -> Bool) -> [a] -> [a]\n var nubBy = function (p, xs) {\n var x = xs.length ? xs[0] : undefined;\n\n return x !== undefined ? [x].concat(nubBy(p, xs.slice(1)\n .filter(function (y) {\n return !p(x, y);\n }))) : [];\n };\n\n // find :: (a -> Bool) -> [a] -> Maybe a\n var find = function (f, xs) {\n for (var i = 0, lng = xs.length; i < lng; i++) {\n if (f(xs[i], i)) return xs[i];\n }\n return undefined;\n };\n\n // Int -> [a] -> [a]\n var take = function (n, xs) {\n return xs.slice(0, n);\n };\n\n // unlines :: [String] -> String\n var unlines = function (xs) {\n return xs.join('\\n');\n };\n\n // show :: a -> String\n var show = function (x) {\n return JSON.stringify(x);\n }; //, null, 2);\n\n // head :: [a] -> a\n var head = function (xs) {\n return xs.length ? xs[0] : undefined;\n };\n\n // tail :: [a] -> [a]\n var tail = function (xs) {\n return xs.length ? xs.slice(1) : undefined;\n };\n\n // length :: [a] -> Int\n var length = function (xs) {\n return xs.length;\n };\n\n // SIGNED DIGIT SEQUENCES (mapped to sums and to strings)\n\n // data Sign :: [ 0 | 1 | -1 ] = ( Unsigned | Plus | Minus )\n // asSum :: [Sign] -> Int\n var asSum = function (xs) {\n var dct = xs.reduceRight(function (a, sign, i) {\n var d = i + 1; // zero-based index to [1-9] positions\n if (sign !== 0) {\n // Sum increased, digits cleared\n return {\n digits: [],\n n: a.n + sign * parseInt([d].concat(a.digits)\n .join(''), 10)\n };\n } else return { // Digits extended, sum unchanged\n digits: [d].concat(a.digits),\n n: a.n\n };\n }, {\n digits: [],\n n: 0\n });\n return dct.n + (\n dct.digits.length > 0 ? parseInt(dct.digits.join(''), 10) : 0\n );\n };\n\n // data Sign :: [ 0 | 1 | -1 ] = ( Unsigned | Plus | Minus )\n // asString :: [Sign] -> String\n var asString = function (xs) {\n var ns = xs.reduce(function (a, sign, i) {\n var d = (i + 1)\n .toString();\n return sign === 0 ? a + d : a + (sign > 0 ? ' +' : ' -') + d;\n }, '');\n\n return ns[0] === '+' ? tail(ns) : ns;\n };\n\n // SUM T0 100 ------------------------------------------------------------\n\n // universe :: [[Sign]]\n var universe = permutationsWithRepetition(9, [0, 1, -1])\n .filter(function (x) {\n return x[0] !== 1;\n });\n\n // allNonNegativeSums :: [Int]\n var allNonNegativeSums = universe.map(asSum)\n .filter(function (x) {\n return x >= 0;\n })\n .sort();\n\n // uniqueNonNegativeSums :: [Int]\n var uniqueNonNegativeSums = nub(allNonNegativeSums);\n\n return [\"Sums to 100:\\n\", unlines(universe.filter(function (x) {\n return asSum(x) === 100;\n })\n .map(asString)),\n\n \"\\n\\n10 commonest sums (sum, followed by number of routes to it):\\n\",\n show(take(10, group(allNonNegativeSums)\n .sort(on(flip(compare), length))\n .map(function (xs) {\n return [xs[0], xs.length];\n }))),\n\n \"\\n\\nFirst positive integer not expressible as a sum of this kind:\\n\",\n show(find(function (x, i) {\n return x !== i;\n }, uniqueNonNegativeSums.sort(compare)) - 1), // zero-based index\n\n \"\\n10 largest sums:\\n\",\n show(take(10, uniqueNonNegativeSums.sort(flip(compare))))\n ].join('\\n') + '\\n';\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Superellipse", + "type": "Waypoint", + "description": [ + "

    A superellipse is a geometric figure defined as the set of all points (x, y) with

    ", + "

    :: $\\left|\\frac{x}{a}\\right|^n\\! + \\left|\\frac{y}{b}\\right|^n\\! = 1,$

    ", + "

    where n, a, and b are positive numbers.

    ", + "Task", + "

    Draw a superellipse with n = 2.5, and a = b = 200

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "var n = 2.5, a = 200, b = 200, ctx;", + "", + "function point( x, y ) {", + " ctx.fillRect( x, y, 1, 1);", + "}", + "", + "function start() {", + " var can = document.createElement('canvas');", + " can.width = can.height = 600;", + " ctx = can.getContext( \"2d\" );", + " ctx.rect( 0, 0, can.width, can.height );", + " ctx.fillStyle = \"#000000\"; ctx.fill();", + " document.body.appendChild( can );", + "", + " ctx.fillStyle = \"#ffffff\";", + " for( var t = 0; t < 1000; t += .1 ) {", + " x = Math.pow( Math.abs( Math.cos( t ) ), 2 / n ) * a * Math.sign( Math.cos( t ) );", + " y = Math.pow( Math.abs( Math.sin( t ) ), 2 / n ) * b * Math.sign( Math.sin( t ) );", + "", + " point( x + ( can.width >> 1 ), y + ( can.height >> 1 ) );", + " }", + "}", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8044", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nvar n = 2.5, a = 200, b = 200, ctx;\n\nfunction point( x, y ) {\n ctx.fillRect( x, y, 1, 1);\n}\n\nfunction start() {\n var can = document.createElement('canvas');\n can.width = can.height = 600;\n ctx = can.getContext( \"2d\" );\n ctx.rect( 0, 0, can.width, can.height );\n ctx.fillStyle = \"#000000\"; ctx.fill();\n document.body.appendChild( can );\n\n ctx.fillStyle = \"#ffffff\";\n for( var t = 0; t < 1000; t += .1 ) {\n x = Math.pow( Math.abs( Math.cos( t ) ), 2 / n ) * a * Math.sign( Math.cos( t ) );\n y = Math.pow( Math.abs( Math.sin( t ) ), 2 / n ) * b * Math.sign( Math.sin( t ) );\n\n point( x + ( can.width >> 1 ), y + ( can.height >> 1 ) );\n }\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Sutherland-Hodgman polygon clipping", + "type": "Waypoint", + "description": [ + "

    The Sutherland-Hodgman clipping algorithm finds the polygon that is the intersection between an arbitrary polygon (the “subject polygon”) and a convex polygon (the “clip polygon”).

    It is used in computer graphics (especially 2D graphics) to reduce the complexity of a scene being displayed by eliminating parts of a polygon that do not need to be displayed.

    ", + "Task:", + "

    Take the closed polygon defined by the points:

    ", + "

    $[(50, 150), (200, 50), (350, 150), (350, 300), (250, 300), (200, 250), (150, 350), (100, 250), (100, 200)]$

    ", + "

    and clip it by the rectangle defined by the points:

    ", + "

    $[(100, 100), (300, 100), (300, 300), (100, 300)]$

    Print the sequence of points that define the resulting clipped polygon.

    ", + "Extra credit:", + "

    Display all three polygons on a graphical surface, using a different color for each polygon and filling the resulting polygon.

    (When displaying you may use either a north-west or a south-west origin, whichever is more convenient for your display mechanism.)

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "'''Solution:'''", + "", + "", + " ", + "\t", + " ", + " \t", + " ", + "", + "", + "", + "You can see it running [http://jsfiddle.net/elisherer/y6RDB/ here]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8045", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n\n \n\t\n \n \t\n \n\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Symmetric difference", + "type": "Waypoint", + "description": [ + "Task", + "

    Given two sets A and B, compute $(A \\setminus B) \\cup (B \\setminus A).$

    That is, enumerate the items that are in A or B but not both. This set is called the symmetric difference of A and B.

    In other words: $(A \\cup B) \\setminus (A \\cap B)$ (the set of items that are in at least one of A or B minus the set of items that are in both A and B).

    Optionally, give the individual differences ($A \\setminus B$ and $B \\setminus A$) as well.

    ", + "Test cases", + "

    A = {John, Bob, Mary, Serena}

    ", + "

    B = {Jim, Mary, John, Bob}

    ", + "Notes", + "If your code uses lists of items to represent sets then ensure duplicate items in lists are correctly handled. For example two lists representing sets of a = [\"John\", \"Serena\", \"Bob\", \"Mary\", \"Serena\"] and b = [\"Jim\", \"Mary\", \"John\", \"Jim\", \"Bob\"] should produce the result of just two strings: [\"Serena\", \"Jim\"], in any order.", + "In the mathematical notation above A \\ B gives the set of items in A that are not in B; A ∪ B gives the set of items in both A and B, (their union); and A ∩ B gives the set of items that are in both A and B (their intersection)." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "====Iterative====", + "", + "{{works with|JavaScript|1.6}}", + "{{works with|Firefox|1.5}}", + "{{works with|SpiderMonkey}} for the print() function.", + "", + "Uses the Array function unique() defined [[Create a Sequence of unique elements#JavaScript|here]].", + "// in A but not in B", + "function relative_complement(A, B) {", + " return A.filter(function(elem) {return B.indexOf(elem) == -1});", + "}", + "", + "// in A or in B but not in both", + "function symmetric_difference(A,B) {", + " return relative_complement(A,B).concat(relative_complement(B,A));", + "}", + "", + "var a = [\"John\", \"Serena\", \"Bob\", \"Mary\", \"Serena\"].unique(); ", + "var b = [\"Jim\", \"Mary\", \"John\", \"Jim\", \"Bob\"].unique();", + "", + "print(a);", + "print(b);", + "print(symmetric_difference(a,b));", + "outputs", + "
    Bob,John,Mary,Serena",
    +        "Bob,Jim,John,Mary",
    +        "Serena,Jim
    ", + "", + "'''Clear JavaScript'''", + "", + "function Difference(A,B)", + "{", + " var a = A.length, b = B.length, c = 0, C = [];", + " for (var i = 0; i < a; i++)", + " { var j = 0, k = 0;", + " while (j < b && B[j] !== A[i]) j++;", + " while (k < c && C[k] !== A[i]) k++;", + " if (j == b && k == c) C[c++] = A[i];", + " }", + " return C;", + "}", + "", + "function SymmetricDifference(A,B)", + "{ ", + " var D1 = Difference(A,B), D2 = Difference(B,A),", + " a = D1.length, b = D2.length;", + " for (var i = 0; i < b; i++) D1[a++] = D2[i];", + " return D1;", + "}", + "", + "", + "/* Example", + " A = ['John', 'Serena', 'Bob', 'Mary', 'Serena'];", + " B = ['Jim', 'Mary', 'John', 'Jim', 'Bob'];", + " ", + " Difference(A,B); // 'Serena'", + " Difference(B,A); // 'Jim'", + " SymmetricDifference(A,B); // 'Serena','Jim'", + "*/", + "", + "===ES6===", + "====Functional====", + "By composition of generic functions;", + "(() => {", + " 'use strict';", + "", + " const symmetricDifference = (xs, ys) =>", + " union(difference(xs, ys), difference(ys, xs));", + "", + "", + " // GENERIC FUNCTIONS ------------------------------------------------------", + "", + " // First instance of x (if any) removed from xs", + " // delete_ :: Eq a => a -> [a] -> [a]", + " const delete_ = (x, xs) => {", + " const i = xs.indexOf(x);", + " return i !== -1 ? (xs.slice(0, i)", + " .concat(xs.slice(i, -1))) : xs;", + " };", + "", + " // (\\\\) :: (Eq a) => [a] -> [a] -> [a]", + " const difference = (xs, ys) =>", + " ys.reduce((a, x) => filter(z => z !== x, a), xs);", + "", + " // filter :: (a -> Bool) -> [a] -> [a]", + " const filter = (f, xs) => xs.filter(f);", + "", + " // flip :: (a -> b -> c) -> b -> a -> c", + " const flip = f => (a, b) => f.apply(null, [b, a]);", + "", + " // foldl :: (b -> a -> b) -> b -> [a] -> b", + " const foldl = (f, a, xs) => xs.reduce(f, a);", + "", + " // nub :: [a] -> [a]", + " const nub = xs => {", + " const mht = unconsMay(xs);", + " return mht.nothing ? xs : (", + " ([h, t]) => [h].concat(nub(t.filter(s => s !== h)))", + " )(mht.just);", + " };", + "", + " // show :: a -> String", + " const show = x => JSON.stringify(x, null, 2);", + "", + " // unconsMay :: [a] -> Maybe (a, [a])", + " const unconsMay = xs => xs.length > 0 ? {", + " just: [xs[0], xs.slice(1)],", + " nothing: false", + " } : {", + " nothing: true", + " };", + "", + " // union :: [a] -> [a] -> [a]", + " const union = (xs, ys) => {", + " const sx = nub(xs);", + " return sx.concat(foldl(flip(delete_), nub(ys), sx));", + " };", + "", + " // TEST -------------------------------------------------------------------", + " const", + " a = [\"John\", \"Serena\", \"Bob\", \"Mary\", \"Serena\"],", + " b = [\"Jim\", \"Mary\", \"John\", \"Jim\", \"Bob\"];", + "", + " return show(", + " symmetricDifference(a, b)", + " );", + "})();", + "{{Out}}", + "[\"Serena\", \"Jim\"]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8046", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// in A but not in B\nfunction relative_complement(A, B) {\n return A.filter(function(elem) {return B.indexOf(elem) == -1});\n}\n\n// in A or in B but not in both\nfunction symmetric_difference(A,B) {\n return relative_complement(A,B).concat(relative_complement(B,A));\n}\n\nvar a = [\"John\", \"Serena\", \"Bob\", \"Mary\", \"Serena\"].unique(); \nvar b = [\"Jim\", \"Mary\", \"John\", \"Jim\", \"Bob\"].unique();\n\nprint(a);\nprint(b);\nprint(symmetric_difference(a,b));\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Synchronous concurrency", + "type": "Waypoint", + "description": [ + "

    The goal of this task is to create two concurrent activities (\"Threads\" or \"Tasks\", not processes.) that share data synchronously. Your language may provide syntax or libraries to perform concurrency. Different languages provide different implementations of concurrency, often with different names. Some languages use the term threads, others use the term tasks, while others use co-processes. This task should not be implemented using fork, spawn, or the Linux/UNIX/Win32 pipe command, as communication should be between threads, not processes.

    One of the concurrent units will read from a file named \"input.txt\" and send the contents of that file, one line at a time, to the other concurrent unit, which will print the line it receives to standard output. The printing unit must count the number of lines it prints. After the concurrent unit reading the file sends its last line to the printing unit, the reading unit will request the number of lines printed by the printing unit. The reading unit will then print the number of lines printed by the printing unit.

    This task requires two-way communication between the concurrent units. All concurrent units must cleanly terminate at the end of the program.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8047", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Temperature conversion", + "type": "Waypoint", + "description": [ + "

    There are quite a number of temperature scales. For this task we will concentrate on four of the perhaps best-known ones:

    ", + "

    Kelvin, Celsius, Fahrenheit, and Rankine.

    The Celsius and Kelvin scales have the same magnitude, but different null points.

    0 degrees Celsius corresponds to 273.15 kelvin.

    ", + "

    0 kelvin is absolute zero.

    The Fahrenheit and Rankine scales also have the same magnitude, but different null points.

    0 degrees Fahrenheit corresponds to 459.67 degrees Rankine.

    ", + "

    0 degrees Rankine is absolute zero.

    The Celsius/Kelvin and Fahrenheit/Rankine scales have a ratio of 5 : 9.

    ", + "Task", + "

    Write code that accepts a value of kelvin, converts it to values of the three other scales, and prints the result.

    ", + "Example:", + "
    ",
    +        "K  21.00C  -252.15F  -421.87R  37.80",
    +        "
    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES5===", + "var k2c = k => k - 273.15", + "var k2r = k => k * 1.8", + "var k2f = k => k2r(k) - 459.67", + "", + "Number.prototype.toMaxDecimal = function (d) {", + "\treturn +this.toFixed(d) + ''", + "}", + "", + "function kCnv(k) {", + "\tdocument.write( k,'K° = ', k2c(k).toMaxDecimal(2),'C° = ', k2r(k).toMaxDecimal(2),'R° = ', k2f(k).toMaxDecimal(2),'F°
    ' ) ", + "}", + " ", + "kCnv(21)", + "kCnv(295)
    ", + "{{out}}", + "
    ",
    +        "21K° = -252.15C° = 37.8R° = -421.87F°",
    +        "295K° = 21.85C° = 531R° = 71.33F°",
    +        "
    ", + "", + "===ES6===", + "", + "Deriving '''kelvinTranslations()''' from a more general '''heatBabel()''' function.", + "", + "(() => {", + " 'use strict';", + "", + " let kelvinTranslations = k => ['K', 'C', 'F', 'R']", + " .map(x => [x, heatBabel(k, 'K', x)]);", + "", + " // heatBabel :: Num -> ScaleName -> ScaleName -> Num", + " let heatBabel = (n, strFromScale, strToScale) => {", + " let ratio = 9 / 5,", + " cels = 273.15,", + " fahr = 459.67,", + " id = x => x,", + " readK = {", + " k: id,", + " c: x => cels + x,", + " f: x => (fahr + x) * ratio,", + " r: x => x / ratio", + " },", + " writeK = {", + " k: id,", + " c: x => x - cels,", + " f: x => (x * ratio) - fahr,", + " r: x => ratio * x", + " };", + "", + " return writeK[strToScale.charAt(0).toLowerCase()](", + " readK[strFromScale.charAt(0).toLowerCase()](n)", + " ).toFixed(2);", + " };", + "", + "", + " // TEST", + " return kelvinTranslations(21)", + " .map(([s, n]) => s + (' ' + n)", + " .slice(-10))", + " .join('\\n');", + "", + "})();", + "", + "", + "{{Out}}", + "", + "
    K     21.00",
    +        "C   -252.15",
    +        "F   -421.87",
    +        "R     37.80
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc804c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var k2c = k => k - 273.15\nvar k2r = k => k * 1.8\nvar k2f = k => k2r(k) - 459.67\n\nNumber.prototype.toMaxDecimal = function (d) {\n\treturn +this.toFixed(d) + ''\n}\n\nfunction kCnv(k) {\n\tdocument.write( k,'K° = ', k2c(k).toMaxDecimal(2),'C° = ', k2r(k).toMaxDecimal(2),'R° = ', k2f(k).toMaxDecimal(2),'F°
    ' ) \n}\n \nkCnv(21)\nkCnv(295)\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Ternary logic", + "type": "Waypoint", + "description": [ + "

    In logic, a three-valued logic (also trivalent, ternary, or trinary logic, sometimes abbreviated 3VL) is any of several many-valued logic systems in which there are three truth values indicating true, false and some indeterminate third value.

    This is contrasted with the more commonly known bivalent logics (such as classical sentential or boolean logic) which provide only for true and false.

    Conceptual form and basic ideas were initially created by Łukasiewicz, Lewis and Sulski.

    These were then re-formulated by Grigore Moisil in an axiomatic algebraic form, and also extended to n-valued logics in 1945.

    ", + "

    {|

    ", + "

    |+Example Ternary Logic Operators in Truth Tables:

    ", + "

    |-

    ", + "

    |

    ", + "

    {| class=wikitable

    ", + "

    |+not a

    ", + "

    |-

    ", + "

    ! colspan=2 | ¬

    ", + "

    |-

    ", + "

    | True || False

    ", + "

    |-

    ", + "

    | Maybe || Maybe

    ", + "

    |-

    ", + "

    | False || True

    ", + "

    |}

    ", + "

    ||

    ", + "

    {| class=wikitable

    ", + "

    |+a and b

    ", + "

    |-

    ", + "

    ! ∧

    ", + "

    | True || Maybe || False

    ", + "

    |-

    ", + "

    | True || True || Maybe || False

    ", + "

    |-

    ", + "

    | Maybe || Maybe || Maybe || False

    ", + "

    |-

    ", + "

    | False || False || False || False

    ", + "

    |}

    ", + "

    ||

    ", + "

    {| class=wikitable

    ", + "

    |-

    ", + "

    |+a or b

    ", + "

    |-

    ", + "

    ! ∨

    ", + "

    | True || Maybe || False

    ", + "

    |-

    ", + "

    | True || True || True || True

    ", + "

    |-

    ", + "

    | Maybe || True || Maybe || Maybe

    ", + "

    |-

    ", + "

    | False || True || Maybe || False

    ", + "

    |}

    ", + "

    |-

    ", + "

    ||

    ", + "

    {| class=wikitable

    ", + "

    |-

    ", + "

    |+if a then b

    ", + "

    |-

    ", + "

    ! ⊃

    ", + "

    | True || Maybe || False

    ", + "

    |-

    ", + "

    | True || True || Maybe || False

    ", + "

    |-

    ", + "

    | Maybe || True || Maybe || Maybe

    ", + "

    |-

    ", + "

    | False || True || True || True

    ", + "

    |}

    ", + "

    ||

    ", + "

    {| class=wikitable

    ", + "

    |-

    ", + "

    |+a is equivalent to b

    ", + "

    |-

    ", + "

    ! ≡

    ", + "

    | True || Maybe || False

    ", + "

    |-

    ", + "

    | True || True || Maybe || False

    ", + "

    |-

    ", + "

    | Maybe || Maybe || Maybe || Maybe

    ", + "

    |-

    ", + "

    | False || False || Maybe || True

    ", + "

    |}

    ", + "

    |}

    ", + "Task:", + "Define a new type that emulates ternary logic by storing data trits.", + "Given all the binary logic operators of the original programming language, reimplement these operators for the new Ternary logic type trit.", + "Generate a sampling of results using trit variables.", + "Kudos for actually thinking up a test case algorithm where ternary logic is intrinsically useful, optimises the test case algorithm and is preferable to binary logic.", + "

    Note: Setun (Сетунь) was a balanced ternary computer developed in 1958 at Moscow State University. The device was built under the lead of Sergei Sobolev and Nikolay Brusentsov. It was the only modern ternary computer, using three-valued ternary logic

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Let's use the trit already available in JavaScript:", + "true, false (both boolean) and undefined…", + "var L3 = new Object();", + "", + "L3.not = function(a) {", + " if (typeof a == \"boolean\") return !a;", + " if (a == undefined) return undefined;", + " throw(\"Invalid Ternary Expression.\");", + "}", + "", + "L3.and = function(a, b) {", + " if (typeof a == \"boolean\" && typeof b == \"boolean\") return a && b;", + " if ((a == true && b == undefined) || (a == undefined && b == true)) return undefined;", + " if ((a == false && b == undefined) || (a == undefined && b == false)) return false;", + " if (a == undefined && b == undefined) return undefined;", + " throw(\"Invalid Ternary Expression.\");", + "}", + "", + "L3.or = function(a, b) {", + " if (typeof a == \"boolean\" && typeof b == \"boolean\") return a || b;", + " if ((a == true && b == undefined) || (a == undefined && b == true)) return true;", + " if ((a == false && b == undefined) || (a == undefined && b == false)) return undefined;", + " if (a == undefined && b == undefined) return undefined;", + " throw(\"Invalid Ternary Expression.\");", + "}", + "", + "// A -> B is equivalent to -A or B", + "L3.ifThen = function(a, b) {", + " return L3.or(L3.not(a), b);", + "}", + "", + "// A <=> B is equivalent to (A -> B) and (B -> A)", + "L3.iff = function(a, b) {", + " return L3.and(L3.ifThen(a, b), L3.ifThen(b, a));", + "}", + "", + "… and try these:", + "", + "L3.not(true) // false", + "L3.not(var a) // undefined", + "", + "L3.and(true, a) // undefined", + "", + "L3.or(a, 2 == 3) // false", + "", + "L3.ifThen(true, a) // undefined", + "", + "L3.iff(a, 2 == 2) // undefined ", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8059", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "var L3 = new Object();\n\nL3.not = function(a) {\n if (typeof a == \"boolean\") return !a;\n if (a == undefined) return undefined;\n throw(\"Invalid Ternary Expression.\");\n}\n\nL3.and = function(a, b) {\n if (typeof a == \"boolean\" && typeof b == \"boolean\") return a && b;\n if ((a == true && b == undefined) || (a == undefined && b == true)) return undefined;\n if ((a == false && b == undefined) || (a == undefined && b == false)) return false;\n if (a == undefined && b == undefined) return undefined;\n throw(\"Invalid Ternary Expression.\");\n}\n\nL3.or = function(a, b) {\n if (typeof a == \"boolean\" && typeof b == \"boolean\") return a || b;\n if ((a == true && b == undefined) || (a == undefined && b == true)) return true;\n if ((a == false && b == undefined) || (a == undefined && b == false)) return undefined;\n if (a == undefined && b == undefined) return undefined;\n throw(\"Invalid Ternary Expression.\");\n}\n\n// A -> B is equivalent to -A or B\nL3.ifThen = function(a, b) {\n return L3.or(L3.not(a), b);\n}\n\n// A <=> B is equivalent to (A -> B) and (B -> A)\nL3.iff = function(a, b) {\n return L3.and(L3.ifThen(a, b), L3.ifThen(b, a));\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "The Twelve Days of Christmas", + "type": "Waypoint", + "description": [ + "

    Write a program that outputs the lyrics of the Christmas carol The Twelve Days of Christmas.

    ", + "

    The lyrics can be found here.

    ", + "

    (You must reproduce the words in the correct order, but case, format, and punctuation are left to your discretion.)

    Cf:", + "Comma quibbling" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "var days = [", + " 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth',", + " 'tenth', 'eleventh', 'twelfth',", + "];", + "", + "var gifts = [", + " \"A partridge in a pear tree\",", + " \"Two turtle doves\",", + " \"Three french hens\",", + " \"Four calling birds\",", + " \"Five golden rings\",", + " \"Six geese a-laying\",", + " \"Seven swans a-swimming\",", + " \"Eight maids a-milking\",", + " \"Nine ladies dancing\",", + " \"Ten lords a-leaping\",", + " \"Eleven pipers piping\",", + " \"Twelve drummers drumming\"", + "];", + "", + "var lines, verses = [], song;", + "", + "for ( var i = 0; i < 12; i++ ) {", + "", + " lines = [];", + " lines[0] = \"On the \" + days[i] + \" day of Christmas, my true love gave to me\";", + " ", + " var j = i + 1;", + " var k = 0;", + " while ( j-- > 0 )", + " lines[++k] = gifts[j];", + "", + " ", + " verses[i] = lines.join('\\n');", + " ", + " if ( i == 0 )", + " gifts[0] = \"And a partridge in a pear tree\";", + " ", + "}", + "", + "song = verses.join('\\n\\n');", + "document.write(song);", + "", + "", + "", + "Alternatively, in a functional style of JavaScript, we can define the ancient song \"strPrepn the lstOrdinal[i] strUnit of strHoliday\" as an expression, and return that expression in a human-legible and machine-parseable JSON string translation, for further analysis and processing :-)", + "", + "JSON.stringify(", + " (function (", + " strPrepn,", + " strHoliday,", + " strUnit,", + " strRole,", + " strProcess,", + " strRecipient", + " ) {", + " var lstOrdinal =", + " 'first second third fourth fifth sixth\\", + " seventh eighth ninth tenth eleventh twelfth'", + " .split(/\\s+/),", + " lngUnits = lstOrdinal.length,", + "", + " lstGoods =", + " 'A partridge in a pear tree.\\", + " Two turtle doves\\", + " Three french hens\\", + " Four calling birds\\", + " Five golden rings\\", + " Six geese a-laying\\", + " Seven swans a-swimming\\", + " Eight maids a-milking\\", + " Nine ladies dancing\\", + " Ten lords a-leaping\\", + " Eleven pipers piping\\", + " Twelve drummers drumming'", + " .split(/\\s{2,}/),", + "", + " lstReversed = (function () {", + " var lst = lstGoods.slice(0);", + " return (lst.reverse(), lst);", + " })(),", + "", + " strProvenance = [strRole, strProcess, strRecipient + ':'].join(' '),", + "", + " strPenultimate = lstReversed[lngUnits - 2] + ' and',", + " strFinal = lstGoods[0];", + "", + " return lstOrdinal.reduce(", + " function (sofar, day, i) {", + " return sofar.concat(", + " [", + " [", + " [ // abstraction of line 1", + " strPrepn,", + " 'the',", + " lstOrdinal[i],", + " strUnit,", + " 'of',", + " strHoliday", + " ].join(' '),", + " strProvenance", + " ].concat( // reversed descent through memory", + " (i > 1 ? [lstGoods[i]] : []).concat(", + " lstReversed.slice(", + " lngUnits - i,", + " lngUnits - 2", + " )", + " ).concat( // penultimate line ends with 'and'", + " [", + " strPenultimate,", + " strFinal", + " ].slice(i ? 0 : 1)", + " )", + " )", + " ]", + " );", + " }, []", + " );", + " })(", + " 'On', 'Christmas', 'day', 'my true love', 'gave to', 'me'", + " ), null, 2", + ");", + "", + "Note that the Google Closure compiler's translation of this would be half the size, but rather less legible.", + "(It does make interesting suggestions though – the semi-colon segmentation of the verses below is a trick that might be worth remembering).", + "", + "JSON.stringify(function (h, k, l, f, m, n) {", + " var c =", + " \"first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth\"", + " .split(\" \"),", + " d = c.length,", + " e =", + " \"A partridge in a pear tree.;Two turtle doves;Three french hens;Four calling birds;Five golden rings;Six geese a-laying;Seven swans a-swimming;Eight maids a-milking;Nine ladies dancing;Ten lords a-leaping;Eleven pipers piping;Twelve drummers drumming\"", + " .split(\";\"),", + " g = function () {", + " var b = e.slice(0);", + " return b.reverse(), b;", + " }(),", + " p = [f, m, n + \":\"].join(\" \"),", + " q = g[d - 2] + \" and\",", + " r = e[0];", + " ", + " return c.reduce(function (b, f, a) {", + " return b.concat([[[h, \"the\", c[a], l, \"of\", k].join(\" \"), p].concat((1 <", + " a ? [e[a]] : []).concat(g.slice(d - a, d - 2)).concat([q, r].slice(a ?", + " 0 : 1)))]);", + " }, []);", + "}(\"On\", \"Christmas\", \"day\", \"my true love\", \"gave to\", \"me\"), null, 2);", + "", + "Formatted JSON output (the expanded and Closure-compiled versions above both yield the same output).", + "", + "[", + " [", + " \"On the first day of Christmas\",", + " \"my true love gave to me:\",", + " \"A partridge in a pear tree.\"", + " ],", + " [", + " \"On the second day of Christmas\",", + " \"my true love gave to me:\",", + " \"Two turtle doves and\",", + " \"A partridge in a pear tree.\"", + " ],", + " [", + " \"On the third day of Christmas\",", + " \"my true love gave to me:\",", + " \"Three french hens\",", + " \"Two turtle doves and\",", + " \"A partridge in a pear tree.\"", + " ],", + " [", + " \"On the fourth day of Christmas\",", + " \"my true love gave to me:\",", + " \"Four calling birds\",", + " \"Three french hens\",", + " \"Two turtle doves and\",", + " \"A partridge in a pear tree.\"", + " ],", + " [", + " \"On the fifth day of Christmas\",", + " \"my true love gave to me:\",", + " \"Five golden rings\",", + " \"Four calling birds\",", + " \"Three french hens\",", + " \"Two turtle doves and\",", + " \"A partridge in a pear tree.\"", + " ]", + "", + "//... etc.", + "", + "]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84252665b21eecc8061", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nvar days = [\n 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth',\n 'tenth', 'eleventh', 'twelfth',\n];\n\nvar gifts = [\n \"A partridge in a pear tree\",\n \"Two turtle doves\",\n \"Three french hens\",\n \"Four calling birds\",\n \"Five golden rings\",\n \"Six geese a-laying\",\n \"Seven swans a-swimming\",\n \"Eight maids a-milking\",\n \"Nine ladies dancing\",\n \"Ten lords a-leaping\",\n \"Eleven pipers piping\",\n \"Twelve drummers drumming\"\n];\n\nvar lines, verses = [], song;\n\nfor ( var i = 0; i < 12; i++ ) {\n\n lines = [];\n lines[0] = \"On the \" + days[i] + \" day of Christmas, my true love gave to me\";\n \n var j = i + 1;\n var k = 0;\n while ( j-- > 0 )\n lines[++k] = gifts[j];\n\n \n verses[i] = lines.join('\\n');\n \n if ( i == 0 )\n gifts[0] = \"And a partridge in a pear tree\";\n \n}\n\nsong = verses.join('\\n\\n');\ndocument.write(song);\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Thue-Morse", + "type": "Waypoint", + "description": [ + "Task:", + "

    Create a Thue-Morse sequence.

    ", + "See also", + " YouTube entry: The Fairest Sharing Sequence Ever " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "===ES6===", + "(() => {", + " 'use strict';", + "", + " // THUE MORSE", + "", + " // thueMorse :: Int -> String", + " let thueMorse = nCycles => range(1, Math.abs(nCycles))", + " .reduce(a => a.concat(a.map(x => 1 - x)), [0])", + " .join('');", + "", + "", + " // GENERIC FUNCTION", + "", + " // range :: Int -> Int -> [Int]", + " let range = (m, n) => Array.from({", + " length: Math.floor((n - m)) + 1", + " }, (_, i) => m + i);", + "", + "", + " // TEST", + "", + " return thueMorse(6);", + "", + " // 0110100110010110100101100110100110010110011010010110100110010110", + "", + "})();", + "", + "", + "{{Out}}", + "
    0110100110010110100101100110100110010110011010010110100110010110
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84352665b21eecc8063", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(() => {\n 'use strict';\n\n // THUE MORSE\n\n // thueMorse :: Int -> String\n let thueMorse = nCycles => range(1, Math.abs(nCycles))\n .reduce(a => a.concat(a.map(x => 1 - x)), [0])\n .join('');\n\n\n // GENERIC FUNCTION\n\n // range :: Int -> Int -> [Int]\n let range = (m, n) => Array.from({\n length: Math.floor((n - m)) + 1\n }, (_, i) => m + i);\n\n\n // TEST\n\n return thueMorse(6);\n\n // 0110100110010110100101100110100110010110011010010110100110010110\n\n})();\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Trabb Pardo–Knuth algorithm", + "type": "Waypoint", + "description": [ + "

    The TPK algorithm is an early example of a programming chrestomathy.

    ", + "

    It was used in Donald Knuth and Luis Trabb Pardo's Stanford tech report The Early Development of Programming Languages.

    ", + "

    The report traces the early history of work in developing computer languages in the 1940s and 1950s, giving several translations of the algorithm.

    From the wikipedia entry:

    ask for 11 numbers to be read into a sequence S

    ", + "

    reverse sequence S

    ", + "

    for each item in sequence S

    ", + "

    result := call a function to do an operation

    ", + "

    if result overflows

    ", + "

    alert user

    ", + "

    else

    ", + "

    print result

    The task is to implement the algorithm:

    ", + "Use the function: $f(x) = |x|^{0.5} + 5x^3$", + "The overflow condition is an answer of greater than 400.", + "The 'user alert' should not stop processing of other items of the sequence.", + "Print a prompt before accepting eleven, textual, numeric inputs.", + "You may optionally print the item as well as its associated result, but the results must be in reverse order of input.", + "The sequence S may be 'implied' and so not shown explicitly.", + "Print and show the program in action from a typical run here. (If the output is graphical rather than text then either add a screendump or describe textually what is displayed)." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "", + "=== Spidermonkey ===", + "#!/usr/bin/env js", + "", + "function main() {", + " var nums = getNumbers(11);", + " nums.reverse();", + " for (var i in nums) {", + " pardoKnuth(nums[i], fn, 400);", + " }", + "}", + "", + "function pardoKnuth(n, f, max) {", + " var res = f(n);", + " putstr('f(' + String(n) + ')');", + " if (res > max) {", + " print(' is too large');", + " } else {", + " print(' = ' + String(res));", + " } ", + "}", + "", + "function fn(x) {", + " return Math.pow(Math.abs(x), 0.5) + 5 * Math.pow(x, 3);", + "}", + "", + "function getNumbers(n) {", + " var nums = [];", + " print('Enter', n, 'numbers.');", + " for (var i = 1; i <= n; i++) {", + " putstr(' ' + i + ': ');", + " var num = readline();", + " nums.push(Number(num)); ", + " }", + " return nums;", + "}", + "", + "main();", + "", + "", + "Results:", + " Enter 11 numbers.", + " 1: 1", + " 2: 2", + " 3: 3", + " 4: 4", + " 5: 5", + " 6: 6", + " 7: 7", + " 8: 8", + " 9: 9", + " 10: 10", + " 11: 11", + " f(11) is too large", + " f(10) is too large", + " f(9) is too large", + " f(8) is too large", + " f(7) is too large", + " f(6) is too large", + " f(5) is too large", + " f(4) = 322", + " f(3) = 136.73205080756887", + " f(2) = 41.41421356237309", + " f(1) = 6", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84352665b21eecc806e", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "#!/usr/bin/env js\n\nfunction main() {\n var nums = getNumbers(11);\n nums.reverse();\n for (var i in nums) {\n pardoKnuth(nums[i], fn, 400);\n }\n}\n\nfunction pardoKnuth(n, f, max) {\n var res = f(n);\n putstr('f(' + String(n) + ')');\n if (res > max) {\n print(' is too large');\n } else {\n print(' = ' + String(res));\n } \n}\n\nfunction fn(x) {\n return Math.pow(Math.abs(x), 0.5) + 5 * Math.pow(x, 3);\n}\n\nfunction getNumbers(n) {\n var nums = [];\n print('Enter', n, 'numbers.');\n for (var i = 1; i <= n; i++) {\n putstr(' ' + i + ': ');\n var num = readline();\n nums.push(Number(num)); \n }\n return nums;\n}\n\nmain();\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Tree traversal", + "type": "Waypoint", + "description": [ + "Task:", + "

    Implement a binary tree where each node carries an integer, and implement:

    ", + "

    ::* pre-order,

    ", + "

    ::* in-order,

    ", + "

    ::* post-order, and

    ", + "

    ::* level-order traversal.

    ", + "

    Use those traversals to output the following tree:

    ", + "

    1

    ", + "

    / \\

    ", + "

    / \\

    ", + "

    / \\

    ", + "

    2 3

    ", + "

    / \\ /

    ", + "

    4 5 6

    ", + "

    / / \\

    ", + "

    7 8 9

    The correct output should look like this:

    ", + "

    preorder: 1 2 4 7 5 3 6 8 9

    ", + "

    inorder: 7 4 2 5 1 8 6 9 3

    ", + "

    postorder: 7 4 5 2 8 9 6 3 1

    ", + "

    level-order: 1 2 3 4 5 6 7 8 9

    ", + "See also:", + " Wikipedia article: Tree traversal." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "====Iteration====", + "inspired by [[#Ruby|Ruby]]", + "function BinaryTree(value, left, right) {", + " this.value = value;", + " this.left = left;", + " this.right = right;", + "}", + "BinaryTree.prototype.preorder = function(f) {this.walk(f,['this','left','right'])}", + "BinaryTree.prototype.inorder = function(f) {this.walk(f,['left','this','right'])}", + "BinaryTree.prototype.postorder = function(f) {this.walk(f,['left','right','this'])}", + "BinaryTree.prototype.walk = function(func, order) {", + " for (var i in order) ", + " switch (order[i]) {", + " case \"this\": func(this.value); break;", + " case \"left\": if (this.left) this.left.walk(func, order); break;", + " case \"right\": if (this.right) this.right.walk(func, order); break;", + " }", + "}", + "BinaryTree.prototype.levelorder = function(func) {", + " var queue = [this];", + " while (queue.length != 0) {", + " var node = queue.shift();", + " func(node.value);", + " if (node.left) queue.push(node.left);", + " if (node.right) queue.push(node.right);", + " }", + "}", + "", + "// convenience function for creating a binary tree", + "function createBinaryTreeFromArray(ary) {", + " var left = null, right = null;", + " if (ary[1]) left = createBinaryTreeFromArray(ary[1]);", + " if (ary[2]) right = createBinaryTreeFromArray(ary[2]);", + " return new BinaryTree(ary[0], left, right);", + "}", + "", + "var tree = createBinaryTreeFromArray([1, [2, [4, [7]], [5]], [3, [6, [8],[9]]]]);", + "", + "print(\"*** preorder ***\"); tree.preorder(print); ", + "print(\"*** inorder ***\"); tree.inorder(print); ", + "print(\"*** postorder ***\"); tree.postorder(print);", + "print(\"*** levelorder ***\"); tree.levelorder(print);", + "", + "====Functional composition====", + "{{Trans|Haskell}}", + "(for binary trees consisting of nested lists)", + "", + "(function () {", + "", + " function preorder(n) {", + " return [n[v]].concat(", + " n[l] ? preorder(n[l]) : []", + " ).concat(", + " n[r] ? preorder(n[r]) : []", + " );", + " }", + "", + " function inorder(n) {", + " return (", + " n[l] ? inorder(n[l]) : []", + " ).concat(", + " n[v]", + " ).concat(", + " n[r] ? inorder(n[r]) : []", + " );", + " }", + "", + " function postorder(n) {", + " return (", + " n[l] ? postorder(n[l]) : []", + " ).concat(", + " n[r] ? postorder(n[r]) : []", + " ).concat(", + " n[v]", + " );", + " }", + "", + " function levelorder(n) {", + " return (function loop(x) {", + " return x.length ? (", + " x[0] ? (", + " [x[0][v]].concat(", + " loop(", + " x.slice(1).concat(", + " [x[0][l], x[0][r]]", + " )", + " )", + " )", + " ) : loop(x.slice(1))", + " ) : [];", + " })([n]);", + " }", + "", + " var v = 0,", + " l = 1,", + " r = 2,", + "", + " tree = [1,", + " [2,", + " [4,", + " [7]", + " ],", + " [5]", + " ],", + " [3,", + " [6,", + " [8],", + " [9]", + " ]", + " ]", + " ],", + "", + " lstTest = [[\"Traversal\", \"Nodes visited\"]].concat(", + " [preorder, inorder, postorder, levelorder].map(", + " function (f) {", + " return [f.name, f(tree)];", + " }", + " )", + " );", + "", + " // [[a]] -> bool -> s -> s", + " function wikiTable(lstRows, blnHeaderRow, strStyle) {", + " return '{| class=\"wikitable\" ' + (", + " strStyle ? 'style=\"' + strStyle + '\"' : ''", + " ) + lstRows.map(function (lstRow, iRow) {", + " var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|');", + "", + " return '\\n|-\\n' + strDelim + ' ' + lstRow.map(function (v) {", + " return typeof v === 'undefined' ? ' ' : v;", + " }).join(' ' + strDelim + strDelim + ' ');", + " }).join('') + '\\n|}';", + " }", + "", + " return wikiTable(lstTest, true) + '\\n\\n' + JSON.stringify(lstTest);", + "", + "})();", + "", + "Output:", + "", + "{| class=\"wikitable\" ", + "|-", + "! Traversal !! Nodes visited", + "|-", + "| preorder || 1,2,4,7,5,3,6,8,9", + "|-", + "| inorder || 7,4,2,5,1,8,6,9,3", + "|-", + "| postorder || 7,4,5,2,8,9,6,3,1", + "|-", + "| levelorder || 1,2,3,4,5,6,7,8,9", + "|}", + "", + "[[\"Traversal\",\"Nodes visited\"],", + "[\"preorder\",[1,2,4,7,5,3,6,8,9]],[\"inorder\",[7,4,2,5,1,8,6,9,3]],", + "[\"postorder\",[7,4,5,2,8,9,6,3,1]],[\"levelorder\",[1,2,3,4,5,6,7,8,9]]]", + "", + "", + "or, again functionally, but:", + "", + "# for a tree of nested dictionaries (rather than a simple nested list),", + "# defining a single '''traverse()''' function", + "# checking that the tree is indeed binary, and returning ''undefined'' for the ''in-order'' traversal if any node in the tree has more than two children. (The other 3 traversals are still defined for rose trees).", + "", + "", + "(function () {", + " 'use strict';", + "", + " // 'preorder' | 'inorder' | 'postorder' | 'level-order'", + "", + " // traverse :: String -> Tree {value: a, nest: [Tree]} -> [a]", + " function traverse(strOrderName, dctTree) {", + " var strName = strOrderName.toLowerCase();", + "", + " if (strName.startsWith('level')) {", + "", + " // LEVEL-ORDER", + " return levelOrder([dctTree]);", + "", + " } else if (strName.startsWith('in')) {", + " var lstNest = dctTree.nest;", + "", + " if ((lstNest ? lstNest.length : 0) < 3) {", + " var left = lstNest[0] || [],", + " right = lstNest[1] || [],", + "", + " lstLeft = left.nest ? (", + " traverse(strName, left)", + " ) : (left.value || []),", + " lstRight = right.nest ? (", + " traverse(strName, right)", + " ) : (right.value || []);", + "", + " return (lstLeft !== undefined && lstRight !== undefined) ?", + "", + " // IN-ORDER", + " (lstLeft instanceof Array ? lstLeft : [lstLeft])", + " .concat(dctTree.value)", + " .concat(lstRight) : undefined;", + "", + " } else { // in-order only defined here for binary trees", + " return undefined;", + " }", + "", + " } else {", + " var lstTraversed = concatMap(function (x) {", + " return traverse(strName, x);", + " }, (dctTree.nest || []));", + "", + " return (", + " strName.startsWith('pre') ? (", + "", + " // PRE-ORDER", + " [dctTree.value].concat(lstTraversed)", + "", + " ) : strName.startsWith('post') ? (", + "", + " // POST-ORDER", + " lstTraversed.concat(dctTree.value)", + "", + " ) : []", + " );", + " }", + " }", + "", + " // levelOrder :: [Tree {value: a, nest: [Tree]}] -> [a]", + " function levelOrder(lstTree) {", + " var lngTree = lstTree.length,", + " head = lngTree ? lstTree[0] : undefined,", + " tail = lstTree.slice(1);", + "", + " // Recursively take any value found in the head node", + " // of the remaining tail, deferring any child nodes", + " // of that head to the end of the tail", + " return lngTree ? (", + " head ? (", + " [head.value].concat(", + " levelOrder(", + " tail", + " .concat(head.nest || [])", + " )", + " )", + " ) : levelOrder(tail)", + " ) : [];", + " }", + "", + " // concatMap :: (a -> [b]) -> [a] -> [b]", + " function concatMap(f, xs) {", + " return [].concat.apply([], xs.map(f));", + " }", + "", + " var dctTree = {", + " value: 1,", + " nest: [{", + " value: 2,", + " nest: [{", + " value: 4,", + " nest: [{", + " value: 7", + " }]", + " }, {", + " value: 5", + " }]", + " }, {", + " value: 3,", + " nest: [{", + " value: 6,", + " nest: [{", + " value: 8", + " }, {", + " value: 9", + " }]", + " }]", + " }]", + " };", + "", + "", + " return ['preorder', 'inorder', 'postorder', 'level-order']", + " .reduce(function (a, k) {", + " return (", + " a[k] = traverse(k, dctTree),", + " a", + " );", + " }, {});", + "", + "})();", + "{{Out}}", + "{\"preorder\":[1, 2, 4, 7, 5, 3, 6, 8, 9], ", + "\"inorder\":[7, 4, 2, 5, 1, 8, 6, 9, 3], ", + "\"postorder\":[7, 4, 5, 2, 8, 9, 6, 3, 1], ", + "\"level-order\":[1, 2, 3, 4, 5, 6, 7, 8, 9]}", + "", + "===ES6===", + "{{Trans|Haskell}}", + "(() => {", + " // TRAVERSALS -------------------------------------------------------------", + "", + " // preorder Tree a -> [a]", + " const preorder = a => [a[v]]", + " .concat(a[l] ? preorder(a[l]) : [])", + " .concat(a[r] ? preorder(a[r]) : []);", + "", + " // inorder Tree a -> [a]", + " const inorder = a =>", + " (a[l] ? inorder(a[l]) : [])", + " .concat(a[v])", + " .concat(a[r] ? inorder(a[r]) : []);", + "", + " // postorder Tree a -> [a]", + " const postorder = a =>", + " (a[l] ? postorder(a[l]) : [])", + " .concat(a[r] ? postorder(a[r]) : [])", + " .concat(a[v]);", + "", + " // levelorder Tree a -> [a]", + " const levelorder = a => (function go(x) {", + " return x.length ? (", + " x[0] ? (", + " [x[0][v]].concat(", + " go(x.slice(1)", + " .concat([x[0][l], x[0][r]])", + " )", + " )", + " ) : go(x.slice(1))", + " ) : [];", + " })([a]);", + "", + "", + " // GENERIC FUNCTIONS -----------------------------------------------------", + "", + " // A list of functions applied to a list of arguments", + " // <*> :: [(a -> b)] -> [a] -> [b]", + " const ap = (fs, xs) => //", + " [].concat.apply([], fs.map(f => //", + " [].concat.apply([], xs.map(x => [f(x)]))));", + "", + " // intercalate :: String -> [a] -> String", + " const intercalate = (s, xs) => xs.join(s);", + "", + " // justifyLeft :: Int -> Char -> Text -> Text", + " const justifyLeft = (n, cFiller, strText) =>", + " n > strText.length ? (", + " (strText + cFiller.repeat(n))", + " .substr(0, n)", + " ) : strText;", + "", + " // unlines :: [String] -> String", + " const unlines = xs => xs.join('\\n');", + "", + " // unwords :: [String] -> String", + " const unwords = xs => xs.join(' ');", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " const zipWith = (f, xs, ys) =>", + " Array.from({", + " length: Math.min(xs.length, ys.length)", + " }, (_, i) => f(xs[i], ys[i]));", + "", + " // TEST -------------------------------------------------------------------", + " // asciiTree :: String", + " const asciiTree = unlines([", + " ' 1',", + " ' / \\\\',", + " ' / \\\\',", + " ' / \\\\',", + " ' 2 3',", + " ' / \\\\ /',", + " ' 4 5 6',", + " ' / / \\\\',", + " ' 7 8 9'", + " ]);", + "", + " const [v, l, r] = [0, 1, 2],", + " tree = [1, [2, [4, [7]],", + " [5]", + " ],", + " [3, [6, [8],", + " [9]", + " ]]", + " ],", + "", + " // fs :: [(Tree a -> [a])]", + " fs = [preorder, inorder, postorder, levelorder];", + "", + " return asciiTree + '\\n\\n' +", + " intercalate('\\n',", + " zipWith(", + " (f, xs) => justifyLeft(12, ' ', f.name + ':') + unwords(xs),", + " fs,", + " ap(fs, [tree])", + " )", + " );", + "})();", + "{{Out}}", + " 1", + " / \\", + " / \\", + " / \\", + " 2 3", + " / \\ /", + " 4 5 6", + " / / \\", + " 7 8 9", + "", + "preorder: 1 2 4 7 5 3 6 8 9", + "inorder: 7 4 2 5 1 8 6 9 3", + "postorder: 7 4 5 2 8 9 6 3 1", + "levelorder: 1 2 3 4 5 6 7 8 9", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84352665b21eecc806f", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function BinaryTree(value, left, right) {\n this.value = value;\n this.left = left;\n this.right = right;\n}\nBinaryTree.prototype.preorder = function(f) {this.walk(f,['this','left','right'])}\nBinaryTree.prototype.inorder = function(f) {this.walk(f,['left','this','right'])}\nBinaryTree.prototype.postorder = function(f) {this.walk(f,['left','right','this'])}\nBinaryTree.prototype.walk = function(func, order) {\n for (var i in order) \n switch (order[i]) {\n case \"this\": func(this.value); break;\n case \"left\": if (this.left) this.left.walk(func, order); break;\n case \"right\": if (this.right) this.right.walk(func, order); break;\n }\n}\nBinaryTree.prototype.levelorder = function(func) {\n var queue = [this];\n while (queue.length != 0) {\n var node = queue.shift();\n func(node.value);\n if (node.left) queue.push(node.left);\n if (node.right) queue.push(node.right);\n }\n}\n\n// convenience function for creating a binary tree\nfunction createBinaryTreeFromArray(ary) {\n var left = null, right = null;\n if (ary[1]) left = createBinaryTreeFromArray(ary[1]);\n if (ary[2]) right = createBinaryTreeFromArray(ary[2]);\n return new BinaryTree(ary[0], left, right);\n}\n\nvar tree = createBinaryTreeFromArray([1, [2, [4, [7]], [5]], [3, [6, [8],[9]]]]);\n\nprint(\"*** preorder ***\"); tree.preorder(print); \nprint(\"*** inorder ***\"); tree.inorder(print); \nprint(\"*** postorder ***\"); tree.postorder(print);\nprint(\"*** levelorder ***\"); tree.levelorder(print);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Truth table", + "type": "Waypoint", + "description": [ + "

    A truth table is a display of the inputs to, and the output of a Boolean equation organised as a table where each row gives one combination of input values and the corresponding value of the equation.

    ", + "Task:", + "Input a Boolean equation from the user as a string then calculate and print a formatted truth table for the given equation. (One can assume that the user input is correct).", + "Print and show output for Boolean equations of two and three input variables, but any program should not be limited to that many variables in the equation. ", + "Either reverse-polish or infix notation expressions are allowed.Related tasks:", + " Boolean values", + " Ternary logicSee also:", + " Wolfram MathWorld entry on truth tables.", + " some \"truth table\" examples from Google." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "Actually a HTML document. Save as a .html document and double-click it. You should be fine.", + "Truth table", + "{{Out|Output in browser window after entering \"AB^\"}}", + "
    A B AB^",
    +        "F F F",
    +        "F T T",
    +        "T F T",
    +        "T T F
    ", + "{{Out|Output in browser window after entering \"ABC^{{!}}\"}}", + "
    A B C ABC^|",
    +        "F F F F",
    +        "F F T T",
    +        "F T F T",
    +        "F T T F",
    +        "T F F T",
    +        "T F T T",
    +        "T T F T",
    +        "T T T T
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84352665b21eecc8073", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "Truth table\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Ulam spiral (for primes)", + "type": "Waypoint", + "description": [ + "

    An Ulam spiral (of primes numbers) is a method of visualizing prime numbers when expressed in a (normally counter-clockwise) outward spiral (usually starting at 1), constructed on a square grid, starting at the \"center\".

    An Ulam spiral is also known as a prime spiral.

    The first grid (green) is shown with all numbers (primes and non-primes) shown, starting at 1.

    In an Ulam spiral of primes, only the primes are shown (usually indicated by some glyph such as a dot or asterisk), and all non-primes as shown as a blank (or some other whitespace).

    Of course, the grid and border are not to be displayed (but they are displayed here when using these Wiki HTML tables).

    Normally, the spiral starts in the \"center\", and the 2nd number is to the viewer's right and the number spiral starts from there in a counter-clockwise direction.

    There are other geometric shapes that are used as well, including clock-wise spirals.

    Also, some spirals (for the 2nd number) is viewed upwards from the 1st number instead of to the right, but that is just a matter of orientation.

    Sometimes, the starting number can be specified to show more visual striking patterns (of prime densities).

    [A larger than necessary grid (numbers wise) is shown here to illustrate the pattern of numbers on the diagonals (which may be used by the method to orientate the direction of spiral-construction algorithm within the example computer programs)].

    Then, in the next phase in the transformation of the Ulam prime spiral, the non-primes are translated to blanks.

    In the orange grid below, the primes are left intact, and all non-primes are changed to blanks.

    Then, in the final transformation of the Ulam spiral (the yellow grid), translate the primes to a glyph such as a or some other suitable glyph.

    ", + "

    {| style=\"float:left;border: 2px solid black; background:lightgreen; color:black; margin-left:0;margin-right:auto;text-align:center;width:34em;height:34em;table-layout:fixed;font-size:70%\"

    ", + "

    |-

    ", + "

    | 65 || 64 || 63 || 62 || 61 || 60 || 59 || 58 || 57

    ", + "

    |->

    ", + "

    | 66 || 37 || 36 || 35 || 34 || 33 || 32 || 31 || 56

    ", + "

    |-

    ", + "

    | 67 || 38 || 17 || 16 || 15 || 14 || 13 || 30 || 55

    ", + "

    |-

    ", + "

    | 68 || 39 || 18 || 5 || 4 || 3 || 12 || 29 || 54

    ", + "

    |-

    ", + "

    | 69 || 40 || 19 || 6 || 1 || 2 || 11 || 28 || 53

    ", + "

    |-

    ", + "

    | 70 || 41 || 20 || 7 || 8 || 9 || 10 || 27 || 52

    ", + "

    |-

    ", + "

    | 71 || 42 || 21 || 22 || 23 || 24 || 25 || 26 || 51

    ", + "

    |-

    ", + "

    | 72 || 43 || 44 || 45 || 46 || 47 || 48 || 49 || 50

    ", + "

    |-

    ", + "

    | 73 || 74 || 75 || 76 || 77 || 78 || 79 || 80 || 81

    ", + "

    |}

    {| style=\"float:left;border: 2px solid black; background:orange; color:black; margin-left:20px;margin-right:auto;text-align:center;width:34em;height:34em;table-layout:fixed;font-size:70%\"

    ", + "

    |-

    ", + "

    | || || || || 61 || || 59 || ||

    ", + "

    |-

    ", + "

    | || 37 || || || || || || 31 ||

    ", + "

    |-

    ", + "

    | 67 || || 17 || || || || 13 || ||

    ", + "

    |-

    ", + "

    | || || || 5 || || 3 || || 29 ||

    ", + "

    |-

    ", + "

    | || || 19 || || || 2 || 11 || || 53

    ", + "

    |-

    ", + "

    | || 41 || || 7 || || || || ||

    ", + "

    |-

    ", + "

    | 71 || || || || 23 || || || ||

    ", + "

    |-

    ", + "

    | || 43 || || || || 47 || || ||

    ", + "

    |-

    ", + "

    | 73 || || || || || || 79 || ||

    ", + "

    |}

    {| style=\"float:left;border: 2px solid black; background:yellow; color:black; margin-left:20px;margin-right:auto;text-align:center;width:34em;height:34em;table-layout:fixed;font-size:70%\"

    ", + "

    |-

    ", + "

    | || || || || || || || ||

    ", + "

    |-

    ", + "

    | || || || || || || || ||

    ", + "

    |-

    ", + "

    | || || || || || || || ||

    ", + "

    |-

    ", + "

    | || || || || || || || ||

    ", + "

    |-

    ", + "

    | || || || || || || || ||

    ", + "

    |-

    ", + "

    | || || || || || || || ||

    ", + "

    |-

    ", + "

    | || || || || || || || ||

    ", + "

    |-

    ", + "

    | || || || || || || || ||

    ", + "

    |-

    ", + "

    | || || || || || || || ||

    ", + "

    |}

    ", + "

    The Ulam spiral becomes more visually obvious as the grid increases in size.

    ", + "Task", + "

    For any sized N x N grid, construct and show an Ulam spiral (counter-clockwise) of primes starting at some specified initial number (the default would be 1), with some suitably dotty (glyph) representation to indicate primes, and the absence of dots to indicate non-primes.

    You should demonstrate the generator by showing at Ulam prime spiral large enough to (almost) fill your terminal screen.

    ", + "Related tasks:", + " Spiral matrix", + " Zig-zag matrix", + " Identity_matrix See also", + "Wikipedia entry: Ulam spiral ", + "MathWorld™ entry: Prime Spiral" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": "null", + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84352665b21eecc8075", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Universal Turing machine", + "type": "Waypoint", + "description": [ + "

    One of the foundational mathematical constructs behind computer science

    ", + "

    is the universal Turing Machine.

    Indeed one way to definitively prove that a language

    ", + "

    is turing-complete

    ", + "

    is to implement a universal Turing machine in it.

    ", + "Task:

    Simulate such a machine capable

    ", + "

    of taking the definition of any other Turing machine and executing it.

    Of course, you will not have an infinite tape,

    ", + "

    but you should emulate this as much as is possible.

    The three permissible actions on the tape are \"left\", \"right\" and \"stay\".

    To test your universal Turing machine (and prove your programming language

    ", + "

    is Turing complete!), you should execute the following two Turing machines

    ", + "

    based on the following definitions.

    ", + "

    Simple incrementer

    ", + "States: q0, qf", + "Initial state: q0", + "Terminating states: qf", + "Permissible symbols: B, 1", + "Blank symbol: B", + "Rules:", + "* (q0, 1, 1, right, q0)", + "* (q0, B, 1, stay, qf)", + "

    The input for this machine should be a tape of 1 1 1

    ", + "

    Three-state busy beaver

    ", + "States: a, b, c, halt", + "Initial state: a", + "Terminating states: halt", + "Permissible symbols: 0, 1", + "Blank symbol: 0", + "Rules:", + "* (a, 0, 1, right, b)", + "* (a, 1, 1, left, c)", + "* (b, 0, 1, left, a)", + "* (b, 1, 1, right, b)", + "* (c, 0, 1, left, b)", + "* (c, 1, 1, stay, halt)", + "

    The input for this machine should be an empty tape.

    ", + "

    Bonus:

    5-state, 2-symbol probable Busy Beaver machine from Wikipedia

    ", + "States: A, B, C, D, E, H", + "Initial state: A", + "Terminating states: H", + "Permissible symbols: 0, 1", + "Blank symbol: 0", + "Rules:", + "* (A, 0, 1, right, B)", + "* (A, 1, 1, left, C)", + "* (B, 0, 1, right, C)", + "* (B, 1, 1, right, B)", + "* (C, 0, 1, right, D)", + "* (C, 1, 0, left, E)", + "* (D, 0, 1, left, A)", + "* (D, 1, 1, left, D)", + "* (E, 0, 1, stay, H)", + "* (E, 1, 0, left, A)", + "

    The input for this machine should be an empty tape.

    This machine runs for more than 47 millions steps.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{works with|FireFox}}", + "function tm(d,s,e,i,b,t,... r) {", + "\tdocument.write(d, '
    ')", + "\tif (i<0||i>=t.length) return", + "\tvar re=new RegExp(b,'g')", + "\twrite('*',s,i,t=t.split(''))", + "\tvar p={}; r.forEach(e=>((s,r,w,m,n)=>{p[s+'.'+r]={w,n,m:[0,1,-1][1+'RL'.indexOf(m)]}})(... e.split(/[ .:,]+/)))", + "\tfor (var n=1; s!=e; n+=1) {", + "\t\twith (p[s+'.'+t[i]]) t[i]=w,s=n,i+=m", + "\t\tif (i==-1) i=0,t.unshift(b)", + "\t\telse if (i==t.length) t[i]=b", + "\t\twrite(n,s,i,t)", + "\t}", + "\tdocument.write('
    ')", + "\tfunction write(n, s, i, t) {", + "\t\tt = t.join('')", + "\t\tt = t.substring(0,i) + '' + t.charAt(i) + '' + t.substr(i+1)", + "\t\tdocument.write((' '+n).slice(-3).replace(/ /g,' '), ': ', s, ' [', t.replace(re,' '), ']', '
    ')", + "\t}", + "}", + "", + "tm( 'Unary incrementer',", + "//\t s e i b t", + "\t'a', 'h', 0, 'B', '111',", + "//\t s.r: w, m, n", + "\t'a.1: 1, L, a',", + "\t'a.B: 1, S, h'", + ")", + "", + "tm( 'Unary adder',", + "\t1, 0, 0, '0', '1110111',", + "\t'1.1: 0, R, 2', // write 0 rigth goto 2", + "\t'2.1: 1, R, 2', // while (1) rigth", + "\t'2.0: 1, S, 0' // write 1 stay halt", + ")", + "", + "tm( 'Three-state busy beaver',", + "\t1, 0, 0, '0', '0',", + "\t'1.0: 1, R, 2',", + "\t'1.1: 1, R, 0',", + "\t'2.0: 0, R, 3',", + "\t'2.1: 1, R, 2',", + "\t'3.0: 1, L, 3',", + "\t'3.1: 1, L, 1'", + ")
    ", + "{{out}}", + " Unary incrementer
      *: a [111]
      1: a [ 111]
      2: h [1111]

    Unary adder
       *: 1 [111 111]
      1: 2 [ 11 111]
      2: 3 [ 11 111]
      3: 3 [ 11 111]
      4: 0 [ 111111]

    Three-state busy beaver
       *: 1 [ ]
      1: 2 [1 ]
      2: 3 [1  ]
      3: 3 [1 1]
      4: 3 [111]
      5: 1 [ 111]
      6: 2 [1111]
      7: 2 [1111]
      8: 2 [1111]
      9: 2 [1111 ]
     10: 3 [1111  ]
     11: 3 [1111 1]
     12: 3 [111111]
     13: 1 [111111]
     14: 0 [111111]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84352665b21eecc807a", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function tm(d,s,e,i,b,t,... r) {\n\tdocument.write(d, '
    ')\n\tif (i<0||i>=t.length) return\n\tvar re=new RegExp(b,'g')\n\twrite('*',s,i,t=t.split(''))\n\tvar p={}; r.forEach(e=>((s,r,w,m,n)=>{p[s+'.'+r]={w,n,m:[0,1,-1][1+'RL'.indexOf(m)]}})(... e.split(/[ .:,]+/)))\n\tfor (var n=1; s!=e; n+=1) {\n\t\twith (p[s+'.'+t[i]]) t[i]=w,s=n,i+=m\n\t\tif (i==-1) i=0,t.unshift(b)\n\t\telse if (i==t.length) t[i]=b\n\t\twrite(n,s,i,t)\n\t}\n\tdocument.write('
    ')\n\tfunction write(n, s, i, t) {\n\t\tt = t.join('')\n\t\tt = t.substring(0,i) + '' + t.charAt(i) + '' + t.substr(i+1)\n\t\tdocument.write((' '+n).slice(-3).replace(/ /g,' '), ': ', s, ' [', t.replace(re,' '), ']', '
    ')\n\t}\n}\n\ntm( 'Unary incrementer',\n//\t s e i b t\n\t'a', 'h', 0, 'B', '111',\n//\t s.r: w, m, n\n\t'a.1: 1, L, a',\n\t'a.B: 1, S, h'\n)\n\ntm( 'Unary adder',\n\t1, 0, 0, '0', '1110111',\n\t'1.1: 0, R, 2', // write 0 rigth goto 2\n\t'2.1: 1, R, 2', // while (1) rigth\n\t'2.0: 1, S, 0' // write 1 stay halt\n)\n\ntm( 'Three-state busy beaver',\n\t1, 0, 0, '0', '0',\n\t'1.0: 1, R, 2',\n\t'1.1: 1, R, 0',\n\t'2.0: 0, R, 3',\n\t'2.1: 1, R, 2',\n\t'3.0: 1, L, 3',\n\t'3.1: 1, L, 1'\n)\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Vector products", + "type": "Waypoint", + "description": [ + "

    A vector is defined as having three dimensions as being represented by an ordered collection of three numbers: (X, Y, Z).

    If you imagine a graph with the x and y axis being at right angles to each other and having a third, z axis coming out of the page, then a triplet of numbers, (X, Y, Z) would represent a point in the region, and a vector from the origin to the point.

    Given the vectors:

    ", + "

    A = (a1, a2, a3)

    ", + "

    B = (b1, b2, b3)

    ", + "

    C = (c1, c2, c3)

    ", + "

    then the following common vector products are defined:

    ", + "The dot product (a scalar quantity)::: A • B = a1b1 + a2b2 + a3b3 ", + "The cross product (a vector quantity)::: A x B = (a2b3 - a3b2, a3b1 - a1b3, a1b2 - a2b1) ", + "The scalar triple product (a scalar quantity)::: A • (B x C) ", + "The vector triple product (a vector quantity)::: A x (B x C) ", + "Task:", + "

    Given the three vectors:

    ", + "

    a = ( 3, 4, 5)

    ", + "

    b = ( 4, 3, 5)

    ", + "

    c = (-5, -12, -13)

    ", + "Create a named function/subroutine/method to compute the dot product of two vectors.", + "Create a function to compute the cross product of two vectors.", + "Optionally create a function to compute the scalar triple product of three vectors.", + "Optionally create a function to compute the vector triple product of three vectors.", + "Compute and display: a • b", + "Compute and display: a x b", + "Compute and display: a • b x c, the scalar triple product.", + "Compute and display: a x b x c, the vector triple product.References:", + " A starting page on Wolfram MathWorld is .", + " Wikipedia dot product, Wikipedia cross product ", + "

    Wikipedia triple product entries.

    ", + "Related tasks:", + " Dot product", + " Quaternion type" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "The dotProduct() function is generic and will create a dot product of any set of vectors provided they are all the same dimension.", + "The crossProduct() function expects two 3D vectors.", + "function dotProduct() {", + " var len = arguments[0] && arguments[0].length;", + " var argsLen = arguments.length;", + " var i, j = len;", + " var prod, sum = 0;", + " ", + " // If no arguments supplied, return undefined", + " if (!len) {", + " return;", + " }", + " ", + " // If all vectors not same length, return undefined", + " i = argsLen;", + " while (i--) {", + " ", + " if (arguments[i].length != len) {", + " return; // return undefined", + " }", + " }", + " ", + " // Sum terms", + " while (j--) {", + " i = argsLen;", + " prod = 1;", + " ", + " while (i--) {", + " prod *= arguments[i][j];", + " }", + " sum += prod;", + " }", + " return sum;", + "}", + "", + "function crossProduct(a, b) {", + "", + " // Check lengths", + " if (a.length != 3 || b.length != 3) {", + " return;", + " }", + " ", + " return [a[1]*b[2] - a[2]*b[1],", + " a[2]*b[0] - a[0]*b[2],", + " a[0]*b[1] - a[1]*b[0]];", + " ", + "}", + "", + "function scalarTripleProduct(a, b, c) {", + " return dotProduct(a, crossProduct(b, c));", + "}", + "", + "function vectorTripleProduct(a, b, c) {", + " return crossProduct(a, crossProduct(b, c));", + "}", + "", + "// Run tests", + "(function () {", + " var a = [3, 4, 5];", + " var b = [4, 3, 5];", + " var c = [-5, -12, -13];", + " ", + " alert(", + " 'A . B: ' + dotProduct(a, b) +", + " '\\n' +", + " 'A x B: ' + crossProduct(a, b) +", + " '\\n' +", + " 'A . (B x C): ' + scalarTripleProduct(a, b, c) +", + " '\\n' +", + " 'A x (B x C): ' + vectorTripleProduct(a, b, c)", + " ); ", + "}());", + "Output:", + "
    ",
    +        "A . B: 49",
    +        "A x B: 5,5,-7",
    +        "A . (B x C): 6",
    +        "A x (B x C): -267,204,-3",
    +        "
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84352665b21eecc808c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function dotProduct() {\n var len = arguments[0] && arguments[0].length;\n var argsLen = arguments.length;\n var i, j = len;\n var prod, sum = 0;\n \n // If no arguments supplied, return undefined\n if (!len) {\n return;\n }\n \n // If all vectors not same length, return undefined\n i = argsLen;\n while (i--) {\n \n if (arguments[i].length != len) {\n return; // return undefined\n }\n }\n \n // Sum terms\n while (j--) {\n i = argsLen;\n prod = 1;\n \n while (i--) {\n prod *= arguments[i][j];\n }\n sum += prod;\n }\n return sum;\n}\n\nfunction crossProduct(a, b) {\n\n // Check lengths\n if (a.length != 3 || b.length != 3) {\n return;\n }\n \n return [a[1]*b[2] - a[2]*b[1],\n a[2]*b[0] - a[0]*b[2],\n a[0]*b[1] - a[1]*b[0]];\n \n}\n\nfunction scalarTripleProduct(a, b, c) {\n return dotProduct(a, crossProduct(b, c));\n}\n\nfunction vectorTripleProduct(a, b, c) {\n return crossProduct(a, crossProduct(b, c));\n}\n\n// Run tests\n(function () {\n var a = [3, 4, 5];\n var b = [4, 3, 5];\n var c = [-5, -12, -13];\n \n alert(\n 'A . B: ' + dotProduct(a, b) +\n '\\n' +\n 'A x B: ' + crossProduct(a, b) +\n '\\n' +\n 'A . (B x C): ' + scalarTripleProduct(a, b, c) +\n '\\n' +\n 'A x (B x C): ' + vectorTripleProduct(a, b, c)\n ); \n}());\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Verify distribution uniformity/Naive", + "type": "Waypoint", + "description": [ + "

    This task is an adjunct to Seven-sided dice from five-sided dice.

    ", + "Ttask:", + "

    Create a function to check that the random integers returned from a small-integer generator function have uniform distribution.

    ", + "

    The function should take as arguments:

    ", + "The function (or object) producing random integers.", + "The number of times to call the integer generator.", + "A 'delta' value of some sort that indicates how close to a flat distribution is close enough.", + "

    The function should produce:

    ", + "Some indication of the distribution achieved.", + "An 'error' if the distribution is not flat enough.", + "

    Show the distribution checker working when the produced distribution is flat enough and when it is not. (Use a generator from Seven-sided dice from five-sided dice).

    See also:

    ", + "Verify distribution uniformity/Chi-squared test" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "{{trans|Tcl}}", + "function distcheck(random_func, times, opts) {", + " if (opts === undefined) opts = {}", + " opts['delta'] = opts['delta'] || 2;", + "", + " var count = {}, vals = [];", + " for (var i = 0; i < times; i++) {", + " var val = random_func();", + " if (! has_property(count, val)) {", + " count[val] = 1;", + " vals.push(val);", + " }", + " else", + " count[val] ++;", + " }", + " vals.sort(function(a,b) {return a-b});", + "", + " var target = times / vals.length;", + " var tolerance = target * opts['delta'] / 100; ", + "", + " for (var i = 0; i < vals.length; i++) {", + " var val = vals[i];", + " if (Math.abs(count[val] - target) > tolerance) ", + " throw \"distribution potentially skewed for \" + val +", + " \": expected result around \" + target + \", got \" +count[val];", + " else", + " print(val + \"\\t\" + count[val]);", + " }", + "}", + "", + "function has_property(obj, propname) {", + " return typeof(obj[propname]) == \"undefined\" ? false : true;", + "}", + "", + "try {", + " distcheck(function() {return Math.floor(10 * Math.random())}, 100000);", + " print();", + " distcheck(function() {return (Math.random() > 0.95 ? 1 : 0)}, 100000);", + "} catch (e) {", + " print(e);", + "}", + "Output:", + "
    0       9945",
    +        "1       9862",
    +        "2       9954",
    +        "3       10104",
    +        "4       9861",
    +        "5       10140",
    +        "6       10066",
    +        "7       10001",
    +        "8       10101",
    +        "9       9966",
    +        "",
    +        "distribution potentially skewed for 0: expected result around 50000, got 95040
    ", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84352665b21eecc808e", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "function distcheck(random_func, times, opts) {\n if (opts === undefined) opts = {}\n opts['delta'] = opts['delta'] || 2;\n\n var count = {}, vals = [];\n for (var i = 0; i < times; i++) {\n var val = random_func();\n if (! has_property(count, val)) {\n count[val] = 1;\n vals.push(val);\n }\n else\n count[val] ++;\n }\n vals.sort(function(a,b) {return a-b});\n\n var target = times / vals.length;\n var tolerance = target * opts['delta'] / 100; \n\n for (var i = 0; i < vals.length; i++) {\n var val = vals[i];\n if (Math.abs(count[val] - target) > tolerance) \n throw \"distribution potentially skewed for \" + val +\n \": expected result around \" + target + \", got \" +count[val];\n else\n print(val + \"\\t\" + count[val]);\n }\n}\n\nfunction has_property(obj, propname) {\n return typeof(obj[propname]) == \"undefined\" ? false : true;\n}\n\ntry {\n distcheck(function() {return Math.floor(10 * Math.random())}, 100000);\n print();\n distcheck(function() {return (Math.random() > 0.95 ? 1 : 0)}, 100000);\n} catch (e) {\n print(e);\n}\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Vigenère cipher", + "type": "Waypoint", + "description": [ + "Task:", + "

    Implement a Vigenère cypher, both encryption and decryption.

    The program should handle keys and text of unequal length,

    ", + "

    and should capitalize everything and discard non-alphabetic characters.

    ", + "

    (If your program handles non-alphabetic characters in another way,

    ", + "

    make a note of it.)

    ", + "Related tasks:", + " Caesar cipher", + " Rot-13", + " Substitution Cipher" + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "// helpers", + "// helper", + "function ordA(a) {", + " return a.charCodeAt(0) - 65;", + "}", + "", + "// vigenere", + "function vigenere(text, key, decode) {", + " var i = 0, b;", + " key = key.toUpperCase().replace(/[^A-Z]/g, '');", + " return text.toUpperCase().replace(/[^A-Z]/g, '').replace(/[A-Z]/g, function(a) {", + " b = key[i++ % key.length];", + " return String.fromCharCode(((ordA(a) + (decode ? 26 - ordA(b) : ordA(b))) % 26 + 65));", + " });", + "}", + "", + "// example", + "var text = \"The quick brown fox Jumped over the lazy Dog the lazy dog lazy dog dog\";", + "var key = 'alex';", + "var enc = vigenere(text,key);", + "var dec = vigenere(enc,key,true);", + "", + "console.log(enc);", + "console.log(dec);", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84352665b21eecc8091", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "// helpers\n// helper\nfunction ordA(a) {\n return a.charCodeAt(0) - 65;\n}\n\n// vigenere\nfunction vigenere(text, key, decode) {\n var i = 0, b;\n key = key.toUpperCase().replace(/[^A-Z]/g, '');\n return text.toUpperCase().replace(/[^A-Z]/g, '').replace(/[A-Z]/g, function(a) {\n b = key[i++ % key.length];\n return String.fromCharCode(((ordA(a) + (decode ? 26 - ordA(b) : ordA(b))) % 26 + 65));\n });\n}\n\n// example\nvar text = \"The quick brown fox Jumped over the lazy Dog the lazy dog lazy dog dog\";\nvar key = 'alex';\nvar enc = vigenere(text,key);\nvar dec = vigenere(enc,key,true);\n\nconsole.log(enc);\nconsole.log(dec);\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Water collected between towers", + "type": "Waypoint", + "description": [ + "Task:", + "

    In a two-dimensional world, we begin with any bar-chart (or row of close-packed 'towers', each of unit width), and then it rains,

    ", + "

    completely filling all convex enclosures in the chart with water.

    ", + "
    9               ██           9               ██    ",
    +        "8               ██           8               ██    ",
    +        "7     ██        ██           7     ██≈≈≈≈≈≈≈≈██    ",
    +        "6     ██  ██    ██           6     ██≈≈██≈≈≈≈██    ",
    +        "5 ██  ██  ██  ████           5 ██≈≈██≈≈██≈≈████    ",
    +        "4 ██  ██  ████████           4 ██≈≈██≈≈████████    ",
    +        "3 ██████  ████████           3 ██████≈≈████████    ",
    +        "2 ████████████████  ██       2 ████████████████≈≈██",
    +        "1 ████████████████████       1 ████████████████████
    ", + "

    In the example above, a bar chart representing the values [5, 3, 7, 2, 6, 4, 5, 9, 1, 2] has filled, collecting 14 units of water.

    Write a function, in your language, from a given array of heights, to the number of water units that can be held in this way, by a corresponding bar chart.

    Calculate the number of water units that could be collected by bar charts representing each of the following seven series:

       [[1, 5, 3, 7, 2],",
    +        "    [5, 3, 7, 2, 6, 4, 5, 9, 1, 2],",
    +        "    [2, 6, 3, 5, 2, 8, 1, 4, 2, 2, 5, 3, 5, 7, 4, 1],",
    +        "    [5, 5, 5, 5],",
    +        "    [5, 6, 7, 8],",
    +        "    [8, 7, 7, 6],",
    +        "    [6, 7, 10, 7, 6]]
    ", + "

    See, also:

    Four Solutions to a Trivial Problem – a Google Tech Talk by Guy Steele", + "Water collected between towers on Stack Overflow, from which the example above is taken)", + "An interesting Haskell solution, using the Tardis monad, by Phil Freeman in a Github gist." + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "===ES5===", + "{{Trans|Haskell}}", + "(function () {", + " 'use strict';", + "", + " // waterCollected :: [Int] -> Int", + " var waterCollected = function (xs) {", + " return sum( // water above each bar", + " zipWith(function (a, b) {", + " return a - b; // difference between water level and bar", + " },", + " zipWith(min, // lower of two flanking walls", + " scanl1(max, xs), // highest walls to left", + " scanr1(max, xs) // highest walls to right", + " ), ", + " xs // tops of bars", + " )", + " .filter(function (x) {", + " return x > 0; // only bars with water above them", + " })", + " );", + " };", + "", + " // GENERIC FUNCTIONS ----------------------------------------", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " var zipWith = function (f, xs, ys) {", + " var ny = ys.length;", + " return (xs.length <= ny ? xs : xs.slice(0, ny))", + " .map(function (x, i) {", + " return f(x, ys[i]);", + " });", + " };", + "", + " // scanl1 is a variant of scanl that has no starting value argument", + " // scanl1 :: (a -> a -> a) -> [a] -> [a]", + " var scanl1 = function (f, xs) {", + " return xs.length > 0 ? scanl(f, xs[0], xs.slice(1)) : [];", + " };", + "", + " // scanr1 is a variant of scanr that has no starting value argument", + " // scanr1 :: (a -> a -> a) -> [a] -> [a]", + " var scanr1 = function (f, xs) {", + " return xs.length > 0 ? scanr(f, xs.slice(-1)[0], xs.slice(0, -1)) : [];", + " };", + "", + " // scanl :: (b -> a -> b) -> b -> [a] -> [b]", + " var scanl = function (f, startValue, xs) {", + " var lst = [startValue];", + " return xs.reduce(function (a, x) {", + " var v = f(a, x);", + " return lst.push(v), v;", + " }, startValue), lst;", + " };", + "", + " // scanr :: (b -> a -> b) -> b -> [a] -> [b]", + " var scanr = function (f, startValue, xs) {", + " var lst = [startValue];", + " return xs.reduceRight(function (a, x) {", + " var v = f(a, x);", + " return lst.push(v), v;", + " }, startValue), lst.reverse();", + " };", + "", + " // sum :: (Num a) => [a] -> a", + " var sum = function (xs) {", + " return xs.reduce(function (a, x) {", + " return a + x;", + " }, 0);", + " };", + "", + " // max :: Ord a => a -> a -> a", + " var max = function (a, b) {", + " return a > b ? a : b;", + " };", + "", + " // min :: Ord a => a -> a -> a", + " var min = function (a, b) {", + " return b < a ? b : a;", + " };", + "", + " // TEST ---------------------------------------------------", + " return [", + " [1, 5, 3, 7, 2],", + " [5, 3, 7, 2, 6, 4, 5, 9, 1, 2],", + " [2, 6, 3, 5, 2, 8, 1, 4, 2, 2, 5, 3, 5, 7, 4, 1],", + " [5, 5, 5, 5],", + " [5, 6, 7, 8],", + " [8, 7, 7, 6],", + " [6, 7, 10, 7, 6]", + " ].map(waterCollected);", + "", + " //--> [2, 14, 35, 0, 0, 0, 0]", + "})();", + "", + "{{Out}}", + "[2, 14, 35, 0, 0, 0, 0]", + "", + "===ES6===", + "{{Trans|Haskell}}", + "", + "(() => {", + " 'use strict';", + " ", + " // waterCollected :: [Int] -> Int", + " const waterCollected = xs => {", + " const maxToRight = scanr1(max, xs),", + " maxToLeft = scanl1(max, xs),", + " levels = zipWith(min, maxToLeft, maxToRight);", + "", + " return sum(zipWith(difference, levels, xs)", + " .filter(x => x > 0));", + " };", + "", + "", + " // GENERIC FUNCTIONS ----------------------------------------", + "", + " // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]", + " const zipWith = (f, xs, ys) => {", + " const ny = ys.length;", + " return (xs.length <= ny ? xs : xs.slice(0, ny))", + " .map((x, i) => f(x, ys[i]));", + " }", + "", + " // scanl1 is a variant of scanl that has no starting value argument", + " // scanl1 :: (a -> a -> a) -> [a] -> [a]", + " const scanl1 = (f, xs) =>", + " xs.length > 0 ? scanl(f, xs[0], xs.slice(1)) : [];", + "", + " // scanr1 is a variant of scanr that has no starting value argument", + " // scanr1 :: (a -> a -> a) -> [a] -> [a]", + " const scanr1 = (f, xs) =>", + " xs.length > 0 ? scanr(f, xs.slice(-1)[0], xs.slice(0, -1)) : [];", + "", + " // scanl :: (b -> a -> b) -> b -> [a] -> [b]", + " const scanl = (f, startValue, xs) => {", + " const lst = [startValue];", + " return (", + " xs.reduce((a, x) => {", + " const v = f(a, x);", + " return (lst.push(v), v);", + " }, startValue),", + " lst", + " );", + " };", + "", + " // scanr :: (b -> a -> b) -> b -> [a] -> [b]", + " const scanr = (f, startValue, xs) => {", + " const lst = [startValue];", + " return (", + " xs.reduceRight((a, x) => {", + " const v = f(a, x);", + " return (lst.push(v), v);", + " }, startValue),", + " lst.reverse()", + " );", + " };", + "", + " // difference :: (Num a) => a -> a -> a", + " const difference = (a, b) => a - b;", + "", + " // sum :: (Num a) => [a] -> a", + " const sum = xs => xs.reduce((a, x) => a + x, 0);", + "", + " // max :: Ord a => a -> a -> a", + " const max = (a, b) => a > b ? a : b;", + "", + " // min :: Ord a => a -> a -> a", + " const min = (a, b) => b < a ? b : a;", + "", + "", + " // TEST ---------------------------------------------------", + " return [", + " [1, 5, 3, 7, 2],", + " [5, 3, 7, 2, 6, 4, 5, 9, 1, 2],", + " [2, 6, 3, 5, 2, 8, 1, 4, 2, 2, 5, 3, 5, 7, 4, 1],", + " [5, 5, 5, 5],", + " [5, 6, 7, 8],", + " [8, 7, 7, 6],", + " [6, 7, 10, 7, 6]", + " ].map(waterCollected);", + "", + " //--> [2, 14, 35, 0, 0, 0, 0]", + "})();", + "", + "{{Out}}", + "[2, 14, 35, 0, 0, 0, 0]", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84352665b21eecc8097", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "(function () {\n 'use strict';\n\n // waterCollected :: [Int] -> Int\n var waterCollected = function (xs) {\n return sum( // water above each bar\n zipWith(function (a, b) {\n return a - b; // difference between water level and bar\n },\n zipWith(min, // lower of two flanking walls\n scanl1(max, xs), // highest walls to left\n scanr1(max, xs) // highest walls to right\n ), \n xs // tops of bars\n )\n .filter(function (x) {\n return x > 0; // only bars with water above them\n })\n );\n };\n\n // GENERIC FUNCTIONS ----------------------------------------\n\n // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]\n var zipWith = function (f, xs, ys) {\n var ny = ys.length;\n return (xs.length <= ny ? xs : xs.slice(0, ny))\n .map(function (x, i) {\n return f(x, ys[i]);\n });\n };\n\n // scanl1 is a variant of scanl that has no starting value argument\n // scanl1 :: (a -> a -> a) -> [a] -> [a]\n var scanl1 = function (f, xs) {\n return xs.length > 0 ? scanl(f, xs[0], xs.slice(1)) : [];\n };\n\n // scanr1 is a variant of scanr that has no starting value argument\n // scanr1 :: (a -> a -> a) -> [a] -> [a]\n var scanr1 = function (f, xs) {\n return xs.length > 0 ? scanr(f, xs.slice(-1)[0], xs.slice(0, -1)) : [];\n };\n\n // scanl :: (b -> a -> b) -> b -> [a] -> [b]\n var scanl = function (f, startValue, xs) {\n var lst = [startValue];\n return xs.reduce(function (a, x) {\n var v = f(a, x);\n return lst.push(v), v;\n }, startValue), lst;\n };\n\n // scanr :: (b -> a -> b) -> b -> [a] -> [b]\n var scanr = function (f, startValue, xs) {\n var lst = [startValue];\n return xs.reduceRight(function (a, x) {\n var v = f(a, x);\n return lst.push(v), v;\n }, startValue), lst.reverse();\n };\n\n // sum :: (Num a) => [a] -> a\n var sum = function (xs) {\n return xs.reduce(function (a, x) {\n return a + x;\n }, 0);\n };\n\n // max :: Ord a => a -> a -> a\n var max = function (a, b) {\n return a > b ? a : b;\n };\n\n // min :: Ord a => a -> a -> a\n var min = function (a, b) {\n return b < a ? b : a;\n };\n\n // TEST ---------------------------------------------------\n return [\n [1, 5, 3, 7, 2],\n [5, 3, 7, 2, 6, 4, 5, 9, 1, 2],\n [2, 6, 3, 5, 2, 8, 1, 4, 2, 2, 5, 3, 5, 7, 4, 1],\n [5, 5, 5, 5],\n [5, 6, 7, 8],\n [8, 7, 7, 6],\n [6, 7, 10, 7, 6]\n ].map(waterCollected);\n\n //--> [2, 14, 35, 0, 0, 0, 0]\n})();\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] + }, + { + "title": "Wireworld", + "type": "Waypoint", + "description": [ + "

    Wireworld is a cellular automaton with some similarities to Conway's Game of Life.

    It is capable of doing sophisticated computations with appropriate programs

    ", + "

    (it is actually Turing complete),

    ", + "

    and is much simpler to program for.

    A Wireworld arena consists of a Cartesian grid of cells,

    ", + "

    each of which can be in one of four states.

    ", + "

    All cell transitions happen simultaneously.

    The cell transition rules are this:

    ", + "

    {| class=wikitable

    ", + "

    |-

    ", + "

    ! Input State

    ", + "

    ! Output State

    ", + "

    ! Condition

    ", + "

    |-

    ", + "

    | empty

    ", + "

    | empty

    ", + "

    |

    ", + "

    |-

    ", + "

    | electronhead

    ", + "

    | electrontail

    ", + "

    |

    ", + "

    |-

    ", + "

    | electrontail

    ", + "

    | conductor

    ", + "

    |

    ", + "

    |-

    ", + "

    | valign=top | conductor

    ", + "

    | valign=top | electronhead

    ", + "

    | if 1 or 2 cells in the neighborhood of the cell are in the state “electron head

    ", + "

    |-

    ", + "

    | conductor

    ", + "

    | conductor

    ", + "

    | otherwise

    ", + "

    |}

    ", + "Task:", + "

    Create a program that reads a Wireworld program from a file and displays an animation of the processing. Here is a sample description file (using \"H\" for an electron head, \"t\" for a tail, \".\" for a conductor and a space for empty) you may wish to test with, which demonstrates two cycle-3 generators and an inhibit gate:

    ", + "
    ",
    +        "tH.........",
    +        ".   .",
    +        "   ...",
    +        ".   .",
    +        "Ht.. ......",
    +        "
    ", + "

    While text-only implementations of this task are possible, mapping cells to pixels is advisable if you wish to be able to display large designs. The logic is not significantly more complex.

    " + ], + "challengeSeed": [ + "function replaceMe (foo) {", + " // Good luck!", + " return true;", + "}" + ], + "rawSolutions": [ + "=={{header|JavaScript}}==", + "You have to search and open the file manually.
    ", + "This is the HTML you need to test.", + "
    ",
    +        "",
    +        "Wireworld",
    +        "",
    +        "",
    +        "
    ", + "", + "var ctx, sizeW, sizeH, scl = 10, map, tmp;", + "function getNeighbour( i, j ) {", + " var ii, jj, c = 0;", + " for( var b = -1; b < 2; b++ ) {", + " for( var a = -1; a < 2; a++ ) {", + " ii = i + a; jj = j + b;", + " if( ii < 0 || ii >= sizeW || jj < 0 || jj >= sizeH ) continue;", + " if( map[ii][jj] == 1 ) c++;", + " }", + " }", + " return ( c == 1 || c == 2 );", + "}", + "function simulate() {", + " drawWorld();", + " for( var j = 0; j < sizeH; j++ ) {", + " for( var i = 0; i < sizeW; i++ ) {", + " switch( map[i][j] ) {", + " case 0: tmp[i][j] = 0; break;", + " case 1: tmp[i][j] = 2; break;", + " case 2: tmp[i][j] = 3; break;", + " case 3: ", + " if( getNeighbour( i, j ) ) tmp[i][j] = 1;", + " else tmp[i][j] = 3;", + " break;", + " }", + " }", + " }", + " [tmp, map] = [map, tmp]; ", + " setTimeout( simulate, 200 );", + "}", + "function drawWorld() {", + " ctx.fillStyle = \"#000\"; ctx.fillRect( 0, 0, sizeW * scl, sizeH * scl );", + " for( var j = 0; j < sizeH; j++ ) {", + " for( var i = 0; i < sizeW; i++ ) {", + " switch( map[i][j] ) {", + " case 0: continue;", + " case 1: ctx.fillStyle = \"#03f\"; break;", + " case 2: ctx.fillStyle = \"#f30\"; break;", + " case 3: ctx.fillStyle = \"#ff3\"; break;", + " }", + " ctx.fillRect( i, j, 1, 1 );", + " }", + " }", + "}", + "function openFile( event ) {", + " var input = event.target;", + " var reader = new FileReader();", + " reader.onload = function() {", + " createWorld( reader.result );", + " };", + " reader.readAsText(input.files[0]);", + "}", + "function createWorld( txt ) {", + " var l = txt.split( \"\\n\" );", + " sizeW = parseInt( l[0] );", + " sizeH = parseInt( l[1] );", + " map = new Array( sizeW );", + " tmp = new Array( sizeW );", + " for( var i = 0; i < sizeW; i++ ) {", + " map[i] = new Array( sizeH );", + " tmp[i] = new Array( sizeH );", + " for( var j = 0; j < sizeH; j++ ) {", + " map[i][j] = tmp[i][j] = 0;", + " }", + " }", + " var t;", + " for( var j = 0; j < sizeH; j++ ) {", + " for( var i = 0; i < sizeW; i++ ) {", + " switch( l[j + 2][i] ) {", + " case \" \": t = 0; break;", + " case \"H\": t = 1; break;", + " case \"t\": t = 2; break;", + " case \".\": t = 3; break;", + " }", + " map[i][j] = t;", + " }", + " }", + " init();", + "}", + "function init() {", + " var canvas = document.createElement( \"canvas\" );", + " canvas.width = sizeW * scl;", + " canvas.height = sizeH * scl;", + " ctx = canvas.getContext( \"2d\" );", + " ctx.scale( scl, scl );", + " document.body.appendChild( canvas );", + " simulate();", + "}", + "", + "", + "" + ], + "tail": [ + "const replaceThis = 3;" + ], + "id": "5a23c84352665b21eecc809c", + "challengeType": 5, + "releasedOn": "December 27, 2017", + "isBeta": "true", + "betaSolutions": [ + "\nvar ctx, sizeW, sizeH, scl = 10, map, tmp;\nfunction getNeighbour( i, j ) {\n var ii, jj, c = 0;\n for( var b = -1; b < 2; b++ ) {\n for( var a = -1; a < 2; a++ ) {\n ii = i + a; jj = j + b;\n if( ii < 0 || ii >= sizeW || jj < 0 || jj >= sizeH ) continue;\n if( map[ii][jj] == 1 ) c++;\n }\n }\n return ( c == 1 || c == 2 );\n}\nfunction simulate() {\n drawWorld();\n for( var j = 0; j < sizeH; j++ ) {\n for( var i = 0; i < sizeW; i++ ) {\n switch( map[i][j] ) {\n case 0: tmp[i][j] = 0; break;\n case 1: tmp[i][j] = 2; break;\n case 2: tmp[i][j] = 3; break;\n case 3: \n if( getNeighbour( i, j ) ) tmp[i][j] = 1;\n else tmp[i][j] = 3;\n break;\n }\n }\n }\n [tmp, map] = [map, tmp]; \n setTimeout( simulate, 200 );\n}\nfunction drawWorld() {\n ctx.fillStyle = \"#000\"; ctx.fillRect( 0, 0, sizeW * scl, sizeH * scl );\n for( var j = 0; j < sizeH; j++ ) {\n for( var i = 0; i < sizeW; i++ ) {\n switch( map[i][j] ) {\n case 0: continue;\n case 1: ctx.fillStyle = \"#03f\"; break;\n case 2: ctx.fillStyle = \"#f30\"; break;\n case 3: ctx.fillStyle = \"#ff3\"; break;\n }\n ctx.fillRect( i, j, 1, 1 );\n }\n }\n}\nfunction openFile( event ) {\n var input = event.target;\n var reader = new FileReader();\n reader.onload = function() {\n createWorld( reader.result );\n };\n reader.readAsText(input.files[0]);\n}\nfunction createWorld( txt ) {\n var l = txt.split( \"\\n\" );\n sizeW = parseInt( l[0] );\n sizeH = parseInt( l[1] );\n map = new Array( sizeW );\n tmp = new Array( sizeW );\n for( var i = 0; i < sizeW; i++ ) {\n map[i] = new Array( sizeH );\n tmp[i] = new Array( sizeH );\n for( var j = 0; j < sizeH; j++ ) {\n map[i][j] = tmp[i][j] = 0;\n }\n }\n var t;\n for( var j = 0; j < sizeH; j++ ) {\n for( var i = 0; i < sizeW; i++ ) {\n switch( l[j + 2][i] ) {\n case \" \": t = 0; break;\n case \"H\": t = 1; break;\n case \"t\": t = 2; break;\n case \".\": t = 3; break;\n }\n map[i][j] = t;\n }\n }\n init();\n}\nfunction init() {\n var canvas = document.createElement( \"canvas\" );\n canvas.width = sizeW * scl;\n canvas.height = sizeH * scl;\n ctx = canvas.getContext( \"2d\" );\n ctx.scale( scl, scl );\n document.body.appendChild( canvas );\n simulate();\n}\n\n" + ], + "betaTests": [ + "assert(typeof replaceMe === 'function', 'message: replaceMe is a function.');" + ] } ] } From 941e060da58f9e5969edfe0bdbe52514439a926a Mon Sep 17 00:00:00 2001 From: Niko Date: Thu, 28 Dec 2017 02:47:43 -0400 Subject: [PATCH 030/108] fix: Homepage responsiveness (#16326) --- server/views/home.jade | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/server/views/home.jade b/server/views/home.jade index 51f13dba21..90f0440fc1 100644 --- a/server/views/home.jade +++ b/server/views/home.jade @@ -51,29 +51,29 @@ block content .spacer .row .text-center.negative-35 - .col-xs-12.col-sm-12.col-md-3 + .col-xs-12.col-sm-6.col-md-3 .landing-skill-icon.ion-social-html5 h2.black-text HTML5 - .col-xs-12.col-sm-12.col-md-3 + .col-xs-12.col-sm-6.col-md-3 .landing-skill-icon.ion-social-css3 h2.black-text CSS3 - .col-xs-12.col-sm-12.col-md-3 + .col-xs-12.col-sm-6.col-md-3 .landing-skill-icon.ion-social-javascript h2.black-text JavaScript - .col-xs-12.col-sm-12.col-md-3 + .col-xs-12.col-sm-6.col-md-3 .landing-skill-icon.fa.fa-database.font-awesome-padding h2.black-text Databases - .col-xs-12.col-sm-12.col-md-3 + .col-xs-12.col-sm-6.col-md-3 .landing-skill-icon.ion-social-github h2.black-text Git & GitHub - .col-xs-12.col-sm-12.col-md-3 + .col-xs-12.col-sm-6.col-md-3 .landing-skill-icon.ion-social-nodejs h2.black-text Node.js - .col-xs-12.col-sm-12.col-md-3 + .col-xs-12.col-sm-6.col-md-3 .landing-skill-icon.custom-landing-skill-icon img(src='https://s3.amazonaws.com/freecodecamp/react.svg') h2.black-text React.js - .col-xs-12.col-sm-12.col-md-3 + .col-xs-12.col-sm-6.col-md-3 .landing-skill-icon.custom-landing-skill-icon img(src='https://s3.amazonaws.com/freecodecamp/d3-logo.svg') h2.black-text D3.js From bd8f03cfc45be6038a4e935221b978effe8b3185 Mon Sep 17 00:00:00 2001 From: Timo Date: Thu, 28 Dec 2017 13:39:25 +0100 Subject: [PATCH 031/108] docs(contributing): Tweak CONTRIBUTING.md (#16347) --- CONTRIBUTING.md | 161 +++++++++++++++++++++--------------------------- 1 file changed, 71 insertions(+), 90 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 27af9b4376..c20378a2c6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,20 +19,19 @@ Working on your first Pull Request? You can learn how from this *free* series [H ## Contribution Guidelines - [Prerequisites](#prerequisites) -- [Forking The Project](#forking-the-project) -- [Create A Branch](#create-a-branch) -- [Setup Linting](#setup-linting) -- [Setup freeCodeCamp](#setup-freecodecamp) +- [Forking the Project](#forking-the-project) +- [Create a Branch](#create-a-branch) +- [Set Up Linting](#set-up-linting) +- [Set Up MailHog](#set-up-mailhog) +- [Set Up freeCodeCamp](#set-up-freecodecamp) - [Make Changes](#make-changes) - [Run The Test Suite](#run-the-test-suite) -- [Squash Your Commits](#squash-your-commits) -- [Commit Message](#commit-message) -- [Creating A Pull Request](#creating-a-pull-request) +- [Creating a Pull Request](#creating-a-pull-request) - [Common Steps](#common-steps) - [How We Review and Merge Pull Requests](#how-we-review-and-merge-pull-requests) - [How We Close Stale Issues](#how-we-close-stale-issues) - [Next Steps](#next-steps) -- [Other resources](#other-resources) +- [Other Resources](#other-resources) ### Prerequisites @@ -45,7 +44,7 @@ Working on your first Pull Request? You can learn how from this *free* series [H > _Updating to the latest releases is recommended_. -If Node or MongoDB is already installed in your machine, run the following commands to validate the versions: +If Node.js or MongoDB is already installed on your machine, run the following commands to validate the versions: ```shell node -v @@ -60,19 +59,18 @@ Platform-specific guides to setting up a development environment: - [How to clone and setup the freeCodeCamp website on a Windows pc](https://forum.freecodecamp.org/t/how-to-clone-and-setup-the-free-code-camp-website-on-a-windows-pc/19366) - [How to Clone and Setup the freeCodeCamp Website on a Mac](https://forum.freecodecamp.org/t/how-to-clone-and-setup-the-freecodecamp-website-on-a-mac/78450) -### Forking The Project +### Forking the Project #### Setting Up Your System 1. Install [Git](https://git-scm.com/) or your favorite Git client. 2. (Optional) [Setup an SSH Key](https://help.github.com/articles/generating-an-ssh-key/) for GitHub. -3. Create a parent projects directory on your system. For this guide, it will be assumed that it is `/mean/` #### Forking freeCodeCamp 1. Go to the top level freeCodeCamp repository: 2. Click the "Fork" Button in the upper right hand corner of the interface ([More Details Here](https://help.github.com/articles/fork-a-repo/)) -3. After the repository has been forked, you will be taken to your copy of the FCC repo at `yourUsername/freeCodeCamp` +3. After the repository (repo) has been forked, you will be taken to your copy of the freeCodeCamp repo at #### Cloning Your Fork @@ -83,26 +81,26 @@ Platform-specific guides to setting up a development environment: $ git clone https://github.com/yourUsername/freeCodeCamp.git ``` -##### (make sure to replace `yourUsername` with your GitHub Username) +**(make sure to replace `yourUsername` with your GitHub username)** -This will download the entire FCC repo to your projects directory. +This will download the entire freeCodeCamp repo to your projects directory. #### Setup Your Upstream 1. Change directory to the new freeCodeCamp directory (`cd freeCodeCamp`) -2. Add a remote to the official FCC repo: +2. Add a remote to the official freeCodeCamp repo: ```shell $ git remote add upstream https://github.com/freeCodeCamp/freeCodeCamp.git ``` -Congratulations, you now have a local copy of the FCC repo! +Congratulations, you now have a local copy of the freeCodeCamp repo! #### Maintaining Your Fork Now that you have a copy of your fork, there is work you will need to do to keep it current. -##### **Rebasing from Upstream** +##### Rebasing from Upstream Do this prior to every time you create a branch for a PR: @@ -135,7 +133,7 @@ $ git push origin staging --force This will overwrite the staging branch of your fork. -### Create A Branch +### Create a Branch Before you start working, you will need to create a separate branch specific to the issue / feature you're working on. You will push your work to this branch. @@ -157,38 +155,19 @@ and to push to GitHub: $ git push origin [name_of_your_new_branch] ``` -##### If you need more help with branching, take a look at _[this](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches)_. +**If you need more help with branching, take a look at [this](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches).** -### Setup Linting +### Set Up Linting You should have [ESLint running in your editor](http://eslint.org/docs/user-guide/integrations.html), and it will highlight anything doesn't conform to [freeCodeCamp's JavaScript Style Guide](http://forum.freecodecamp.org/t/free-code-camp-javascript-style-guide/19121) (you can find a summary of those rules [here](https://github.com/freeCodeCamp/freeCodeCamp/blob/staging/.eslintrc)). > Please do not ignore any linting errors, as they are meant to **help** you and to ensure a clean and simple code base. +### Set Up MailHog -### Setup freeCodeCamp -Once you have freeCodeCamp cloned, before you start the application, you first need to install all of the dependencies: +To be able to log in, you need to set up MailHog. MailHod is a local SMTP mail server that will catch the emails your freeCodeCamp instance is sending. How you install MailHog is dependent upon your OS. -```bash -# Install NPM dependencies -npm install - -``` - -Then you need to add the private environment variables (API Keys): - -```bash -# Create a copy of the "sample.env" and name it as ".env". -# Populate it with the necessary API keys and secrets: -cp sample.env .env -``` -Then edit the `.env` file and modify the API keys only for services that you will use. - -Note: Not all keys are required, to run the app locally, however `MONGOHQ_URL` is the most important one. Unless you have MongoDB running in a setup different than the defaults, the URL in the sample.env should work fine. - -You can leave the other keys as they are. Keep in mind if you want to use more services you'll have to get your own API keys for those services and edit those entries accordingly in the .env file. - -Next you should setup MailHog, a local SMTP mail server that will catch all the outgoing freeCodeCamp messages generated locally. How you start up MailHog is dependent upon your OS. +#### macOS Here is how to set up MailHog on macOS with [Homebrew](https://brew.sh/): @@ -197,16 +176,43 @@ brew install mailhog brew services start mailhog ``` -Here is how to set up MailHog on Windows: +#### Windows Download the latest MailHog version from [MailHog's official repository](https://github.com/mailhog/MailHog/blob/master/docs/RELEASES.md). Click on the link for your Windows version (32 or 64 bit) and .exe file will be downloaded to your computer. Once it finishes downloading, click on the file. You will probably get a Windows firewall notification where you will have to allow access to MailHog. Once you do, a standard Windows command line prompt will open with MailHog already running. -If you want to close MailHog, simply close the command prompt. To run it again, click on the same .exe file, there is no need to download a new one. +To close MailHog, close the command prompt. To run it again, click on the same .exe file. You don't need to download a new one. To access your MailHog inbox, open your browser and navigate to [http://localhost:8025](http://localhost:8025). For any other questions related to MailHog or for instructions on custom configurations, check out the [MailHog](https://github.com/mailhog/MailHog) repository. +### Set Up freeCodeCamp + +Once you have freeCodeCamp cloned, before you start the application, you first need to install all of the dependencies: + +```bash +# Install NPM dependencies +npm install +``` + +Then you need to add the private environment variables (API Keys): + +```bash +# Create a copy of the "sample.env" and name it as ".env". +# Populate it with the necessary API keys and secrets: + +# macOS / Linux +cp sample.env .env + +# Windows +copy sample.env .env +``` +Then edit the `.env` file and modify the API keys only for services that you will use. + +Note: Not all keys are required, to run the app locally, however `MONGOHQ_URL` is the most important one. Unless you have MongoDB running in a setup different than the defaults, the URL in the sample.env should work fine. + +You can leave the other keys as they are. Keep in mind if you want to use more services you'll have to get your own API keys for those services and edit those entries accordingly in the .env file. + Now you will need to start MongoDB, and then seed the database, then you can start the application: ```bash @@ -223,14 +229,14 @@ mongod # This command should only be run once. npm run only-once -# start the application +# Start the application npm run develop ``` -Now navigate to your browser and open -. If the app loads, -congratulations – you're all set. Otherwise, let us know by asking in the [Contributors chat room](https://gitter.im/FreeCodeCamp/Contributors) on Gitter. There also might be an error in the console of your browser or in Bash / Terminal / Command Line that will help identify the problem. If the app launches but you are encountering errors with the UI itself, for example if fonts are not being loaded or if the code editor is not displaying properly, you may try the following: +Now navigate to your browser and open . If the app loads, congratulations – you're all set. +Otherwise, let us know by asking in the [Contributors chat room](https://gitter.im/FreeCodeCamp/Contributors) on Gitter. There might be an error in the console of your browser or in Bash / Terminal / Command Line that will help identify the problem. +If the app launches but you are encountering errors with the UI itself, for example if fonts are not being loaded or if the code editor is not displaying properly, you may try the following: ```bash # Remove all installed node modules rm -rf node_modules @@ -238,7 +244,7 @@ rm -rf node_modules # Reinstall npm packages npm install -# Seed the database (optional) +# Seed the database node seed # Re-start the application @@ -246,9 +252,10 @@ npm run develop ``` ### Make Changes + This bit is up to you! -#### How to find the code in the freeCodeCamp codebase to fix/edit? +#### How to find the code in the freeCodeCamp codebase to fix/edit The best way to find out any code you wish to change/add or remove is using the GitHub search bar at the top of the repository page. For example, you could @@ -258,6 +265,7 @@ that you were looking forward to edit. Always feel free to reach out to the chat room when you are not certain of any thing specific in the code. #### Changes to the seed files + If you made changes to any file in the `/seed` directory, you need to run ```shell $ node seed @@ -265,6 +273,7 @@ $ node seed in order to see the changes. ### Run The Test Suite + When you're ready to share your code, run the test suite: ```shell @@ -273,34 +282,12 @@ $ npm test and ensure all tests pass. -### Squash Your Commits -When you make a pull request, all of your changes need to be in one commit. - -If you have made more than one commit, then you will need to _squash_ your commits. - -To do this, see [Squashing Your Commits](http://forum.freecodecamp.org/t/how-to-squash-multiple-commits-into-one-with-git/13231). - -### Commit Message -When you commit your changes, please use conventional commit messages. - -The commit message should be structured as follows: -``` -[optional scope]: - -[optional body] - -[optional footer] -``` -For help writing your commit message, execute `npm run commit` from the command line and the [commitizen](http://commitizen.github.io/cz-cli/) CLI tool will assist you in creating a conventional commit message. - -Learn more at [Conventional Commits](http://conventionalcommits.org). - -### Creating A Pull Request +### Creating a Pull Request #### What is a Pull Request? A pull request (PR) is a method of submitting proposed changes to the freeCodeCamp -Repo (or any Repo, for that matter). You will make changes to copies of the +repo (or any repo, for that matter). You will make changes to copies of the files which make up freeCodeCamp in a personal fork, then apply to have them accepted by freeCodeCamp proper. @@ -356,20 +343,16 @@ nothing to commit, working directory clean add .` to add all unstaged files. Take care, though, because you can accidentally add files you don't want added. Review your `git status` first. -6. Commit your edits (follow any one of the below methods): +6. Commit your edits: We have a [tool](https://commitizen.github.io/cz-cli/) + that helps you to make standard commit messages. Execute `npm run commit` + and follow the steps. - a. Using the inbuilt script (_recommended_): - - We have a [tool](https://commitizen.github.io/cz-cli/) that helps you to make standard commit messages. Simply execute `npm run commit` after you have added the necessary files as mentioned in the step earlier. +7. [Squash your commits](http://forum.freecodecamp.org/t/how-to-squash-multiple-commits-into-one-with-git/13231) if there are more than one. - b. Using Commitizen CLI: - - If you are already using [commitizen](http://commitizen.github.io/cz-cli/), simply doing a `git cz` works as expected too! - -7. Squash your commits, if there are more than one. - -8. If you would want to add/remove changes to previous commit simply add the files as in Step 5 earlier, +8. If you would want to add/remove changes to previous commit, add the files as in Step 5 earlier, and use `git commit --amend` or `git commit --amend --no-edit` (for keeping the same commit message). -9. Push your commits to your GitHub Fork: `git push -u origin branch/name-here` +9. Push your commits to your GitHub Fork: `git push origin branch/name-here` 10. Go to [Common Steps](#common-steps) @@ -388,7 +371,7 @@ for further information 1. Once the edits have been committed, you will be prompted to create a pull request on your fork's GitHub Page. -2. By default, all pull requests should be against the FCC main repo, `staging` +2. By default, all pull requests should be against the freeCodeCamp main repo, `staging` branch. 3. Submit a [pull @@ -413,7 +396,6 @@ for further information 6. Indicate if you have tested on a local copy of the site or not. - ### How We Review and Merge Pull Requests freeCodeCamp has a team of volunteer Issue Moderators. These Issue Moderators routinely go through open pull requests in a process called [Quality Assurance](https://en.wikipedia.org/wiki/Quality_assurance) (QA). @@ -424,7 +406,6 @@ freeCodeCamp has a team of volunteer Issue Moderators. These Issue Moderators ro If you would like to apply to join our Issue Moderator team - which is a Core Team position - message [@BerkeleyTrue](https://gitter.im/berkeleytrue) with links to 5 of your pull requests that have been accepted and 5 issues where you have helped someone else through commenting or QA'ing. - ### How We Close Stale Issues We will close any issues or pull requests that have been inactive for more than 15 days, except those that match the following criteria: @@ -458,7 +439,7 @@ overwrite your old commit: `git push --force` Be sure to post in the PR conversation that you have made the requested changes. -### Other resources +### Other Resources - [Style Guide for freeCodeCamp Challenges](https://github.com/freeCodeCamp/freeCodeCamp/blob/staging/seed/challenge-style-guide.md) @@ -475,11 +456,11 @@ Be sure to post in the PR conversation that you have made the requested changes. - [How to clone the freeCodeCamp website on a Windows pc](http://forum.freecodecamp.org/t/how-to-clone-and-setup-the-free-code-camp-website-on-a-windows-pc/19366) -- [How to log in to your local FCC site - using +- [How to log in to your local freeCodeCamp site - using GitHub](http://forum.freecodecamp.org/t/how-to-log-in-to-your-local-instance-of-free-code-camp/19552) - [Writing great git commit messages](http://forum.freecodecamp.org/t/writing-good-git-commit-messages/13210) -- [Contributor Chat Support - For the FCC Repositories, and running a local +- [Contributor Chat Support - For the freeCodeCamp repositories, and running a local instance](https://gitter.im/FreeCodeCamp/Contributors) From 2884b551c363d3b4c12006b53aebfe004803533f Mon Sep 17 00:00:00 2001 From: Stuart Taylor Date: Thu, 28 Dec 2017 18:47:42 +0000 Subject: [PATCH 032/108] fix(classNames): Use block prop for .btn-block className --- common/app/routes/Challenges/Tool-Panel.jsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/app/routes/Challenges/Tool-Panel.jsx b/common/app/routes/Challenges/Tool-Panel.jsx index d46b5ae509..6a08a93269 100644 --- a/common/app/routes/Challenges/Tool-Panel.jsx +++ b/common/app/routes/Challenges/Tool-Panel.jsx @@ -112,24 +112,27 @@ export default class ToolPanel extends PureComponent { }