From 0acf575788c0aa1079a7c872b51b0175944f5dff Mon Sep 17 00:00:00 2001 From: Tejas Bubane Date: Thu, 1 Feb 2018 12:34:55 +0530 Subject: [PATCH 01/39] Use LTS version of node in travis-ci (#497) As suggested in https://github.com/exercism/javascript/issues/462. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2b97b13d..45fde31c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: node_js sudo: false node_js: - - "node" + - "lts/*" install: - "npm install" From ffbf14cf7863d6512a0a3a79317317b6dfa2e42b Mon Sep 17 00:00:00 2001 From: Ajo John Date: Mon, 12 Feb 2018 22:08:32 +0530 Subject: [PATCH 02/39] Fixes: Alphametic Lint Fixes (#499) Tested both alphametics.spec.js and example.js . Found no eslint errors in both files. Removed these files from .eslintignore. --- .eslintignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index e3e9691a..f3d52c45 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,4 @@ big-integer.js -exercises/alphametics exercises/binary-search exercises/binary-search-tree exercises/bracket-push From 9f6c1eb4757b085d3ae292a9d7e342ad29f98d65 Mon Sep 17 00:00:00 2001 From: Ajo John Date: Tue, 13 Feb 2018 21:53:39 +0530 Subject: [PATCH 03/39] Fix eslint errors in multiple exercises * binary-search * binary-search-tree * bracket-push * leap * list-ops * luhn * pythagorean-triplet * roman-numerals --- .eslintignore | 8 -------- exercises/binary-search-tree/example.js | 4 ++-- exercises/binary-search/example.js | 2 +- exercises/bracket-push/example.js | 2 +- exercises/leap/example.js | 10 +++++++--- exercises/leap/leap.js | 4 ++-- exercises/list-ops/example.js | 2 +- exercises/luhn/example.js | 4 ++-- exercises/pythagorean-triplet/example.js | 3 ++- exercises/roman-numerals/example.js | 5 +++-- 10 files changed, 21 insertions(+), 23 deletions(-) diff --git a/.eslintignore b/.eslintignore index f3d52c45..a6052eb7 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,24 +1,16 @@ big-integer.js -exercises/binary-search -exercises/binary-search-tree -exercises/bracket-push exercises/custom-set exercises/flatten-array exercises/grade-school exercises/grains/big-integer.js exercises/grains/big-integer.spec.js exercises/kindergarten-garden -exercises/leap exercises/linked-list -exercises/list-ops -exercises/luhn exercises/minesweeper exercises/nth-prime exercises/perfect-numbers -exercises/pythagorean-triplet exercises/queen-attack exercises/robot-simulator -exercises/roman-numerals exercises/saddle-points exercises/secret-handshake exercises/simple-cipher diff --git a/exercises/binary-search-tree/example.js b/exercises/binary-search-tree/example.js index 6b4665b6..edc3af96 100644 --- a/exercises/binary-search-tree/example.js +++ b/exercises/binary-search-tree/example.js @@ -2,8 +2,8 @@ function BinarySearchTree(data) { this.data = data; - this.left = undefined; - this.right = undefined; + this.left = null; + this.right = null; } BinarySearchTree.prototype.insert = function (value) { diff --git a/exercises/binary-search/example.js b/exercises/binary-search/example.js index a4e6095c..a1fd178f 100644 --- a/exercises/binary-search/example.js +++ b/exercises/binary-search/example.js @@ -18,7 +18,7 @@ function BinarySearch(array) { function recursiveSearch(array, value, start, end) { - if (start == end) return -1; + if (start === end) return -1; var mid = Math.floor((start + end) / 2); diff --git a/exercises/bracket-push/example.js b/exercises/bracket-push/example.js index ab3d22d3..ace16508 100644 --- a/exercises/bracket-push/example.js +++ b/exercises/bracket-push/example.js @@ -28,7 +28,7 @@ var bracketPush = module.exports = function (input) { for (var k = 0; k < 3; k++) { if (bracketArray[topNumber] === openArray[k]) { - if (typeof bracketArray[(topNumber + 1)] !== undefined) { + if (typeof bracketArray[(topNumber + 1)] !== 'undefined') { if (bracketArray[(topNumber + 1)] === closeArray[k]) { bracketArray.splice(topNumber, 2); return bracketPush(bracketArray); diff --git a/exercises/leap/example.js b/exercises/leap/example.js index bbe7eceb..653dbe45 100644 --- a/exercises/leap/example.js +++ b/exercises/leap/example.js @@ -3,9 +3,11 @@ /** * Represents a year to check whether is leap or not * - * @param {number} year + * @param {number} year + * * Numeric year. */ + function Year(year) { this.year = year; } @@ -13,11 +15,13 @@ function Year(year) { /** * Whether given year is a leap year. * - * @return {boolean} + * @returns {boolean} + * * Whether given year is a leap year. */ + Year.prototype.isLeap = function () { - return (this.year % 400 == 0) || ((this.year % 4 == 0) && (this.year % 100 != 0)); + return (this.year % 400 === 0) || ((this.year % 4 === 0) && (this.year % 100 !== 0)); }; module.exports = Year; diff --git a/exercises/leap/leap.js b/exercises/leap/leap.js index 22b6bb5c..5329bf2d 100644 --- a/exercises/leap/leap.js +++ b/exercises/leap/leap.js @@ -3,10 +3,10 @@ // convenience to get you started writing code faster. // -var Year = function (input) { +var Year = function () { // // YOUR CODE GOES HERE -// +// }; Year.prototype.isLeap = function () { diff --git a/exercises/list-ops/example.js b/exercises/list-ops/example.js index c32141e7..f47d84b9 100644 --- a/exercises/list-ops/example.js +++ b/exercises/list-ops/example.js @@ -56,7 +56,7 @@ List.prototype = { return new List(this.foldl(this.cons, [])); }, - map: function (func, arr) { + map: function (func) { var applyFuncThenCons = function (x, acc) { return this.cons(func(x), acc); }; diff --git a/exercises/luhn/example.js b/exercises/luhn/example.js index b311427f..cc38e98f 100644 --- a/exercises/luhn/example.js +++ b/exercises/luhn/example.js @@ -1,8 +1,8 @@ 'use strict'; function isValid(number) { - number = number.replace(/\s/g, ''); - const digits = [...number]; + var numbers = number.replace(/\s/g, ''); + const digits = [...numbers]; const sum = digits // convert to integers diff --git a/exercises/pythagorean-triplet/example.js b/exercises/pythagorean-triplet/example.js index 44f4edf4..a30323bc 100644 --- a/exercises/pythagorean-triplet/example.js +++ b/exercises/pythagorean-triplet/example.js @@ -35,7 +35,8 @@ Triplets.prototype.isDesired = function (triplet) { }; Triplets.prototype.toArray = function () { - var triplet, triplets = []; + var triplet = []; + var triplets = []; for (var a = this.min; a < this.max - 1; a++) { for (var b = a + 1; b < this.max; b++) { for (var c = b + 1; c <= this.max; c++) { diff --git a/exercises/roman-numerals/example.js b/exercises/roman-numerals/example.js index 40e8ddf0..a39d19cc 100644 --- a/exercises/roman-numerals/example.js +++ b/exercises/roman-numerals/example.js @@ -2,6 +2,7 @@ module.exports = function (number) { var result = ''; + var numbers = number; var mappings = [ {arabic: 1000, roman: 'M'}, {arabic: 900, roman: 'CM'}, @@ -20,9 +21,9 @@ module.exports = function (number) { for (var i = 0; i < mappings.length; i++) { var mapping = mappings[i]; - while (number >= mapping.arabic) { + while (numbers >= mapping.arabic) { result = result + mapping.roman; - number = number - mapping.arabic; + numbers = numbers - mapping.arabic; } } From 124e4968d1201a206f7168c9d611b8194f389c11 Mon Sep 17 00:00:00 2001 From: Ajo John Date: Mon, 19 Feb 2018 23:51:44 +0530 Subject: [PATCH 04/39] Move eslint config to package.json And remove the `.eslintconfig.json` file. Closes #456 --- .eslintrc.json | 10 ---------- package.json | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) delete mode 100644 .eslintrc.json diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 50b380a4..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "plugins": ["jasmine"], - "extends": "eslint-config-airbnb-es5", - "env": { - "jasmine": true - }, - "rules": { - "func-names": "off" - } -} diff --git a/package.json b/package.json index 8feba32a..cac2593c 100644 --- a/package.json +++ b/package.json @@ -19,5 +19,15 @@ "scripts": { "lint": "eslint .", "lint-fix": "eslint . --fix" + }, + "eslintConfig": { + "plugins": ["jasmine"], + "env": { + "jasmine": true + }, + "extends": "eslint-config-airbnb-es5", + "rules": { + "func-names": "off" + } } } From 8e151d92f82c9099359ee1d119a0143788c150eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Rivas=20G=C3=B3mez?= Date: Wed, 28 Feb 2018 01:48:20 +0100 Subject: [PATCH 05/39] Add new exercise Rotational Cipher (#504) * Add new exercise Rotational Cipher * Fix linting and tests --- config.json | 12 ++++ exercises/rotational-cipher/README.md | 64 +++++++++++++++++++ exercises/rotational-cipher/example.js | 24 +++++++ .../rotational-cipher.spec.js | 55 ++++++++++++++++ 4 files changed, 155 insertions(+) create mode 100644 exercises/rotational-cipher/README.md create mode 100644 exercises/rotational-cipher/example.js create mode 100644 exercises/rotational-cipher/rotational-cipher.spec.js diff --git a/config.json b/config.json index 479a7e3b..cda1f322 100644 --- a/config.json +++ b/config.json @@ -206,6 +206,18 @@ ], "uuid": "0a3a452c-f734-47eb-8e65-34c8ae710ef0" }, + { + "core": false, + "difficulty": 6, + "slug": "rotational-cipher", + "topics": [ + "cryptography", + "integers", + "strings" + ], + "unlocked_by": "secret-handshake", + "uuid": "7078b1a4-ef73-4c02-809d-b2de62e9af11" + }, { "core": true, "difficulty": 6, diff --git a/exercises/rotational-cipher/README.md b/exercises/rotational-cipher/README.md new file mode 100644 index 00000000..01384ca3 --- /dev/null +++ b/exercises/rotational-cipher/README.md @@ -0,0 +1,64 @@ +# Rotational Cipher + +Create an implementation of the rotational cipher, also sometimes called the Caesar cipher. + +The Caesar cipher is a simple shift cipher that relies on +transposing all the letters in the alphabet using an integer key +between `0` and `26`. Using a key of `0` or `26` will always yield +the same output due to modular arithmetic. The letter is shifted +for as many values as the value of the key. + +The general notation for rotational ciphers is `ROT + `. +The most commonly used rotational cipher is `ROT13`. + +A `ROT13` on the Latin alphabet would be as follows: + +```text +Plain: abcdefghijklmnopqrstuvwxyz +Cipher: nopqrstuvwxyzabcdefghijklm +``` + +It is stronger than the Atbash cipher because it has 27 possible keys, and 25 usable keys. + +Ciphertext is written out in the same formatting as the input including spaces and punctuation. + +## Examples + +- ROT5 `omg` gives `trl` +- ROT0 `c` gives `c` +- ROT26 `Cool` gives `Cool` +- ROT13 `The quick brown fox jumps over the lazy dog.` gives `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` +- ROT13 `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` gives `The quick brown fox jumps over the lazy dog.` + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine rotational-cipher.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Wikipedia [https://en.wikipedia.org/wiki/Caesar_cipher](https://en.wikipedia.org/wiki/Caesar_cipher) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/rotational-cipher/example.js b/exercises/rotational-cipher/example.js new file mode 100644 index 00000000..fa3e7baa --- /dev/null +++ b/exercises/rotational-cipher/example.js @@ -0,0 +1,24 @@ +var RotationalCipher = function () {}; + +RotationalCipher.prototype.rotate = function (text, shiftKey) { + if (text.length === 1) { + if (text.charCodeAt(0) >= 97 && text.charCodeAt(0) <= 122) return this.rotateLowerCase(text, shiftKey); + if (text.charCodeAt(0) >= 65 && text.charCodeAt(0) <= 90) return this.rotateUpperCase(text, shiftKey); + return text; + } + return this.rotate(text.charAt(0), shiftKey) + this.rotate(text.slice(1), shiftKey); +}; + +RotationalCipher.prototype.rotateLowerCase = function (letter, shiftKey) { + var rotatedLowerCase = String.fromCharCode(letter.charCodeAt(0) + shiftKey); + if (rotatedLowerCase.charCodeAt(0) > 122) rotatedLowerCase = String.fromCharCode(rotatedLowerCase.charCodeAt(0) - 26); + return rotatedLowerCase; +}; + +RotationalCipher.prototype.rotateUpperCase = function (letter, shiftKey) { + var rotatedUpperCase = String.fromCharCode(letter.charCodeAt(0) + shiftKey); + if (rotatedUpperCase.charCodeAt(0) > 90) rotatedUpperCase = String.fromCharCode(rotatedUpperCase.charCodeAt(0) - 26); + return rotatedUpperCase; +}; + +module.exports = RotationalCipher; diff --git a/exercises/rotational-cipher/rotational-cipher.spec.js b/exercises/rotational-cipher/rotational-cipher.spec.js new file mode 100644 index 00000000..5e6f864d --- /dev/null +++ b/exercises/rotational-cipher/rotational-cipher.spec.js @@ -0,0 +1,55 @@ +var RotationalCipher = require('./rotational-cipher'); + +describe('RotationalCipher', function () { + var rotationalCipher = new RotationalCipher(); + + it('rotate a by 0, same output as input', function () { + var expected = 'a'; + expect(rotationalCipher.rotate('a', 0)).toEqual(expected); + }); + + xit('rotate a by 1', function () { + var expected = 'b'; + expect(rotationalCipher.rotate('a', 1)).toEqual(expected); + }); + + xit('rotate a by 26, same output as input', function () { + var expected = 'a'; + expect(rotationalCipher.rotate('a', 26)).toEqual(expected); + }); + + xit('rotate m by 13', function () { + var expected = 'z'; + expect(rotationalCipher.rotate('m', 13)).toEqual(expected); + }); + + xit('rotate n by 13 with wrap around alphabet', function () { + var expected = 'a'; + expect(rotationalCipher.rotate('n', 13)).toEqual(expected); + }); + + xit('rotate capital letters', function () { + var expected = 'TRL'; + expect(rotationalCipher.rotate('OMG', 5)).toEqual(expected); + }); + + xit('rotate spaces', function () { + var expected = 'T R L'; + expect(rotationalCipher.rotate('O M G', 5)).toEqual(expected); + }); + + xit('rotate numbers', function () { + var expected = 'Xiwxmrk 1 2 3 xiwxmrk'; + expect(rotationalCipher.rotate('Testing 1 2 3 testing', 4)).toEqual(expected); + }); + + xit('rotate punctuation', function () { + var expected = 'Gzo\'n zvo, Bmviyhv!'; + expect(rotationalCipher.rotate('Let\'s eat, Grandma!', 21)).toEqual(expected); + }); + + xit('rotate all letters', function () { + var expected = 'Gur dhvpx oebja sbk whzcf bire gur ynml qbt.'; + expect(rotationalCipher.rotate('The quick brown fox jumps over the lazy dog.', 13)).toEqual(expected); + }); +}); From 09c859b378d173ba86bae2e3116d50fde82ced82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Rivas=20G=C3=B3mez?= Date: Wed, 28 Feb 2018 23:34:14 +0100 Subject: [PATCH 06/39] Add new exercise Rational Numbers (#506) * Add new exercise Rational Numbers * Rename rational.spec.js to rational-numbers.spec.js * Remove rational.spec.js * Fix module path * Fix naming * Fix difficulty estimation --- config.json | 12 ++ exercises/rational-numbers/README.md | 62 ++++++ exercises/rational-numbers/example.js | 69 ++++++ .../rational-numbers/rational-numbers.spec.js | 197 ++++++++++++++++++ 4 files changed, 340 insertions(+) create mode 100644 exercises/rational-numbers/README.md create mode 100644 exercises/rational-numbers/example.js create mode 100644 exercises/rational-numbers/rational-numbers.spec.js diff --git a/config.json b/config.json index cda1f322..b10b081d 100644 --- a/config.json +++ b/config.json @@ -268,6 +268,18 @@ ], "uuid": "e70defe4-5944-4392-956c-63cb92e7fd9c" }, + { + "core": false, + "difficulty": 5, + "slug": "rational-numbers", + "topics": [ + "floating_point_numbers", + "mathematics", + "algorithms" + ], + "unlocked_by": "pascals-triangle", + "uuid": "2de5677e-5759-4a21-93c7-39a3d88242e8" + }, { "core": false, "difficulty": 2, diff --git a/exercises/rational-numbers/README.md b/exercises/rational-numbers/README.md new file mode 100644 index 00000000..12cb067b --- /dev/null +++ b/exercises/rational-numbers/README.md @@ -0,0 +1,62 @@ +# Rational Numbers + +A rational number is defined as the quotient of two integers `a` and `b`, called the numerator and denominator, respectively, where `b != 0`. + +The absolute value `|r|` of the rational number `r = a/b` is equal to `|a|/|b|`. + +The sum of two rational numbers `r1 = a1/b1` and `r2 = a2/b2` is `r1 + r2 = a1/b1 + a2/b2 = (a1 * b2 + a2 * b1) / (b1 * b2)`. + +The difference of two rational numbers `r1 = a1/b1` and `r2 = a2/b2` is `r1 - r2 = a1/b1 - a2/b2 = (a1 * b2 - a2 * b1) / (b1 * b2)`. + +The product (multiplication) of two rational numbers `r1 = a1/b1` and `r2 = a2/b2` is `r1 * r2 = (a1 * a2) / (b1 * b2)`. + +Dividing a rational number `r1 = a1/b1` by another `r2 = a2/b2` is `r1 / r2 = (a1 * b2) / (a2 * b1)` if `a2 * b1` is not zero. + +Exponentiation of a rational number `r = a/b` to a non-negative integer power `n` is `r^n = (a^n)/(b^n)`. + +Exponentiation of a rational number `r = a/b` to a negative integer power `n` is `r^n = (b^m)/(a^m)`, where `m = |n|`. + +Exponentiation of a rational number `r = a/b` to a real (floating-point) number `x` is the quotient `(a^x)/(b^x)`, which is a real number. + +Exponentiation of a real number `x` to a rational number `r = a/b` is `x^(a/b) = root(x^a, b)`, where `root(p, q)` is the `q`th root of `p`. + +Implement the following operations: + - addition, subtraction, multiplication and division of two rational numbers, + - absolute value, exponentiation of a given rational number to an integer power, exponentiation of a given rational number to a real (floating-point) power, exponentiation of a real number to a rational number. + +Your implementation of rational numbers should always be reduced to lowest terms. For example, `4/4` should reduce to `1/1`, `30/60` should reduce to `1/2`, `12/8` should reduce to `3/2`, etc. To reduce a rational number `r = a/b`, divide `a` and `b` by the greatest common divisor (gcd) of `a` and `b`. So, for example, `gcd(12, 8) = 4`, so `r = 12/8` can be reduced to `(12/4)/(8/4) = 3/2`. + +Assume that the programming language you are using does not have an implementation of rational numbers. + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine rational-numbers.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Wikipedia [https://en.wikipedia.org/wiki/Rational_number](https://en.wikipedia.org/wiki/Rational_number) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/rational-numbers/example.js b/exercises/rational-numbers/example.js new file mode 100644 index 00000000..cd95bdc1 --- /dev/null +++ b/exercises/rational-numbers/example.js @@ -0,0 +1,69 @@ +function Rational(numerator, denominator) { + if (denominator === 0) {throw new Error('Denominator must not be zero.');} + + this.numerator = numerator; + this.denominator = denominator; + + this.reduce(); + this.ensureSignInNumerator(); +} + +Rational.prototype.add = function (that) { + var commonDenominator = this.denominator * that.denominator; + return new Rational(this.numerator * that.denominator + that.numerator * this.denominator, commonDenominator); +}; + +Rational.prototype.sub = function (that) { + var commonDenominator = this.denominator * that.denominator; + return new Rational(this.numerator * that.denominator - that.numerator * this.denominator, commonDenominator); +}; + +Rational.prototype.mul = function (that) { + return new Rational(this.numerator * that.numerator, this.denominator * that.denominator); +}; + +Rational.prototype.div = function (that) { + return new Rational(this.numerator * that.denominator, this.denominator * that.numerator); +}; + +Rational.prototype.abs = function () { + return new Rational(Math.abs(this.numerator), Math.abs(this.denominator)); +}; + +Rational.prototype.exprational = function (n) { + return new Rational(Math.pow(this.numerator, n), Math.pow(this.denominator, n)); +}; + +Rational.prototype.expreal = function (base) { + return Math.pow(10.0, Math.log10(Math.pow(base, this.numerator)) / this.denominator); +}; + +Rational.prototype.reduce = function () { + var commonDivisor = this.gcd(this.numerator, this.denominator); + + this.numerator /= commonDivisor; + this.denominator /= commonDivisor; + this.ensureSignInNumerator(); + + return this; +}; + +Rational.prototype.gcd = function (a, b) { + var localA = a; + var localB = b; + while (localB !== 0) { + var t = localB; + localB = localA % localB; + localA = t; + } + return localA; +}; + +Rational.prototype.ensureSignInNumerator = function () { + if (this.denominator < 0) { + this.denominator = -this.denominator; + this.numerator = -this.numerator; + } +}; + +module.exports = Rational; diff --git a/exercises/rational-numbers/rational-numbers.spec.js b/exercises/rational-numbers/rational-numbers.spec.js new file mode 100644 index 00000000..b11c7ed3 --- /dev/null +++ b/exercises/rational-numbers/rational-numbers.spec.js @@ -0,0 +1,197 @@ +var Rational = require('./rational-numbers'); + +describe('Addition', function () { + it('Add two positive rational numbers', function () { + var expected = new Rational(7, 6); + expect(new Rational(1, 2).add(new Rational(2, 3))).toEqual(expected); + }); + + xit('Add a positive rational number and a negative rational number', function () { + var expected = new Rational(-1, 6); + expect(new Rational(1, 2).add(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Add two negative rational numbers', function () { + var expected = new Rational(-7, 6); + expect(new Rational(-1, 2).add(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Add a rational number to its additive inverse', function () { + var expected = new Rational(0, 1); + expect(new Rational(1, 2).add(new Rational(-1, 2))).toEqual(expected); + }); +}); + +describe('Subtraction', function () { + xit('Subtract two positive rational numbers', function () { + var expected = new Rational(-1, 6); + expect(new Rational(1, 2).sub(new Rational(2, 3))).toEqual(expected); + }); + + xit('Subtract a positive rational number and a negative rational number', function () { + var expected = new Rational(7, 6); + expect(new Rational(1, 2).sub(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Subtract two negative rational numbers', function () { + var expected = new Rational(1, 6); + expect(new Rational(-1, 2).sub(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Subtract a rational number from itself', function () { + var expected = new Rational(0, 1); + expect(new Rational(1, 2).sub(new Rational(1, 2))).toEqual(expected); + }); +}); + +describe('Multiplication', function () { + xit('Multiply two positive rational numbers', function () { + var expected = new Rational(1, 3); + expect(new Rational(1, 2).mul(new Rational(2, 3))).toEqual(expected); + }); + + xit('Multiply a negative rational number by a positive rational number', function () { + var expected = new Rational(-1, 3); + expect(new Rational(-1, 2).mul(new Rational(2, 3))).toEqual(expected); + }); + + xit('Multiply two negative rational numbers', function () { + var expected = new Rational(1, 3); + expect(new Rational(-1, 2).mul(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Multiply a rational number by its reciprocal', function () { + var expected = new Rational(1, 1); + expect(new Rational(1, 2).mul(new Rational(2, 1))).toEqual(expected); + }); + + xit('Multiply a rational number by 1', function () { + var expected = new Rational(1, 2); + expect(new Rational(1, 2).mul(new Rational(1, 1))).toEqual(expected); + }); + + xit('Multiply a rational number by 0', function () { + var expected = new Rational(0, 1); + expect(new Rational(1, 2).mul(new Rational(0, 1))).toEqual(expected); + }); +}); + +describe('Division', function () { + xit('Divide two positive rational numbers', function () { + var expected = new Rational(3, 4); + expect(new Rational(1, 2).div(new Rational(2, 3))).toEqual(expected); + }); + + xit('Divide a positive rational number by a negative rational number', function () { + var expected = new Rational(-3, 4); + expect(new Rational(1, 2).div(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Divide two negative rational numbers', function () { + var expected = new Rational(3, 4); + expect(new Rational(-1, 2).div(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Divide a rational number by 1', function () { + var expected = new Rational(1, 2); + expect(new Rational(1, 2).div(new Rational(1, 1))).toEqual(expected); + }); +}); + +describe('Absolute value', function () { + xit('Absolute value of a positive rational number', function () { + var expected = new Rational(1, 2); + expect(new Rational(1, 2).abs()).toEqual(expected); + }); + + xit('Absolute value of a negative rational number', function () { + var expected = new Rational(1, 2); + expect(new Rational(-1, 2).abs()).toEqual(expected); + }); + + xit('Absolute value of zero', function () { + var expected = new Rational(0, 1); + expect(new Rational(0, 1).abs()).toEqual(expected); + }); +}); + +describe('Exponentiation of a rational number', function () { + xit('Raise a positive rational number to a positive integer power', function () { + var expected = new Rational(1, 8); + expect(new Rational(1, 2).exprational(3)).toEqual(expected); + }); + + xit('Raise a negative rational number to a positive integer power', function () { + var expected = new Rational(-1, 8); + expect(new Rational(-1, 2).exprational(3)).toEqual(expected); + }); + + xit('Raise zero to an integer power', function () { + var expected = new Rational(0, 1); + expect(new Rational(0, 1).exprational(5)).toEqual(expected); + }); + + xit('Raise one to an integer power', function () { + var expected = new Rational(1, 1); + expect(new Rational(1, 1).exprational(4)).toEqual(expected); + }); + + xit('Raise a positive rational number to the power of zero', function () { + var expected = new Rational(1, 1); + expect(new Rational(1, 2).exprational(0)).toEqual(expected); + }); + + xit('Raise a negative rational number to the power of zero', function () { + var expected = new Rational(1, 1); + expect(new Rational(-1, 2).exprational(0)).toEqual(expected); + }); +}); + +describe('Exponentiation of a real number to a rational number', function () { + xit('Raise a real number to a positive rational number', function () { + var expected = 16.0; + expect(new Rational(4, 3).expreal(8)).toEqual(expected); + }); + + xit('Raise a real number to a negative rational number', function () { + var expected = 0.3333333333333333; + expect(new Rational(-1, 2).expreal(9)).toEqual(expected); + }); + + xit('Raise a real number to a zero rational number', function () { + var expected = 1.0; + expect(new Rational(0, 1).expreal(2)).toEqual(expected); + }); +}); + +describe('Reduction to lowest terms', function () { + xit('Reduce a positive rational number to lowest terms', function () { + var expected = new Rational(1, 2); + expect(new Rational(2, 4).reduce()).toEqual(expected); + }); + + xit('Reduce a negative rational number to lowest terms', function () { + var expected = new Rational(-2, 3); + expect(new Rational(-4, 6).reduce()).toEqual(expected); + }); + + xit('Reduce a rational number with a negative denominator to lowest terms', function () { + var expected = new Rational(-1, 3); + expect(new Rational(3, -9).reduce()).toEqual(expected); + }); + + xit('Reduce zero to lowest terms', function () { + var expected = new Rational(0, 1); + expect(new Rational(0, 6).reduce()).toEqual(expected); + }); + + xit('Reduce an integer to lowest terms', function () { + var expected = new Rational(-2, 1); + expect(new Rational(-14, 7).reduce()).toEqual(expected); + }); + + xit('Reduce one to lowest terms', function () { + var expected = new Rational(1, 1); + expect(new Rational(13, 13).reduce()).toEqual(expected); + }); +}); From 1b610b8c585fb86f524e414bc47936fbba82241d Mon Sep 17 00:00:00 2001 From: Daniel Jordan <12012148+danielj-jordan@users.noreply.github.com> Date: Thu, 1 Mar 2018 02:46:03 -0800 Subject: [PATCH 07/39] redo the bowling exericse to match the canonical tests and description (#496) --- exercises/bowling/bowling.spec.js | 146 ++++++++++++++++++------- exercises/bowling/example.js | 171 +++++++++++++++++++----------- 2 files changed, 217 insertions(+), 100 deletions(-) diff --git a/exercises/bowling/bowling.spec.js b/exercises/bowling/bowling.spec.js index 1d6746de..a507da47 100644 --- a/exercises/bowling/bowling.spec.js +++ b/exercises/bowling/bowling.spec.js @@ -1,147 +1,211 @@ var Bowling = require('./bowling'); describe('Bowling', function () { + function previousRolls(bowling, rolls) { + for (var i = 0; i < rolls.length; i++) { + bowling.roll(rolls[i]); + } + } describe('Check game can be scored correctly.', function () { it('should be able to score a game with all gutterballs', function () { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(0); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(0); }); - xit('should be able to score a game with all open frames', function () { + xit('should be able to score a game with no strikes or spares', function () { var rolls = [3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6]; - expect(new Bowling(rolls).score()).toEqual(90); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(90); }); - xit('a spare followed by zeros is worth 10 points', function () { + xit('a spare followed by zeros is worth ten points', function () { var rolls = [6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(10); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(10); }); xit('points scored in the roll after a spare are counted twice', function () { var rolls = [6, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(16); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(16); }); xit('consecutive spares each get a one-roll bonus', function () { var rolls = [5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(31); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(31); }); - xit('should allow fill ball when the last frame is a spare', function () { + xit('should allow fill ball the last frame is a spare', function () { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7]; - expect(new Bowling(rolls).score()).toEqual(17); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(17); }); - xit('a strike earns 10 points in a frame with a single roll', function () { + xit('a strike earns ten points in a frame with a single roll', function () { var rolls = [10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(10); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(10); }); xit('points scored in the two rolls after a strike are counted twice as a bonus', function () { var rolls = [10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(26); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(26); }); xit('should be able to score multiple strikes in a row', function () { var rolls = [10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(81); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(81); }); xit('should allow fill balls when the last frame is a strike', function () { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 1]; - expect(new Bowling(rolls).score()).toEqual(18); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(18); }); xit('rolling a spare with the two-roll bonus does not get a bonus roll', function () { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 3]; - expect(new Bowling(rolls).score()).toEqual(20); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(20); }); xit('strikes with the two-roll bonus do not get bonus rolls', function () { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10]; - expect(new Bowling(rolls).score()).toEqual(30); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(30); }); xit('a strike with the one-roll bonus after a spare in the last frame does not get a bonus', function () { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 10]; - expect(new Bowling(rolls).score()).toEqual(20); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(20); }); xit('should be able to score a perfect game', function () { var rolls = [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]; - expect(new Bowling(rolls).score()).toEqual(300); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(300); }); }); describe('Check game rules.', function () { xit('rolls cannot score negative points', function () { - var rolls = [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(function () { new Bowling(rolls).score(); }).toThrow( - new Error('Pins must have a value from 0 to 10')); + var bowling = new Bowling(); + expect(function () {bowling.roll(-1);}).toThrow(new Error('Negative roll is invalid')); }); xit('a roll cannot score more than 10 points', function () { - var rolls = [11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(function () { new Bowling(rolls).score(); }).toThrow( - new Error('Pins must have a value from 0 to 10')); + var bowling = new Bowling(); + expect(function () {bowling.roll(11);}).toThrow( new Error('Pin count exceeds pins on the lane')); }); xit('two rolls in a frame cannot score more than 10 points', function () { - var rolls = [5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(function () { new Bowling(rolls).score(); }).toThrow( + var bowling = new Bowling(); + bowling.roll(5); + expect(function () {bowling.roll(6);}).toThrow( new Error('Pin count exceeds pins on the lane')); + }); + + xit('bonus roll after a strike in the last frame cannot score more than 10 points', function () { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.roll(11); }).toThrow( new Error('Pin count exceeds pins on the lane')); }); xit('two bonus rolls after a strike in the last frame cannot score more than 10 points', function () { - var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 6]; - expect(function () { new Bowling(rolls).score(); }).toThrow( - new Error('Pin count exceeds pins on the lane')); + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () {bowling.roll(6);}).toThrow( new Error('Pin count exceeds pins on the lane')); }); xit('two bonus rolls after a strike in the last frame can score more than 10 points if one is a strike', function () { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 6]; - expect(new Bowling(rolls).score()).toEqual(26); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(26); }); xit('the second bonus roll after a strike in the last frame cannot be a strike if the first one is not a strike', function () { - var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6, 10]; - expect(function () { new Bowling(rolls).score(); }).toThrow( + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.roll(10); }).toThrow( + new Error('Pin count exceeds pins on the lane')); + }); + + xit('the second bonus roll after a strike in the last frame cannot score more than 10 points', function () { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.roll(11); }).toThrow( new Error('Pin count exceeds pins on the lane')); }); xit('an unstarted game cannot be scored', function () { var rolls = []; - expect(function () { new Bowling(rolls).score(); }).toThrow( + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.score(); }).toThrow( new Error('Score cannot be taken until the end of the game')); }); xit('an incomplete game cannot be scored', function () { var rolls = [0, 0]; - expect(function () { new Bowling(rolls).score(); }).toThrow( + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.score(); }).toThrow( new Error('Score cannot be taken until the end of the game')); }); - xit('a game with more than 10 frames and no last frame spare or strike cannot be scored', function () { - var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(function () { new Bowling(rolls).score(); }).toThrow( - new Error('Should not be able to roll after game is over')); + xit('cannot roll if game already has 10 frames', function () { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.roll(0); }).toThrow( + new Error('Cannot roll after game is over')); }); xit('bonus rolls for a strike in the last frame must be rolled before score can be calculated', function () { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10]; - expect(function () { new Bowling(rolls).score(); }).toThrow( + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.score(); }).toThrow( new Error('Score cannot be taken until the end of the game')); }); xit('both bonus rolls for a strike in the last frame must be rolled before score can be calculated', function () { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10]; - expect(function () { new Bowling(rolls).score(); }).toThrow( + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () {bowling.score(); }).toThrow( new Error('Score cannot be taken until the end of the game')); }); xit('bonus roll for a spare in the last frame must be rolled before score can be calculated', function () { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3]; - expect(function () { new Bowling(rolls).score(); }).toThrow( + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.score(); }).toThrow( new Error('Score cannot be taken until the end of the game')); }); }); diff --git a/exercises/bowling/example.js b/exercises/bowling/example.js index b46142ad..ea2a29b1 100644 --- a/exercises/bowling/example.js +++ b/exercises/bowling/example.js @@ -1,82 +1,135 @@ 'use strict'; -function Bowling(rolls) { - this.rolls = rolls; -} - -Bowling.prototype.score = function () { - var maxFrames = 10; +function Bowling() { var maxPins = 10; + var maxFrames = 10; + var frames = []; + var frameScores = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - var initialState = { - frameNumber: 1, - rollNumber: 1, - pinsRemaining: 10, - spareLastFrame: false, - strikeLastFrame: false, - twoStrikesInARow: false, - fillBall: false, - score: 0 - }; + var currentFrame = 0; + var frameRoll = 1; + var remainingPins = maxPins; - var finalState = this.rolls.reduce(function (state, roll) { - if (roll < 0 || roll > maxFrames ) { - throw new Error('Pins must have a value from 0 to 10'); - } + initializeFrame(); - if (roll > state.pinsRemaining) { - throw new Error('Pin count exceeds pins on the lane'); + function initializeFrame() { + frameRoll = 1; + remainingPins = maxPins; + currentFrame++; + } + + function incrementScore(pins) { + if (currentFrame > maxFrames) return; + frameScores[currentFrame - 1] += pins; + } + + function scoreStrike() { + frames[currentFrame - 1] = 'X'; + applyStrikeBonus(maxPins); + applySpareBonus(maxPins); + frameRoll++; + } + + function scoreFirstRoll(pins) { + remainingPins = remainingPins - pins; + applySpareBonus(pins); + applyStrikeBonus(pins); + frameRoll++; + } + + function scoreSpare(pins) { + frames[currentFrame - 1] = 'S'; + applyStrikeBonus(pins); + frameRoll++; + } + + function scoreOpenFrame(pins) { + frames[currentFrame - 1] = (maxPins - remainingPins) + pins; + applyStrikeBonus(pins); + frameRoll++; + } + + function applySpareBonus(pins) { + // pins on the first roll after a spare are counted twice (on the frame of spare) + if (frames[currentFrame - 2] === 'S' ) { + frameScores[currentFrame - 2] += pins; } + } - if (state.frameNumber > maxFrames ) { - throw new Error('Should not be able to roll after game is over'); + function applyStrikeBonus(pins) { + // on the two rolls after a strike are counted twice (on the frame of the strike) + if (frames[currentFrame - 3] === 'X' && frames[currentFrame - 2] === 'X' && + frameRoll === 1 && currentFrame <= (maxFrames + 2)) { + frameScores[currentFrame - 3] += pins; + } + if (frames[currentFrame - 2] === 'X' && currentFrame <= (maxFrames + 1)) { + frameScores[currentFrame - 2] += pins; } + } - var finalFrame = state.frameNumber === maxFrames; - var strike = state.rollNumber === 1 && roll === 10; - var spare = state.rollNumber === 2 && roll === state.pinsRemaining; - var frameOver = finalFrame - ? (!state.fillBall && !spare && state.rollNumber === 2) || state.rollNumber === 3 - : strike || spare || state.rollNumber === 2; + function isGameOver() { + if (currentFrame <= maxFrames) return false; - var score = state.score + roll; + if (frames[maxFrames - 1] !== 'X' && frames[maxFrames - 1] !== 'S') return true; - if (state.strikeLastFrame && state.rollNumber < 3) { score = incrementScore(score, roll); } - if (state.spareLastFrame && state.rollNumber === 1) { score = incrementScore(score, roll); } - if (state.twoStrikesInARow && state.rollNumber === 1) { score = incrementScore(score, roll); } + // spare in the last frame gets no more than bonus roll + if (frames[maxFrames - 1] === 'S' && frameRoll > 1) return true; - var next = {}; + // bonus roll after the spare in the last frame may get a strike but then the games ends without another roll + if (frames[maxFrames - 1] === 'S' && frames[maxFrames] === 'X') return true; - next.frameNumber = frameOver ? state.frameNumber + 1 : state.frameNumber; - next.rollNumber = frameOver ? 1 : state.rollNumber + 1; - if ( finalFrame ) { - next.pinsRemaining = (strike || spare) ? maxPins : pinsRemaining(state.pinsRemaining, roll); - } else { - next.pinsRemaining = frameOver ? maxPins : pinsRemaining(state.pinsRemaining, roll); + if (frames[maxFrames - 1] === 'X') { + // if the first bonus roll is not a strike then finish the bonus frame + if (frames[maxFrames] !== 'X' && currentFrame > maxFrames + 1) return true; + + if (frames[maxFrames] === 'X') { + // if the second bonus roll is a strike, but was still used, the game is over + if (frames[maxFrames + 1] !== 'X' && frameRoll > 1) return true; + // if the second bonus roll is a strike the game is over + if (frames[maxFrames + 1] === 'X') return true; + } } - next.spareLastFrame = frameOver ? spare : state.spareLastFrame; - next.strikeLastFrame = frameOver ? strike : state.strikeLastFrame; - next.twoStrikesInARow = frameOver ? strike && state.strikeLastFrame : state.twoStrikesInARow; - next.fillBall = next.fillBall || (finalFrame && (strike || spare)); - next.score = score; + return false; + } - return next; - }, initialState); + this.roll = function (pins) { + if (pins < 0) { + throw new Error( 'Negative roll is invalid'); + } - if (finalState.frameNumber <= maxFrames ) { - throw new Error('Score cannot be taken until the end of the game'); - } + if (pins > remainingPins) { + throw new Error('Pin count exceeds pins on the lane'); + } - return finalState.score; -}; + if (isGameOver()) { + throw new Error('Cannot roll after game is over'); + } -function incrementScore(score, roll) { - return score + roll; -} + incrementScore(pins); -function pinsRemaining(pins, roll) { - return pins - roll; -} + if (frameRoll === 1) { + if (pins === maxPins) { + scoreStrike(); + initializeFrame(); + } else { + scoreFirstRoll(pins); + } + } else { + if (pins === remainingPins) { + scoreSpare(pins); + } else { + scoreOpenFrame(pins); + } + initializeFrame(); + } + }; + this.score = function () { + if (!isGameOver()) { + throw new Error('Score cannot be taken until the end of the game'); + } + return frameScores.reduce(function (total, num) {return total + num;}); + }; +} module.exports = Bowling; From c1dc998749a10eab3cd3e94bd8a3bf516c16f92b Mon Sep 17 00:00:00 2001 From: librorumque Date: Thu, 1 Mar 2018 17:52:18 +0700 Subject: [PATCH 08/39] Add rectangles exercise (#494) --- config.json | 12 +++ exercises/rectangles/README.md | 91 ++++++++++++++++++++ exercises/rectangles/example.js | 66 +++++++++++++++ exercises/rectangles/rectangles.spec.js | 108 ++++++++++++++++++++++++ 4 files changed, 277 insertions(+) create mode 100644 exercises/rectangles/README.md create mode 100644 exercises/rectangles/example.js create mode 100644 exercises/rectangles/rectangles.spec.js diff --git a/config.json b/config.json index b10b081d..83cc3bdc 100644 --- a/config.json +++ b/config.json @@ -1220,6 +1220,18 @@ "parsing", "domain_specific_languages" ] + }, + { + "uuid": "cb09212c-f2ae-4acf-9177-6c7f42594c1d", + "slug": "rectangles", + "core": false, + "unlocked_by": "grade-school", + "difficulty": 6, + "topics": [ + "parsing", + "searching", + "pattern_recognition" + ] } ], "foregone": [], diff --git a/exercises/rectangles/README.md b/exercises/rectangles/README.md new file mode 100644 index 00000000..362ed98c --- /dev/null +++ b/exercises/rectangles/README.md @@ -0,0 +1,91 @@ +# Rectangles + +Count the rectangles in an ASCII diagram like the one below. + +```text + +--+ + ++ | ++-++--+ +| | | ++--+--+ +``` + +The above diagram contains 6 rectangles: + +```text + + ++-----+ +| | ++-----+ +``` + +```text + +--+ + | | + | | + | | + +--+ +``` + +```text + +--+ + | | + +--+ + + +``` + +```text + + + +--+ + | | + +--+ +``` + +```text + + ++--+ +| | ++--+ +``` + +```text + + ++ + ++ + + +``` + +You may assume that the input is always a proper rectangle (i.e. the length of +every line equals the length of the first line). + +## Setup + +Go through the setup instructions for JavaScript to +install the necessary dependencies: + +http://exercism.io/languages/javascript + +## Making the Test Suite Pass + +Execute the tests with: + + jasmine .spec.js + +Replace `` with the name of the current exercise. E.g., to +test the Hello World exercise: + + jasmine hello-world.spec.js + +In many test suites all but the first test have been skipped. + +Once you get a test passing, you can unskip the next one by +changing `xit` to `it`. + + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/rectangles/example.js b/exercises/rectangles/example.js new file mode 100644 index 00000000..f9cb52c3 --- /dev/null +++ b/exercises/rectangles/example.js @@ -0,0 +1,66 @@ +var GLYPH = { corner: '+', edgeV: '|', edgeH: '-' }; + +var Vertex = function () { + this.right = []; + this.down = []; +}; + +// number of rectangles with given top left corner +Vertex.prototype.findRectangles = function () { + var corners = []; + var rectangles = 0; + + this.right.forEach(function (topLeft) { + topLeft.down.forEach(function (bottomRight) { + corners.push(bottomRight); + }); + }); + this.down.forEach(function (bottomLeft) { + bottomLeft.right.forEach(function (bottomRight) { + if (corners.indexOf(bottomRight) >= 0) { + rectangles++; + } + }); + }); + return rectangles; +}; + +// finds connected corners right and down from every corner +var toVertices = function (grid) { + var vertices = []; + grid.forEach(function (row, y) { + row.forEach(function (cell, x) { + if (cell === GLYPH.corner) { + var newVert = new Vertex(); + var side; + + vertices.push(newVert); + grid[y][x] = newVert; // replace glyph with the vertex + for (var u = y - 1; u >= 0; u--) { // search *up* along the side + side = grid[u][x]; + if (side instanceof Vertex) side.down.push(newVert); + else if (side !== GLYPH.edgeV) break; + } + for (var l = x - 1; l >= 0; l--) { // search *left* along the side + side = grid[y][l]; + if (side instanceof Vertex) side.right.push(newVert); + else if (side !== GLYPH.edgeH) break; + } + } + }); + }); + return vertices; +}; + +var rectangles = function (input) { + var grid; + var corners; + + grid = input.map(function (row) { return row.split(''); }); + corners = toVertices(grid); + return corners.reduce(function (total, vert) { + return total + vert.findRectangles(); + }, 0); +}; + +module.exports = rectangles; diff --git a/exercises/rectangles/rectangles.spec.js b/exercises/rectangles/rectangles.spec.js new file mode 100644 index 00000000..af89e07d --- /dev/null +++ b/exercises/rectangles/rectangles.spec.js @@ -0,0 +1,108 @@ +var rectangles = require('./rectangles'); + +describe('Rectangles', function () { + it('no rows', function () { + expect(rectangles([])).toBe(0); + }); + + xit('no columns', function () { + expect(rectangles([''])).toBe(0); + }); + + xit('no rectangles', function () { + expect(rectangles([' '])).toBe(0); + }); + + xit('one rectangle', function () { + var input = [ + '+-+', + '| |', + '+-+']; + expect(rectangles(input)).toBe(1); + }); + + xit('two rectangles without shared parts', function () { + var input = [ + ' +-+', + ' | |', + '+-+-+', + '| | ', + '+-+ ']; + expect(rectangles(input)).toBe(2); + }); + + xit('five rectangles with shared parts', function () { + var input = [ + ' +-+', + ' | |', + '+-+-+', + '| | |', + '+-+-+']; + expect(rectangles(input)).toBe(5); + }); + + xit('rectangle of height 1 is counted', function () { + var input = [ + '+--+', + '+--+']; + expect(rectangles(input)).toBe(1); + }); + + xit('rectangle of width 1 is counted', function () { + var input = [ + '++', + '||', + '++']; + expect(rectangles(input)).toBe(1); + }); + + xit('1x1 square is counted', function () { + var input = [ + '++', + '++']; + expect(rectangles(input)).toBe(1); + }); + + xit('only complete rectangles are counted', function () { + var input = [ + ' +-+', + ' |', + '+-+-+', + '| | -', + '+-+-+']; + expect(rectangles(input)).toBe(1); + }); + + xit('rectangles can be of different sizes', function () { + var input = [ + '+------+----+', + '| | |', + '+---+--+ |', + '| | |', + '+---+-------+']; + expect(rectangles(input)).toBe(3); + }); + + xit('corner is required for a rectangle to be complete', function () { + var input = [ + '+------+----+', + '| | |', + '+------+ |', + '| | |', + '+---+-------+']; + expect(rectangles(input)).toBe(2); + }); + + xit('large input with many rectangles', function () { + var input = [ + '+---+--+----+', + '| +--+----+', + '+---+--+ |', + '| +--+----+', + '+---+--+--+-+', + '+---+--+--+-+', + '+------+ | |', + ' +-+']; + expect(rectangles(input)).toBe(60); + }); +}); From 33dbffb7ae08f60aa79b6afbdf88770dc44e23da Mon Sep 17 00:00:00 2001 From: librorumque Date: Thu, 1 Mar 2018 17:59:11 +0700 Subject: [PATCH 09/39] Add variable-length-quantity exercise (#493) --- config.json | 11 ++ exercises/variable-length-quantity/README.md | 62 ++++++++++ exercises/variable-length-quantity/example.js | 51 ++++++++ .../variable-length-quantity.spec.js | 115 ++++++++++++++++++ 4 files changed, 239 insertions(+) create mode 100644 exercises/variable-length-quantity/README.md create mode 100644 exercises/variable-length-quantity/example.js create mode 100644 exercises/variable-length-quantity/variable-length-quantity.spec.js diff --git a/config.json b/config.json index 83cc3bdc..035b9e1b 100644 --- a/config.json +++ b/config.json @@ -1221,6 +1221,17 @@ "domain_specific_languages" ] }, + { + "uuid": "f82e470d-0bcc-4eba-b9b0-8a0c50a6fd19", + "slug": "variable-length-quantity", + "core": false, + "unlocked_by": "two-bucket", + "difficulty": 5, + "topics": [ + "bitwise_operations", + "transforming" + ] + }, { "uuid": "cb09212c-f2ae-4acf-9177-6c7f42594c1d", "slug": "rectangles", diff --git a/exercises/variable-length-quantity/README.md b/exercises/variable-length-quantity/README.md new file mode 100644 index 00000000..7e1203a4 --- /dev/null +++ b/exercises/variable-length-quantity/README.md @@ -0,0 +1,62 @@ +# Variable Length Quantity + +Implement variable length quantity encoding and decoding. + +The goal of this exercise is to implement [VLQ](https://en.wikipedia.org/wiki/Variable-length_quantity) encoding/decoding. + +In short, the goal of this encoding is to encode integer values in a way that would save bytes. +Only the first 7 bits of each byte is significant (right-justified; sort of like an ASCII byte). +So, if you have a 32-bit value, you have to unpack it into a series of 7-bit bytes. +Of course, you will have a variable number of bytes depending upon your integer. +To indicate which is the last byte of the series, you leave bit #7 clear. +In all of the preceding bytes, you set bit #7. + +So, if an integer is between `0-127`, it can be represented as one byte. +Although VLQ can deal with numbers of arbitrary sizes, for this exercise we will restrict ourselves to only numbers that fit in a 32-bit unsigned integer. +Here are examples of integers as 32-bit values, and the variable length quantities that they translate to: + +```text + NUMBER VARIABLE QUANTITY +00000000 00 +00000040 40 +0000007F 7F +00000080 81 00 +00002000 C0 00 +00003FFF FF 7F +00004000 81 80 00 +00100000 C0 80 00 +001FFFFF FF FF 7F +00200000 81 80 80 00 +08000000 C0 80 80 00 +0FFFFFFF FF FF FF 7F +``` + +## Setup + +Go through the setup instructions for JavaScript to +install the necessary dependencies: + +http://exercism.io/languages/javascript + +## Making the Test Suite Pass + +Execute the tests with: + + jasmine .spec.js + +Replace `` with the name of the current exercise. E.g., to +test the Hello World exercise: + + jasmine hello-world.spec.js + +In many test suites all but the first test have been skipped. + +Once you get a test passing, you can unskip the next one by +changing `xit` to `it`. + +## Source + +A poor Splice developer having to implement MIDI encoding/decoding. [https://splice.com](https://splice.com) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/variable-length-quantity/example.js b/exercises/variable-length-quantity/example.js new file mode 100644 index 00000000..9aeec820 --- /dev/null +++ b/exercises/variable-length-quantity/example.js @@ -0,0 +1,51 @@ +var LENGTH = 7; +var CONT_BITS = 1 << LENGTH; +var DATA_BITS = CONT_BITS - 1; + +var encodeOne = function (val) { + var buf = []; + var left = val; + + while (left) { + var bits = left & DATA_BITS | CONT_BITS; // set continuation everywhere + left = left >>> LENGTH; + buf.push(bits); + } + buf[0] = buf[0] & DATA_BITS; // cancel the last continuation + return buf.reverse(); +}; + +var decodeOne = function (buf) { + var val = 0; + + for (var i = 0; i < buf.length; i++) { + val = val << LENGTH | buf[i] & DATA_BITS; + } + return val >>> 0; // convert to unsigned 32-bit +}; + +module.exports = { + encode: function encode(data) { + var buf = []; + + for (var i = 0; i < data.length; i++) { + buf = buf.concat(encodeOne(data[i])); + } + return buf; + }, + decode: function decode(data) { + var start = 0; + var vals = []; + + for (var i = 0; i < data.length; i++) { + if (~data[i] & CONT_BITS) { + vals.push(decodeOne(data.slice(start, i + 1))); + start = i + 1; + } + } + if (start < data.length) { + throw new Error('Incomplete sequence'); + } + return vals; + } +}; diff --git a/exercises/variable-length-quantity/variable-length-quantity.spec.js b/exercises/variable-length-quantity/variable-length-quantity.spec.js new file mode 100644 index 00000000..43d066dc --- /dev/null +++ b/exercises/variable-length-quantity/variable-length-quantity.spec.js @@ -0,0 +1,115 @@ +var VLQ = require('./variable-length-quantity'); + +describe('VariableLengthQuantity', function () { + describe('Encode a series of integers, producing a series of bytes.', function () { + it('zero', function () { + expect(VLQ.encode([0])).toEqual([0]); + }); + + it('arbitrary single byte', function () { + expect(VLQ.encode([0x40])).toEqual([0x40]); + }); + + it('largest single byte', function () { + expect(VLQ.encode([0x7f])).toEqual([0x7f]); + }); + + it('smallest double byte', function () { + expect(VLQ.encode([0x80])).toEqual([0x81, 0]); + }); + + it('arbitrary double byte', function () { + expect(VLQ.encode([0x2000])).toEqual([0xc0, 0]); + }); + + it('largest double byte', function () { + expect(VLQ.encode([0x3fff])).toEqual([0xff, 0x7f]); + }); + + it('smallest triple byte', function () { + expect(VLQ.encode([0x4000])).toEqual([0x81, 0x80, 0]); + }); + + it('arbitrary triple byte', function () { + expect(VLQ.encode([0x100000])).toEqual([0xc0, 0x80, 0]); + }); + + it('largest triple byte', function () { + expect(VLQ.encode([0x1fffff])).toEqual([0xff, 0xff, 0x7f]); + }); + + it('smallest quadruple byte', function () { + expect(VLQ.encode([0x200000])).toEqual([0x81, 0x80, 0x80, 0]); + }); + + it('arbitrary quadruple byte', function () { + expect(VLQ.encode([0x8000000])).toEqual([0xc0, 0x80, 0x80, 0]); + }); + + it('largest quadruple byte', function () { + expect(VLQ.encode([0xfffffff])).toEqual([0xff, 0xff, 0xff, 0x7f]); + }); + + it('smallest quintuple byte', function () { + expect(VLQ.encode([0x10000000])).toEqual([0x81, 0x80, 0x80, 0x80, 0]); + }); + + it('arbitrary quintuple byte', function () { + expect(VLQ.encode([0xff000000])).toEqual([0x8f, 0xf8, 0x80, 0x80, 0]); + }); + + it('maximum 32-bit integer input', function () { + expect(VLQ.encode([0xffffffff])).toEqual([0x8f, 0xff, 0xff, 0xff, 0x7f]); + }); + + it('two single-byte values', function () { + expect(VLQ.encode([0x40, 0x7f])).toEqual([0x40, 0x7f]); + }); + + it('two multi-byte values', function () { + expect(VLQ.encode([0x4000, 0x123456])).toEqual([0x81, 0x80, 0, 0xc8, 0xe8, 0x56]); + }); + + it('many multi-byte values', function () { + var input = [0x2000, 0x123456, 0xfffffff, 0, 0x3fff, 0x4000]; + var expected = [0xc0, 0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0, 0xff, 0x7f, 0x81, 0x80, 0]; + expect(VLQ.encode(input)).toEqual(expected); + }); + }); + + describe('Decode a series of bytes, producing a series of integers.', function () { + it('one byte', function () { + expect(VLQ.decode([0x7f])).toEqual([0x7f]); + }); + + it('two bytes', function () { + expect(VLQ.decode([0xc0, 0])).toEqual([0x2000]); + }); + + it('three bytes', function () { + expect(VLQ.decode([0xff, 0xff, 0x7f])).toEqual([0x1fffff]); + }); + + it('four bytes', function () { + expect(VLQ.decode([0x81, 0x80, 0x80, 0])).toEqual([0x200000]); + }); + + it('maximum 32-bit integer', function () { + expect(VLQ.decode([0x8f, 0xff, 0xff, 0xff, 0x7f])).toEqual([0xffffffff]); + }); + + it('incomplete sequence causes error', function () { + expect(function () { VLQ.decode([0xff]); }).toThrow(new Error('Incomplete sequence')); + }); + + it('incomplete sequence causes error, even if value is zero', function () { + expect(function () { VLQ.decode([0x80]); }).toThrow(new Error('Incomplete sequence')); + }); + + it('multiple values', function () { + var input = [0xc0, 0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0, 0xff, 0x7f, 0x81, 0x80, 0]; + var expected = [0x2000, 0x123456, 0xfffffff, 0, 0x3fff, 0x4000]; + expect(VLQ.decode(input)).toEqual(expected); + }); + }); +}); From 9048b56438223a1fb8154648de2a4ae411a5881d Mon Sep 17 00:00:00 2001 From: Allison Zhao Date: Thu, 1 Mar 2018 17:42:20 -0500 Subject: [PATCH 10/39] Fix flatten array (#515) * Initial commit * Fix flatten array linting error --- .eslintignore | 1 - exercises/flatten-array/example.js | 11 +++---- exercises/flatten-array/flatten-array.spec.js | 30 +++++++++---------- package.json | 6 ++-- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/.eslintignore b/.eslintignore index a6052eb7..786fb1bd 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,6 +1,5 @@ big-integer.js exercises/custom-set -exercises/flatten-array exercises/grade-school exercises/grains/big-integer.js exercises/grains/big-integer.spec.js diff --git a/exercises/flatten-array/example.js b/exercises/flatten-array/example.js index 63ab232b..658eb26e 100644 --- a/exercises/flatten-array/example.js +++ b/exercises/flatten-array/example.js @@ -1,11 +1,12 @@ -var Flattener = function () {}; +var Flattener = function () { }; -Flattener.prototype.flatten = function (unflattenedArray, flattenedArray) { - var self = this, flattenedArray = flattenedArray || []; +Flattener.prototype.flatten = function (unflattenedArray, inputFlattenedArray) { + var self = this; + var flattenedArray = inputFlattenedArray || []; unflattenedArray.forEach(function (element) { if (Array.isArray(element)) { - return self.flatten(element, flattenedArray); - } else if ( element !== null) { + self.flatten(element, flattenedArray); + } else if (element !== null) { flattenedArray.push(element); } }); diff --git a/exercises/flatten-array/flatten-array.spec.js b/exercises/flatten-array/flatten-array.spec.js index 6080fe07..4c5be05f 100644 --- a/exercises/flatten-array/flatten-array.spec.js +++ b/exercises/flatten-array/flatten-array.spec.js @@ -3,24 +3,24 @@ var Flattener = require('./flatten-array.js'); describe('FlattenArray', function () { var flattener = new Flattener(); it('flattens a nested list', function () { - expect(flattener.flatten([[]])).toEqual([]); - }); + expect(flattener.flatten([[]])).toEqual([]); + }); xit('flattens a 2 level nested list', function () { - expect(flattener.flatten([1, [2, 3, 4], 5])).toEqual([1, 2, 3, 4, 5]); - }); + expect(flattener.flatten([1, [2, 3, 4], 5])).toEqual([1, 2, 3, 4, 5]); + }); xit('flattens a 3 level nested list', function () { - expect(flattener.flatten([1, [2, 3, 4], 5, [6, [7, 8]]])).toEqual([1, 2, 3, 4, 5, 6, 7, 8]); - }); - xit('flattens a 5 level nested list', function () { - expect(flattener.flatten([0, 2, [[2, 3], 8, 100, 4, [[[50]]]], -2])).toEqual([0, 2, 2, 3, 8, 100, 4, 50, -2]); - }); + expect(flattener.flatten([1, [2, 3, 4], 5, [6, [7, 8]]])).toEqual([1, 2, 3, 4, 5, 6, 7, 8]); + }); + xit('flattens a 5 level nested list', function () { + expect(flattener.flatten([0, 2, [[2, 3], 8, 100, 4, [[[50]]]], -2])).toEqual([0, 2, 2, 3, 8, 100, 4, 50, -2]); + }); xit('flattens a 6 level nest list', function () { - expect(flattener.flatten([1, [2, [[3]], [4, [[5]]], 6, 7], 8])).toEqual([1, 2, 3, 4, 5, 6, 7, 8]); - }); + expect(flattener.flatten([1, [2, [[3]], [4, [[5]]], 6, 7], 8])).toEqual([1, 2, 3, 4, 5, 6, 7, 8]); + }); xit('flattens a 6 level nest list with null values', function () { - expect(flattener.flatten([0, 2, [[2, 3], 8, [[100]], null, [[null]]], -2])).toEqual([0, 2, 2, 3, 8, 100, -2]); - }); + expect(flattener.flatten([0, 2, [[2, 3], 8, [[100]], null, [[null]]], -2])).toEqual([0, 2, 2, 3, 8, 100, -2]); + }); xit('returns an empty list if all values in nested list are null', function () { - expect(flattener.flatten([null, [[[null]]], null, null, [[null, null], null], null])).toEqual([]); - }); + expect(flattener.flatten([null, [[[null]]], null, null, [[null, null], null], null])).toEqual([]); + }); }); diff --git a/package.json b/package.json index cac2593c..8ab06dbf 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,11 @@ "lint-fix": "eslint . --fix" }, "eslintConfig": { - "plugins": ["jasmine"], + "plugins": [ + "jasmine" + ], "env": { - "jasmine": true + "jasmine": true }, "extends": "eslint-config-airbnb-es5", "rules": { From e1fd38e38bdd9a9087d1a024c74a27ea56c912f2 Mon Sep 17 00:00:00 2001 From: Mina Slater Date: Thu, 1 Mar 2018 16:43:15 -0600 Subject: [PATCH 11/39] fixes linting errors for perfect numbers exercise (#508) --- .eslintignore | 1 - exercises/perfect-numbers/example.js | 8 ++++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.eslintignore b/.eslintignore index 786fb1bd..0b7d3a1f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -7,7 +7,6 @@ exercises/kindergarten-garden exercises/linked-list exercises/minesweeper exercises/nth-prime -exercises/perfect-numbers exercises/queen-attack exercises/robot-simulator exercises/saddle-points diff --git a/exercises/perfect-numbers/example.js b/exercises/perfect-numbers/example.js index c7fcdd76..ad7c1c6e 100644 --- a/exercises/perfect-numbers/example.js +++ b/exercises/perfect-numbers/example.js @@ -7,10 +7,12 @@ var PerfectNumbers = function () { /** * Calculate all the divisors for a given number and return them as an array. * Note: the actual number is not include in the returned array. + * @param {number} number - a number input. + * @returns {array} - the array of divisors */ PerfectNumbers.prototype.getDivisors = function (number) { var i; - var divs = new Array(); + var divs = []; // Accepts only natura numbers greater than 1. if (number <= 1) { @@ -31,7 +33,9 @@ PerfectNumbers.prototype.getDivisors = function (number) { }; PerfectNumbers.prototype.classify = function (number) { - var i, sum, result; + var i; + var sum; + var result; // Check if the input is valid if (number <= 0) { From 32cf4cfc6ab61bd0a080e8cb6d1d63ce1d96173d Mon Sep 17 00:00:00 2001 From: Jeffrey Berman <30912433+twistyjeffrey@users.noreply.github.com> Date: Thu, 1 Mar 2018 16:48:57 -0600 Subject: [PATCH 12/39] fixes styling for kindergarten garden (#511) --- .eslintignore | 1 - exercises/kindergarten-garden/example.js | 18 +++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.eslintignore b/.eslintignore index 0b7d3a1f..327203af 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,7 +3,6 @@ exercises/custom-set exercises/grade-school exercises/grains/big-integer.js exercises/grains/big-integer.spec.js -exercises/kindergarten-garden exercises/linked-list exercises/minesweeper exercises/nth-prime diff --git a/exercises/kindergarten-garden/example.js b/exercises/kindergarten-garden/example.js index 725585b1..0fc7f6c4 100644 --- a/exercises/kindergarten-garden/example.js +++ b/exercises/kindergarten-garden/example.js @@ -23,13 +23,13 @@ var plants = { }; function getPlants(pots, index) { - var plants = []; + var plantsArr = []; var position = 2 * index; - plants.push(pots[0][position]); - plants.push(pots[0][position + 1]); - plants.push(pots[1][position]); - plants.push(pots[1][position + 1]); - return plants; + plantsArr.push(pots[0][position]); + plantsArr.push(pots[0][position + 1]); + plantsArr.push(pots[1][position]); + plantsArr.push(pots[1][position + 1]); + return plantsArr; } function parse(diagram) { @@ -42,10 +42,10 @@ function parse(diagram) { function Garden(diagram, students) { var instance = {}; - students = students || defaultChildren; - students.sort(); + var kids = students || defaultChildren; + kids.sort(); - students.forEach(function (student, index) { + kids.forEach(function (student, index) { instance[student.toLowerCase()] = getPlants(parse(diagram), index); }); From a5df83aa4b2afb498f726650dc6bf3779311fada Mon Sep 17 00:00:00 2001 From: Allison Zhao Date: Thu, 1 Mar 2018 18:01:01 -0500 Subject: [PATCH 13/39] Fix custom-set linting errors (#513) * Initial commit * Fix custom-set linting errors --- exercises/custom-set/example-gen.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exercises/custom-set/example-gen.js b/exercises/custom-set/example-gen.js index c791c799..f27732f6 100644 --- a/exercises/custom-set/example-gen.js +++ b/exercises/custom-set/example-gen.js @@ -160,7 +160,7 @@ function renderSuite(tests, otherTests, suiteTemplate) { return suiteTemplate(tests.concat(otherTests)); } -function suiteTemplate(tests) { +function suiteTemplateFn(tests) { return ( `var CustomSet = require('./custom-set'); @@ -179,8 +179,8 @@ function testTemplate(isEnabled, description, body) { `); } -function array(array) { - return array.length === 0 ? '' : `[${array.join(', ')}]`; +function array(arr) { + return arr.length === 0 ? '' : `[${arr.join(', ')}]`; } function generate() { @@ -193,7 +193,7 @@ function generate() { suiteData: suiteData, testBodyTemplates: TEST_BODY_TEMPLATES, extraTests: NON_CANONICAL_TESTS, - suiteTemplate: suiteTemplate + suiteTemplate: suiteTemplateFn })); } From 4e2ef3eb6d40d4f8dbda274902622c5f21577c78 Mon Sep 17 00:00:00 2001 From: Samidh Desai <34141113+SamDesai333@users.noreply.github.com> Date: Fri, 2 Mar 2018 16:52:19 -0600 Subject: [PATCH 14/39] fixes styling in grade-school (#512) * fixes styling in grade-school * updates variable gradeLvl to gradeLevel --- .eslintignore | 2 +- exercises/grade-school/example.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.eslintignore b/.eslintignore index 327203af..dd2770ce 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,6 +1,6 @@ big-integer.js exercises/custom-set -exercises/grade-school +exercises/flatten-array exercises/grains/big-integer.js exercises/grains/big-integer.spec.js exercises/linked-list diff --git a/exercises/grade-school/example.js b/exercises/grade-school/example.js index f43c127e..2e81015c 100644 --- a/exercises/grade-school/example.js +++ b/exercises/grade-school/example.js @@ -1,11 +1,11 @@ module.exports = function School() { var db = {}; - function add(student, grade) { - if (db[grade]) { - db[grade].push(student); + function add(student, gradeLevel) { + if (db[gradeLevel]) { + db[gradeLevel].push(student); } else { - db[grade] = [student]; + db[gradeLevel] = [student]; } } @@ -14,8 +14,8 @@ module.exports = function School() { } function roster() { - return sortedGrades().reduce(function (sorted, grade) { - sorted[grade] = clone(db[grade]).sort(); + return sortedGrades().reduce(function (sorted, gradeLevel) { + sorted[gradeLevel] = clone(db[gradeLevel]).sort(); return sorted; }, {}); } From d43f103403b7e03b19429382699016eee199099e Mon Sep 17 00:00:00 2001 From: Susan Lippa Date: Sun, 4 Mar 2018 06:01:33 -0600 Subject: [PATCH 15/39] Issue#399 queen-attack (#518) * queen-attack & linked-lists linted * Revert "queen-attack & linked-lists linted" This reverts commit 6e0aa7089d33cec19da3a8faadc427f6a4c6a391. * queen-attack linting * queen-attack revision 3/2pm * Update example.js * Update example.js * queen-attack continues * queen-attack linting * queen-attack adj for var --- exercises/queen-attack/example.js | 10 +++++----- exercises/queen-attack/queen-attack.spec.js | 20 +++++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/exercises/queen-attack/example.js b/exercises/queen-attack/example.js index 50016f39..ebe07a5d 100644 --- a/exercises/queen-attack/example.js +++ b/exercises/queen-attack/example.js @@ -1,12 +1,11 @@ 'use strict'; -module.exports = function (options) { - if (options === undefined) { - options = { white: [0, 3], black: [7, 3] }; - } + +module.exports = function (passedInOptions) { + var options = passedInOptions || {white: [0, 3], black: [7, 3]}; if (options.white[0] === options.black[0] && options.white[1] === options.black[1]) { - throw 'Queens cannot share the same space'; + throw String('Queens cannot share the same space'); } this.white = options.white; @@ -61,3 +60,4 @@ module.exports = function (options) { return this.boardRepresentation(); }; }; + diff --git a/exercises/queen-attack/queen-attack.spec.js b/exercises/queen-attack/queen-attack.spec.js index e51205be..b2d4525f 100644 --- a/exercises/queen-attack/queen-attack.spec.js +++ b/exercises/queen-attack/queen-attack.spec.js @@ -18,6 +18,8 @@ describe('Queens', function () { try { var queens = new Queens(positioning); + expect(queens.white).toEqual([2, 4]); + expect(queens.black).toEqual([2, 4]); } catch (error) { expect(error).toEqual('Queens cannot share the same space'); } @@ -26,15 +28,15 @@ describe('Queens', function () { xit('toString representation', function () { var positioning = {white: [2, 4], black: [6, 6]}; var queens = new Queens(positioning); - var board = '_ _ _ _ _ _ _ _\n\ -_ _ _ _ _ _ _ _\n\ -_ _ _ _ W _ _ _\n\ -_ _ _ _ _ _ _ _\n\ -_ _ _ _ _ _ _ _\n\ -_ _ _ _ _ _ _ _\n\ -_ _ _ _ _ _ B _\n\ -_ _ _ _ _ _ _ _\n\ -'; + var board = '_ _ _ _ _ _ _ _\n' + +'_ _ _ _ _ _ _ _\n' + +'_ _ _ _ W _ _ _\n' + +'_ _ _ _ _ _ _ _\n' + +'_ _ _ _ _ _ _ _\n' + +'_ _ _ _ _ _ _ _\n' + +'_ _ _ _ _ _ B _\n' + +'_ _ _ _ _ _ _ _\n' +; expect(queens.toString()).toEqual(board); }); From a4d3e8189606343235cc8c8e1fe978a4a9a7ce3f Mon Sep 17 00:00:00 2001 From: Lauren Cantlin <30631905+laurencantlin@users.noreply.github.com> Date: Mon, 5 Mar 2018 18:21:25 -0600 Subject: [PATCH 16/39] fixes nth-prime linter problems (#525) --- .eslintignore | 1 - exercises/nth-prime/example.js | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.eslintignore b/.eslintignore index dd2770ce..7b66825f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -5,7 +5,6 @@ exercises/grains/big-integer.js exercises/grains/big-integer.spec.js exercises/linked-list exercises/minesweeper -exercises/nth-prime exercises/queen-attack exercises/robot-simulator exercises/saddle-points diff --git a/exercises/nth-prime/example.js b/exercises/nth-prime/example.js index f0d824dc..faf7d05c 100644 --- a/exercises/nth-prime/example.js +++ b/exercises/nth-prime/example.js @@ -7,12 +7,13 @@ module.exports = { return this.realPrimes[nthPrime - 1]; }, generatePrimes: function (uptoNumber) { - var i, j, currentPrime, primeCount, possiblePrimes = []; - - if (this.realPrimes) { return this.realPrimes; } + var i; + var j; + var currentPrime; + var possiblePrimes = []; for (i = 2; i <= uptoNumber; i++) { - possiblePrimes.push({ number: i, prime: true}); + possiblePrimes.push({ number: i, prime: true }); } for (i = 2; i < Math.sqrt(possiblePrimes.length); i++) { @@ -24,8 +25,6 @@ module.exports = { } } - primeCount = 0; - this.realPrimes = []; for (i = 0; i < possiblePrimes.length; i++) { @@ -34,6 +33,7 @@ module.exports = { this.realPrimes.push(currentPrime.number); } } + return this.realPrimes; } }; From cf89157ff9f9659719648e182135667f2577ef43 Mon Sep 17 00:00:00 2001 From: Natraj Subramanian Date: Tue, 6 Mar 2018 06:02:59 -0600 Subject: [PATCH 17/39] Fix lint errors on simple-linked-list (#520) * Empty PR. Fix lint errors on simple-linked-list * Fixes most of the lint specified errors * Disabled incompatible lint rules --- .eslintignore | 1 - exercises/simple-linked-list/example.js | 16 ++++++++++------ .../simple-linked-list.spec.js | 9 ++++++--- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.eslintignore b/.eslintignore index 7b66825f..becfcec7 100644 --- a/.eslintignore +++ b/.eslintignore @@ -10,4 +10,3 @@ exercises/robot-simulator exercises/saddle-points exercises/secret-handshake exercises/simple-cipher -exercises/simple-linked-list diff --git a/exercises/simple-linked-list/example.js b/exercises/simple-linked-list/example.js index 6e1f0d05..e8fca85f 100644 --- a/exercises/simple-linked-list/example.js +++ b/exercises/simple-linked-list/example.js @@ -3,11 +3,11 @@ function Element(value, next) { throw new Error('Element is a constructor.'); } - if (value === undefined) { + if (typeof value === 'undefined') { throw new Error('Value required.'); } - if (next !== undefined && !(next instanceof Element)) { + if (typeof next !== 'undefined' && !(next instanceof Element)) { throw new Error('A Element instance as next value is required.'); } @@ -18,7 +18,7 @@ function Element(value, next) { function List() {} List.prototype.push = function (value) { - if (value === undefined) { + if (typeof value === 'undefined') { throw new Error('Argument required.'); } @@ -40,7 +40,7 @@ List.prototype.push = function (value) { }; List.prototype.unshift = function (value) { - if (value === undefined) { + if (typeof value === 'undefined') { throw new Error('Argument required.'); } @@ -65,17 +65,20 @@ List.prototype.pop = function () { return; } - var penultEl, lastEl = this.head; + var penultEl; + var lastEl = this.head; while (lastEl.next) { penultEl = lastEl; lastEl = lastEl.next; } + /* eslint-disable no-undefined */ if (!penultEl) { this.head = undefined; } else { penultEl.next = undefined; } + /* eslint-enable no-undefined */ }; List.prototype.reverse = function () { @@ -83,7 +86,8 @@ List.prototype.reverse = function () { return; } - var current, previous; + var current; + var previous; while (this.head) { current = this.head; this.shift(); diff --git a/exercises/simple-linked-list/simple-linked-list.spec.js b/exercises/simple-linked-list/simple-linked-list.spec.js index 1254743b..75460d35 100644 --- a/exercises/simple-linked-list/simple-linked-list.spec.js +++ b/exercises/simple-linked-list/simple-linked-list.spec.js @@ -16,9 +16,11 @@ describe('simple-linked-list', function () { var el = new Element(1); expect(el).toBeDefined(); + /* eslint-disable new-cap */ expect(function () { - var el = Element(1); + el = Element(1); }).toThrow(); + /* eslint-enable new-cap */ }); xit('requires an argument', function () { @@ -26,7 +28,7 @@ describe('simple-linked-list', function () { expect(el).toBeDefined(); expect(function () { - var el = new Element(); + el = new Element(); }).toThrow(); }); @@ -47,9 +49,9 @@ describe('simple-linked-list', function () { expect(elTwo.next).toBe(elOne); }); + /* eslint-disable no-unused-vars */ xit('requires an instance of Element as next element', function () { expect(function () { - var el = new Element(1, true); var el = new Element(1, false); }).toThrow(); expect(function () { @@ -62,6 +64,7 @@ describe('simple-linked-list', function () { var el = new Element(1, {}); }).toThrow(); }); + /* eslint-enable no-unused-vars */ describe('List', function () { xit('is a constructor', function () { From c12dbfd24506e54aeb294344f42564cfeadc6caf Mon Sep 17 00:00:00 2001 From: Joe Fitzpatrick <32550334+joefitz12@users.noreply.github.com> Date: Tue, 6 Mar 2018 18:08:34 -0600 Subject: [PATCH 18/39] issue #399 - Removes lint errors from secret-handshake (#519) --- .eslintignore | 1 - exercises/secret-handshake/example.js | 3 +-- exercises/secret-handshake/secret-handshake.spec.js | 3 ++- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.eslintignore b/.eslintignore index becfcec7..382b8bbd 100644 --- a/.eslintignore +++ b/.eslintignore @@ -8,5 +8,4 @@ exercises/minesweeper exercises/queen-attack exercises/robot-simulator exercises/saddle-points -exercises/secret-handshake exercises/simple-cipher diff --git a/exercises/secret-handshake/example.js b/exercises/secret-handshake/example.js index 651a8d78..873ccc97 100644 --- a/exercises/secret-handshake/example.js +++ b/exercises/secret-handshake/example.js @@ -12,8 +12,7 @@ function SecretHandshake(handshake) { return this.shakeWith; }; - this.calculateHandshake = function (handshake) { - /* jshint bitwise:false */ + this.calculateHandshake = function () { var shakeWith = []; for (var i = 0; i < handshakeCommands.length; i++) { diff --git a/exercises/secret-handshake/secret-handshake.spec.js b/exercises/secret-handshake/secret-handshake.spec.js index 6c29444a..bf5fc41d 100644 --- a/exercises/secret-handshake/secret-handshake.spec.js +++ b/exercises/secret-handshake/secret-handshake.spec.js @@ -38,7 +38,8 @@ describe('Secret Handshake', function () { xit('text is an invalid secret handshake', function () { expect( function () { - var handshake = new SecretHandshake('piggies'); + /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "[iI]gnored" }]*/ + var ignoredHandshake = new SecretHandshake('piggies'); }).toThrow(new Error('Handshake must be a number')); }); }); From b9bc950c365a537a7fa5b45c851b8df2639ab69d Mon Sep 17 00:00:00 2001 From: PakkuDon Date: Thu, 8 Mar 2018 22:33:47 +1100 Subject: [PATCH 19/39] Add armstrong-numbers exercise (#522) --- config.json | 11 +++++ exercises/armstrong-numbers/README.md | 46 +++++++++++++++++++ .../armstrong-numbers.spec.js | 43 +++++++++++++++++ exercises/armstrong-numbers/example.js | 11 +++++ 4 files changed, 111 insertions(+) create mode 100644 exercises/armstrong-numbers/README.md create mode 100644 exercises/armstrong-numbers/armstrong-numbers.spec.js create mode 100644 exercises/armstrong-numbers/example.js diff --git a/config.json b/config.json index 035b9e1b..b717adca 100644 --- a/config.json +++ b/config.json @@ -1243,6 +1243,17 @@ "searching", "pattern_recognition" ] + }, + { + "uuid": "0e4b628c-870d-446b-a400-3cc72457f2bc", + "slug": "armstrong-numbers", + "core": false, + "unlocked_by": null, + "difficulty": 2, + "topics": [ + "mathematics", + "algorithms" + ] } ], "foregone": [], diff --git a/exercises/armstrong-numbers/README.md b/exercises/armstrong-numbers/README.md new file mode 100644 index 00000000..f0714aa7 --- /dev/null +++ b/exercises/armstrong-numbers/README.md @@ -0,0 +1,46 @@ +# Armstrong Numbers + +An [Armstrong number](https://en.wikipedia.org/wiki/Narcissistic_number) is a number that is the sum of its own digits each raised to the power of the number of digits. + +For example: + +- 9 is an Armstrong number, because `9 = 9^1 = 9` +- 10 is *not* an Armstrong number, because `10 != 1^2 + 0^2 = 2` +- 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153` +- 154 is *not* an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190` + +Write some code to determine whether a number is an Armstrong number. + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine armstrong-numbers.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Wikipedia [Narcissistic number](https://en.wikipedia.org/wiki/Narcissistic_number) + +## Submitting Incomplete Solutions + +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/armstrong-numbers/armstrong-numbers.spec.js b/exercises/armstrong-numbers/armstrong-numbers.spec.js new file mode 100644 index 00000000..9f250fac --- /dev/null +++ b/exercises/armstrong-numbers/armstrong-numbers.spec.js @@ -0,0 +1,43 @@ +var ArmstrongNumber = require('./armstrong-numbers'); + +describe('ArmstrongNumber', function () { + it('Single digit numbers are Armstrong numbers', function () { + var input = 5; + expect(ArmstrongNumber.validate(input)).toBe(true); + }); + + xit('There are no 2 digit Armstrong numbers', function () { + var input = 10; + expect(ArmstrongNumber.validate(input)).toBe(false); + }); + + xit('Three digit number that is an Armstrong number', function () { + var input = 153; + expect(ArmstrongNumber.validate(input)).toBe(true); + }); + + xit('Three digit number that is not an Armstrong number', function () { + var input = 100; + expect(ArmstrongNumber.validate(input)).toBe(false); + }); + + xit('Four digit number that is an Armstrong number', function () { + var input = 9474; + expect(ArmstrongNumber.validate(input)).toBe(true); + }); + + xit('Four digit number that is not an Armstrong number', function () { + var input = 9475; + expect(ArmstrongNumber.validate(input)).toBe(false); + }); + + xit('Seven digit number that is an Armstrong number', function () { + var input = 9926315; + expect(ArmstrongNumber.validate(input)).toBe(true); + }); + + xit('Seven digit number that is not an Armstrong number', function () { + var input = 9926314; + expect(ArmstrongNumber.validate(input)).toBe(false); + }); +}); diff --git a/exercises/armstrong-numbers/example.js b/exercises/armstrong-numbers/example.js new file mode 100644 index 00000000..c0652924 --- /dev/null +++ b/exercises/armstrong-numbers/example.js @@ -0,0 +1,11 @@ +'use strict'; + +module.exports = { + validate: function (input) { + var digits = String(input).split(''); + var sum = digits.reduce(function (total, current) { + return total + Math.pow(current, digits.length); + }, 0); + return sum === input; + } +}; From e76179e4c54e7b9ffc0eddac46578053120926ee Mon Sep 17 00:00:00 2001 From: Tarun Velli Date: Tue, 13 Mar 2018 18:50:13 +0530 Subject: [PATCH 20/39] fix linting for minesweeper exercise (#526) --- .eslintignore | 1 - exercises/minesweeper/example.js | 30 +++++++++++++++--------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.eslintignore b/.eslintignore index 382b8bbd..2d19a189 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,7 +4,6 @@ exercises/flatten-array exercises/grains/big-integer.js exercises/grains/big-integer.spec.js exercises/linked-list -exercises/minesweeper exercises/queen-attack exercises/robot-simulator exercises/saddle-points diff --git a/exercises/minesweeper/example.js b/exercises/minesweeper/example.js index b5d76036..a366884e 100644 --- a/exercises/minesweeper/example.js +++ b/exercises/minesweeper/example.js @@ -21,25 +21,25 @@ Minesweeper.prototype.annotate = function (rows) { } var board = rows.map(function (row) { return row.split(''); }); var outBoard = []; - for (var x = 0; x < board.length; x++) { + board.forEach(function (memberX, x) { outBoard[x] = []; - for (var y = 0; y < board[x].length; y++) { - var spot = board[x][y]; + memberX.forEach(function (memberXY, y) { + var spot = memberXY; if (spot === '*') { outBoard[x][y] = spot; - continue; + } else { + var bombCount = this.distanceXdistanceYs.map(function (dxdy) { + if (typeof board[x + dxdy[0]] === 'undefined') { + return 0; + } + return board[x + dxdy[0]][y + dxdy[1]] === '*' ? 1 : 0; + }).reduce(function (total, num) { + return total + num; + }); + outBoard[x][y] = bombCount > 0 ? bombCount : ' '; } - var bombCount = this.distanceXdistanceYs.map(function (dxdy) { - if (board[x + dxdy[0]] === undefined) { - return 0; - } - return board[x + dxdy[0]][y + dxdy[1]] === '*' ? 1 : 0; - }).reduce(function (total, num) { - return total + num; - }); - outBoard[x][y] = bombCount > 0 ? bombCount : ' '; - } - } + }, this); + }, this); return outBoard.map(function (row) { return row.join(''); }); From abd7116b282b5632201d9e1a6bde6a225a37d692 Mon Sep 17 00:00:00 2001 From: Tejas Bubane Date: Tue, 13 Mar 2018 19:25:22 +0530 Subject: [PATCH 21/39] Update jasmine to v3.1.0 (#507) Recently [an issue](https://github.com/exercism/javascript/issues/505) came up related to jasmine v3.0.0. And I noticed that we are using v2.8. Jasmine 3 seems to have some [breaking changes](https://github.com/jasmine/jasmine/blob/master/release_notes/3.0.md) and since many of our new users will be installing recent version of jasmine, I thought it would be better to update it so we run CI using v3. --- package-lock.json | 21 +++++++-------------- package.json | 2 +- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index c3c1fed5..94eab4b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -728,12 +728,6 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, "external-editor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", @@ -1091,20 +1085,19 @@ } }, "jasmine": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", - "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.1.0.tgz", + "integrity": "sha1-K9Wf1+xuwOistk4J9Fpo7SrRlSo=", "dev": true, "requires": { - "exit": "0.1.2", "glob": "7.1.2", - "jasmine-core": "2.8.0" + "jasmine-core": "3.1.0" } }, "jasmine-core": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", - "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.1.0.tgz", + "integrity": "sha1-pHheE11d9lAk38kiSVPfWFvSdmw=", "dev": true }, "js-tokens": { diff --git a/package.json b/package.json index 8ab06dbf..001c8229 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "eslint-plugin-import": "^2.8.0", "eslint-plugin-jasmine": "^2.9.1", "eslint-plugin-react": "^7.3.0", - "jasmine": "^2.8.0" + "jasmine": "^3.1.0" }, "scripts": { "lint": "eslint .", From 566bab4c7262ab5c27ca020b31aaddaa2a48001a Mon Sep 17 00:00:00 2001 From: Aaditya Arvind Kulkarni Date: Fri, 16 Mar 2018 12:26:23 -0400 Subject: [PATCH 22/39] Fix linting for linked-list exercise (#529) Issue #399 --- .eslintignore | 1 - exercises/linked-list/example.js | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.eslintignore b/.eslintignore index 2d19a189..657ad2fe 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,7 +3,6 @@ exercises/custom-set exercises/flatten-array exercises/grains/big-integer.js exercises/grains/big-integer.spec.js -exercises/linked-list exercises/queen-attack exercises/robot-simulator exercises/saddle-points diff --git a/exercises/linked-list/example.js b/exercises/linked-list/example.js index 7c288bfa..672dff0c 100644 --- a/exercises/linked-list/example.js +++ b/exercises/linked-list/example.js @@ -10,7 +10,7 @@ function LinkedList() { this._front = null; } -LinkedList.prototype.push = function LinkedList_push(value) { +LinkedList.prototype.push = function (value) { if (this._front === null) { this._front = new Node(value); } else { @@ -21,18 +21,18 @@ LinkedList.prototype.push = function LinkedList_push(value) { } }; -LinkedList.prototype.unshift = function LinkedList_unshift(value) { +LinkedList.prototype.unshift = function (value) { this.push(value); this._front = this._front.prev; }; -LinkedList.prototype.pop = function LinkedList_pop() { - if (this._front === null) {return undefined;} +LinkedList.prototype.pop = function () { + if (this._front === null) {return null;} this._front = this._front.prev; return this.shift(); }; -LinkedList.prototype.shift = function LinkedList_shift() { +LinkedList.prototype.shift = function () { var value = this._front.value; var front = this._front.next; var back = this._front.prev; @@ -63,7 +63,7 @@ LinkedList.prototype.delete = function (match) { this._front.next = this._front.next.next; } else { this._front = this._front.next; - return this.delete(match); + this.delete(match); } }; From 3f1eca21fa34c04fb7044700cbeeccd25dfdc62b Mon Sep 17 00:00:00 2001 From: Tarun Velli Date: Sat, 17 Mar 2018 22:31:37 +0530 Subject: [PATCH 23/39] Fix linting for saddle points (#528) Issue #399 --- .eslintignore | 1 - exercises/saddle-points/example.js | 85 +++++++++++------------------- 2 files changed, 32 insertions(+), 54 deletions(-) diff --git a/.eslintignore b/.eslintignore index 657ad2fe..14b65a23 100644 --- a/.eslintignore +++ b/.eslintignore @@ -5,5 +5,4 @@ exercises/grains/big-integer.js exercises/grains/big-integer.spec.js exercises/queen-attack exercises/robot-simulator -exercises/saddle-points exercises/simple-cipher diff --git a/exercises/saddle-points/example.js b/exercises/saddle-points/example.js index 81217e7c..ac1cde4f 100644 --- a/exercises/saddle-points/example.js +++ b/exercises/saddle-points/example.js @@ -1,78 +1,57 @@ 'use strict'; -function toInt(s) { - return parseInt(s, 10); -} - module.exports = function Matrix(matrix) { - this.rows = []; - this.columns = []; - - var rows = matrix.split('\n'); - var i, j, currentRow; - - for (i = 0; i < rows.length; i++) { - currentRow = rows[i].replace(/^\s+|\s+$/g, '').split(' ').map( toInt ); - this.rows.push(currentRow); - } - - for (i = 0; i < this.rows[0].length; i++) { - this.columns.push([]); - } + this.rows = matrix.split('\n').map(function (row) { + return row.split(' ').map(function (val) { return parseInt(val, 10); }); + }); - for (i = 0; i < this.rows.length; i++) { - for (j = 0; j < this.columns.length; j++) { - this.columns[j].push(this.rows[i][j]); - } - } + this.columns = this.rows[0].map(function () { + return []; + }).map(function (column, index) { + return this.rows.map(function (row) { return row[index]; }); + }, this); this.indexesOfMaxValues = function (array) { - var i, currentElement, maxValue, indexes = []; + var maxValue = array.reduce(function (acc, curr) { + return Math.max(acc, curr); + }); - for (i = 0; i < array.length; i++) { - currentElement = array[i]; - if (maxValue === undefined || currentElement > maxValue) { - maxValue = currentElement; - indexes = [i]; - } else if (currentElement === maxValue) { - indexes.push(i); - } - } - - return indexes; + return this.indexsOf(array, maxValue); }; this.indexesOfMinValues = function (array) { - var i, currentElement, minValue, indexes = []; + var minValue = array.reduce(function (acc, curr) { + return Math.min(acc, curr); + }); - for (i = 0; i < array.length; i++) { - currentElement = array[i]; - if (minValue === undefined || currentElement < minValue) { - minValue = currentElement; - indexes = [i]; - } else if (currentElement === minValue) { - indexes.push(i); - } - } + return this.indexsOf(array, minValue); + }; - return indexes; + this.indexsOf = function (array, value) { + return array.map(function (val, index) { + return val === value ? index : null; + }).filter(function (val) { + return val !== null; + }); }; this.calculateSaddlePoints = function (rows, columns) { - var i, j, maxIndexes, minIndexes, currentMaxIndex, saddlePoints = []; + var maxIndexes; + var minIndexes; + var saddlePoints = []; - for (i = 0; i < rows.length; i++) { - maxIndexes = this.indexesOfMaxValues(rows[i]); + rows.forEach(function (row, i) { + maxIndexes = this.indexesOfMaxValues(row); - for (j = 0; j < maxIndexes.length; j++) { - currentMaxIndex = maxIndexes[j]; + maxIndexes.forEach(function (currentMaxIndex) { minIndexes = this.indexesOfMinValues(columns[currentMaxIndex]); if (minIndexes.indexOf(i) >= 0) { saddlePoints.push([i, currentMaxIndex]); } - } - } + }, this); + }, this); + return saddlePoints; }; From 1bf6bfdad5de27334fa2e53f2321c4200f1c13f6 Mon Sep 17 00:00:00 2001 From: Tejas Bubane Date: Thu, 22 Mar 2018 04:18:06 +0530 Subject: [PATCH 24/39] Fix errors in config for configlet v3.8.0 (#530) Closes #527. configlet v3.8.0 requires unlocked_by to be core exercise. Make the required changes. --- config.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config.json b/config.json index b717adca..1139e8c6 100644 --- a/config.json +++ b/config.json @@ -594,7 +594,7 @@ "text-formatting", "transforming" ], - "unlocked_by": "atbash-cipher", + "unlocked_by": "simple-cipher", "uuid": "a98e3593-d5b4-4c2b-8569-ae3ae7e07dad" }, { @@ -805,7 +805,7 @@ "control-flow-(loops)", "recursion" ], - "unlocked_by": "binary-search", + "unlocked_by": "linked-list", "uuid": "865806e0-950f-49a5-a6e5-26472b90ab85" }, { @@ -1130,7 +1130,7 @@ "Algorithms", "Mathematics" ], - "unlocked_by": "null", + "unlocked_by": null, "uuid" : "fd435dad-311a-4c40-9868-70863455831e" }, { @@ -1213,7 +1213,7 @@ "uuid": "b3dbc935-536e-4910-994d-4a519b511b6a", "slug": "forth", "core": false, - "unlocked_by": "saddle-points", + "unlocked_by": "matrix", "difficulty": 8, "topics": [ "stacks", @@ -1225,7 +1225,7 @@ "uuid": "f82e470d-0bcc-4eba-b9b0-8a0c50a6fd19", "slug": "variable-length-quantity", "core": false, - "unlocked_by": "two-bucket", + "unlocked_by": "grade-school", "difficulty": 5, "topics": [ "bitwise_operations", From 1f5a11c7020ffc12d73bbc28dec631d97b78f66e Mon Sep 17 00:00:00 2001 From: Tarun Velli Date: Sun, 25 Mar 2018 02:55:17 +0530 Subject: [PATCH 25/39] remove linted eercises from lint ignore (#533) --- .eslintignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.eslintignore b/.eslintignore index 14b65a23..749a0761 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,8 +1,5 @@ big-integer.js -exercises/custom-set -exercises/flatten-array exercises/grains/big-integer.js exercises/grains/big-integer.spec.js -exercises/queen-attack exercises/robot-simulator exercises/simple-cipher From 9ac0da445ba4e0c04e5e7d98a2ec2f1578f23332 Mon Sep 17 00:00:00 2001 From: Daniel Jordan <12012148+danielj-jordan@users.noreply.github.com> Date: Sat, 24 Mar 2018 14:26:50 -0700 Subject: [PATCH 26/39] implement the two recently addeded tests from the canonical test spec (#532) --- exercises/bowling/bowling.spec.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/exercises/bowling/bowling.spec.js b/exercises/bowling/bowling.spec.js index a507da47..c78b2f9d 100644 --- a/exercises/bowling/bowling.spec.js +++ b/exercises/bowling/bowling.spec.js @@ -208,5 +208,21 @@ describe('Bowling', function () { expect(function () { bowling.score(); }).toThrow( new Error('Score cannot be taken until the end of the game')); }); + + xit('cannot roll after bonus roll for a spare', function () { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 2]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.roll(2); }).toThrow( + new Error('Cannot roll after game is over')); + }); + + xit('cannot roll after bonus rolls for a strike', function () { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 3, 2]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.roll(2); }).toThrow( + new Error('Cannot roll after game is over')); + }); }); }); From fd567086481e7b85a5bbbb406b905acab72db6bb Mon Sep 17 00:00:00 2001 From: Allison Zhao Date: Fri, 30 Mar 2018 10:47:03 -0400 Subject: [PATCH 27/39] Fix robot simulator (#535) * Initial commit * Fix robot simulator * Remove function wrapping * Update const and let to var --- .eslintignore | 1 - exercises/robot-simulator/example.js | 142 +++++++++++++-------------- 2 files changed, 70 insertions(+), 73 deletions(-) diff --git a/.eslintignore b/.eslintignore index 749a0761..04c884de 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,4 @@ big-integer.js exercises/grains/big-integer.js exercises/grains/big-integer.spec.js -exercises/robot-simulator exercises/simple-cipher diff --git a/exercises/robot-simulator/example.js b/exercises/robot-simulator/example.js index 769134f5..96bb5c90 100644 --- a/exercises/robot-simulator/example.js +++ b/exercises/robot-simulator/example.js @@ -1,87 +1,85 @@ -var Robot = (function () { - 'use strict'; +'use strict'; - var VALID_DIRECTIONS = ['north', 'east', 'south', 'west']; - var INSTRUCTION_KEYS = { - A: 'advance', - L: 'turnLeft', - R: 'turnRight' - }; +var VALID_DIRECTIONS = ['north', 'east', 'south', 'west']; +var INSTRUCTION_KEYS = { + A: 'advance', + L: 'turnLeft', + R: 'turnRight' +}; - function Robot() { - this.coordinates = [0, 0]; - this.bearing = 'north'; - } - - Robot.prototype.at = function (x, y) { - this.coordinates = [x, y]; - }; +function Robot() { + this.coordinates = [0, 0]; + this.bearing = 'north'; +} - Robot.prototype.orient = function (direction) { - if (VALID_DIRECTIONS.indexOf(direction) === -1) { - throw new Error('Invalid Robot Bearing'); - } +Robot.prototype.at = function (x, y) { + this.coordinates = [x, y]; +}; - this.bearing = direction; - }; +Robot.prototype.orient = function (direction) { + if (VALID_DIRECTIONS.indexOf(direction) === -1) { + throw new Error('Invalid Robot Bearing'); + } - Robot.prototype.advance = function () { - switch (this.bearing) { - case 'north': - this.coordinates[1]++; - break; - case 'east': - this.coordinates[0]++; - break; - case 'south': - this.coordinates[1]--; - break; - case 'west': - this.coordinates[0]--; - break; - } - }; + this.bearing = direction; +}; - Robot.prototype.turnLeft = function () { - var directionPosition = VALID_DIRECTIONS.indexOf(this.bearing); +Robot.prototype.advance = function () { + switch (this.bearing) { + case 'north': + this.coordinates[1]++; + break; + case 'east': + this.coordinates[0]++; + break; + case 'south': + this.coordinates[1]--; + break; + case 'west': + this.coordinates[0]--; + break; + default: + break; + } +}; - if (directionPosition > 0) { - this.orient(VALID_DIRECTIONS[--directionPosition]); - } else { - this.orient(VALID_DIRECTIONS[VALID_DIRECTIONS.length - 1]); - } - }; +Robot.prototype.turnLeft = function () { + var directionPosition = VALID_DIRECTIONS.indexOf(this.bearing); - Robot.prototype.turnRight = function () { - var directionPosition = VALID_DIRECTIONS.indexOf(this.bearing); + if (directionPosition > 0) { + this.orient(VALID_DIRECTIONS[--directionPosition]); + } else { + this.orient(VALID_DIRECTIONS[VALID_DIRECTIONS.length - 1]); + } +}; - if (directionPosition < (VALID_DIRECTIONS.length - 1)) { - this.orient(VALID_DIRECTIONS[++directionPosition]); - } else { - this.orient(VALID_DIRECTIONS[0]); - } - }; +Robot.prototype.turnRight = function () { + var directionPosition = VALID_DIRECTIONS.indexOf(this.bearing); - Robot.prototype.instructions = function (instructionKeys) { - return instructionKeys.split('') - .map(function (key) { - return INSTRUCTION_KEYS[key]; - }); - }; + if (directionPosition < (VALID_DIRECTIONS.length - 1)) { + this.orient(VALID_DIRECTIONS[++directionPosition]); + } else { + this.orient(VALID_DIRECTIONS[0]); + } +}; - Robot.prototype.place = function (args) { - this.coordinates = [args.x, args.y]; - this.bearing = args.direction; - }; +Robot.prototype.instructions = function (instructionKeys) { + return instructionKeys.split('') + .map(function (key) { + return INSTRUCTION_KEYS[key]; + }); +}; - Robot.prototype.evaluate = function (instructionKeys) { - this.instructions(instructionKeys) - .forEach(function (instruction) { - this[instruction](); - }, this); - }; +Robot.prototype.place = function (args) { + this.coordinates = [args.x, args.y]; + this.bearing = args.direction; +}; - return Robot; -})(); +Robot.prototype.evaluate = function (instructionKeys) { + this.instructions(instructionKeys) + .forEach(function (instruction) { + this[instruction](); + }, this); +}; module.exports = Robot; From 1524838ef16b5cea02c9cefad2944a97a2c4da04 Mon Sep 17 00:00:00 2001 From: Allison Zhao Date: Fri, 6 Apr 2018 13:29:21 -0400 Subject: [PATCH 28/39] Fix linting errors for simple-cipher (#536) --- .eslintignore | 1 - exercises/simple-cipher/example.js | 10 ++++------ exercises/simple-cipher/simple-cipher.spec.js | 10 +++++++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.eslintignore b/.eslintignore index 04c884de..03223202 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,3 @@ big-integer.js exercises/grains/big-integer.js exercises/grains/big-integer.spec.js -exercises/simple-cipher diff --git a/exercises/simple-cipher/example.js b/exercises/simple-cipher/example.js index b8cc5151..6f0177fb 100644 --- a/exercises/simple-cipher/example.js +++ b/exercises/simple-cipher/example.js @@ -3,8 +3,8 @@ var ALPHABET = 'abcdefghijklmnopqrstuvwxyz'; function randomKey() { - var i, result = ''; - for ( i = 0; i < 100; i++ ) { + var result; + for ( var i = 0; i < 100; i++ ) { result += ALPHABET[randomUpTo(ALPHABET.length)]; } return result; @@ -17,15 +17,13 @@ function randomUpTo(n) { module.exports = function (userDefinedKey) { var key; - function addEncodedCharacter(character, index, array) { - /* jshint validthis:true */ + function addEncodedCharacter(character, index) { var i = ALPHABET.indexOf(character) + ALPHABET.indexOf(key[index % key.length]); if (i >= ALPHABET.length) { i -= ALPHABET.length; } this.push(ALPHABET[i]); } - function addDecodedCharacter(character, index, array) { - /* jshint validthis:true */ + function addDecodedCharacter(character, index) { var i = ALPHABET.indexOf(character) - ALPHABET.indexOf(key[index % key.length]); if (i < 0) { i += ALPHABET.length; } this.push(ALPHABET[i]); diff --git a/exercises/simple-cipher/simple-cipher.spec.js b/exercises/simple-cipher/simple-cipher.spec.js index f3fb2b39..38a08247 100644 --- a/exercises/simple-cipher/simple-cipher.spec.js +++ b/exercises/simple-cipher/simple-cipher.spec.js @@ -24,26 +24,30 @@ describe('Random key cipher', function () { }); }); +/* eslint-disable no-new */ + describe('Incorrect key cipher', function () { xit('throws an error with an all caps key', function () { - expect( function () { + expect(function () { new Cipher('ABCDEF'); }).toThrow(new Error('Bad key')); }); xit('throws an error with a numeric key', function () { - expect( function () { + expect(function () { new Cipher('12345'); }).toThrow(new Error('Bad key')); }); xit('throws an error with an empty key', function () { - expect( function () { + expect(function () { new Cipher(''); }).toThrow(new Error('Bad key')); }); }); +/* eslint-enable no-new */ + describe('Substitution cipher', function () { var key = 'abcdefghij'; var cipher = new Cipher(key); From 3b58a47192a80418650b85b92611987a1cbab1e0 Mon Sep 17 00:00:00 2001 From: Matthew Morgan Date: Mon, 9 Apr 2018 13:14:46 -0400 Subject: [PATCH 29/39] Update Bob to match README (#537) --- exercises/bob/bob.spec.js | 2 +- exercises/bob/example.js | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/exercises/bob/bob.spec.js b/exercises/bob/bob.spec.js index d8555e65..fc017cd1 100644 --- a/exercises/bob/bob.spec.js +++ b/exercises/bob/bob.spec.js @@ -45,7 +45,7 @@ describe('Bob', function () { xit('forceful questions', function () { var result = bob.hey('WHAT THE HELL WERE YOU THINKING?'); - expect(result).toEqual('Whoa, chill out!'); + expect(result).toEqual("Calm down, I know what I'm doing!"); }); xit('shouting numbers', function () { diff --git a/exercises/bob/example.js b/exercises/bob/example.js index 7826975f..b7fa2913 100644 --- a/exercises/bob/example.js +++ b/exercises/bob/example.js @@ -18,6 +18,9 @@ function Bob() { if (isSilence(message)) { return 'Fine. Be that way!'; } else if (isShouting(message)) { + if (isAQuestion(message)) { + return "Calm down, I know what I'm doing!"; + } return 'Whoa, chill out!'; } else if (isAQuestion(message)) { return 'Sure.'; From 025576d445b3dfc2dd045210b65c46520dba569c Mon Sep 17 00:00:00 2001 From: Dave Yarwood Date: Tue, 10 Apr 2018 09:47:45 -0400 Subject: [PATCH 30/39] add tests for random key generation, 100+ character length (#538) --- exercises/simple-cipher/simple-cipher.spec.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/exercises/simple-cipher/simple-cipher.spec.js b/exercises/simple-cipher/simple-cipher.spec.js index 38a08247..c59c16cf 100644 --- a/exercises/simple-cipher/simple-cipher.spec.js +++ b/exercises/simple-cipher/simple-cipher.spec.js @@ -1,5 +1,15 @@ var Cipher = require('./simple-cipher'); +describe('Random key generation', function () { + xit('generates keys at random', function () { + // Strictly speaking, this is difficult to test with 100% certainty. + // But, if you have a generator that generates 100-character-long + // strings of lowercase letters at random, the odds of two consecutively + // generated keys being identical are astronomically low. + expect(new Cipher().key).not.toEqual(new Cipher().key); + }); +}); + describe('Random key cipher', function () { var cipher = new Cipher(); @@ -7,6 +17,10 @@ describe('Random key cipher', function () { expect(cipher.key).toMatch(/^[a-z]+$/); }); + xit('has a key that is at least 100 characters long', function () { + expect(cipher.key.length).toBeGreaterThanOrEqual(100); + }); + // Here we take advantage of the fact that plaintext of "aaa..." // outputs the key. This is a critical problem with shift ciphers, some // characters will always output the key verbatim. From f81aef24fd9c33bbf345dcb9bb2b1d88738a1e0f Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Mon, 11 Jun 2018 01:36:18 -0600 Subject: [PATCH 31/39] Reformat config files (#549) This runs the configlet fmt command, which normalizes the contents and ordering of keys in the track config and maintainers config. This will let us script changes to the config files without having unnecessary noise in the diffs when submitting pull requests. --- config.json | 1128 ++++++++++++++++++++------------------- config/maintainers.json | 80 +-- 2 files changed, 617 insertions(+), 591 deletions(-) diff --git a/config.json b/config.json index 1139e8c6..4de97d0b 100644 --- a/config.json +++ b/config.json @@ -1,1192 +1,1221 @@ { + "language": "JavaScript", "active": true, + "blurb": "", + "test_pattern": ".*[.]spec[.]js$", "exercises": [ { + "slug": "hello-world", + "uuid": "4756cfc9-7509-4783-8be7-60e3376b8256", "core": true, + "unlocked_by": null, "difficulty": 1, - "slug": "hello-world", "topics": [ - "control-flow-(conditionals)", - "optional-values", + "control_flow_conditionals", + "optional_values", "strings", - "text-formatting" - ], - "uuid": "4756cfc9-7509-4783-8be7-60e3376b8256" + "text_formatting" + ] }, { + "slug": "two-fer", + "uuid": "5f3d1326-f0c5-44a6-b90a-6af3b7d455f1", "core": false, + "unlocked_by": "hello-world", "difficulty": 1, - "slug": "two-fer", "topics": [ - "strings", - "control-flow-(conditionals)" - ], - "unlocked_by": "hello-world", - "uuid": "5f3d1326-f0c5-44a6-b90a-6af3b7d455f1" + "control_flow_conditionals", + "strings" + ] }, { + "slug": "leap", + "uuid": "0c231a1c-55f7-47b6-8a54-ccae4ab0c65b", "core": true, + "unlocked_by": null, "difficulty": 1, - "slug": "leap", "topics": [ "booleans", "integers", "logic" - ], - "uuid": "0c231a1c-55f7-47b6-8a54-ccae4ab0c65b" + ] }, { + "slug": "reverse-string", + "uuid": "553a6be7-eecb-45dc-9cea-05126c525f1b", "core": false, + "unlocked_by": "leap", "difficulty": 2, - "slug": "reverse-string", "topics": [ - "loops", "for", + "loops", "strings" - ], - "unlocked_by": "leap", - "uuid": "553a6be7-eecb-45dc-9cea-05126c525f1b" + ] }, { + "slug": "rna-transcription", + "uuid": "d7f57ab9-2edb-44cb-a04e-c575c0f4be4c", "core": true, + "unlocked_by": null, "difficulty": 1, - "slug": "rna-transcription", "topics": [ "strings", "transforming" - ], - "uuid": "d7f57ab9-2edb-44cb-a04e-c575c0f4be4c" + ] }, { + "slug": "simple-cipher", + "uuid": "fff57c49-cde9-4a0c-b70b-2903cef212af", "core": true, + "unlocked_by": null, "difficulty": 1, - "slug": "simple-cipher", "topics": [ "algorithms", - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "mathematics", "randomness", "strings", - "text-formatting", + "text_formatting", "transforming" - ], - "uuid": "fff57c49-cde9-4a0c-b70b-2903cef212af" + ] }, { + "slug": "pangram", + "uuid": "c57bf909-130f-46e6-97ca-aeed58df1a15", "core": true, + "unlocked_by": null, "difficulty": 2, - "slug": "pangram", "topics": [ "algorithms", - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "lists", "maps", "searching", "strings" - ], - "uuid": "c57bf909-130f-46e6-97ca-aeed58df1a15" + ] }, { + "slug": "bob", + "uuid": "246be5d9-b361-4893-9707-f218ede2bed6", "core": true, + "unlocked_by": null, "difficulty": 2, - "slug": "bob", "topics": [ - "control-flow-(conditionals)", - "pattern-recognition", + "control_flow_conditionals", + "pattern_recognition", "polymorfism", - "regular-expressions", + "regular_expressions", "strings", "unicode" - ], - "uuid": "246be5d9-b361-4893-9707-f218ede2bed6" + ] }, { + "slug": "gigasecond", + "uuid": "49e4874b-d7e2-4305-a9bc-627fab4ada44", "core": true, + "unlocked_by": null, "difficulty": 2, - "slug": "gigasecond", "topics": [ "time" - ], - "uuid": "49e4874b-d7e2-4305-a9bc-627fab4ada44" + ] }, { + "slug": "space-age", + "uuid": "b668e11a-a8ce-4e94-ba68-3a1f0fa3f6c8", "core": true, + "unlocked_by": null, "difficulty": 3, - "slug": "space-age", "topics": [ "classes", - "floating-point-numbers", + "floating_point_numbers", "mathematics" - ], - "uuid": "b668e11a-a8ce-4e94-ba68-3a1f0fa3f6c8" + ] }, { + "slug": "binary", + "uuid": "c3035180-ff4c-4afe-8019-f8364158b74e", "core": true, + "unlocked_by": null, "difficulty": 4, - "slug": "binary", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "integers", "mathematics", - "regular-expressions", + "regular_expressions", "strings" - ], - "uuid": "c3035180-ff4c-4afe-8019-f8364158b74e" + ] }, { + "slug": "prime-factors", + "uuid": "73ecd6c2-e59b-4354-b305-64e28a60433f", "core": true, + "unlocked_by": null, "difficulty": 4, - "slug": "prime-factors", "topics": [ "algorithms", - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "integers", "mathematics" - ], - "uuid": "73ecd6c2-e59b-4354-b305-64e28a60433f" + ] }, { + "slug": "matrix", + "uuid": "fbfe6032-c209-40bd-b485-8b2881638166", "core": true, + "unlocked_by": null, "difficulty": 4, - "slug": "matrix", "topics": [ "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", - "data-structures", + "control_flow_conditionals", + "control_flow_loops", + "data_structures", "matrices", - "text-formatting" - ], - "uuid": "fbfe6032-c209-40bd-b485-8b2881638166" + "text_formatting" + ] }, { + "slug": "linked-list", + "uuid": "ecc41237-f629-458f-873e-2cc51ba1a385", "core": true, + "unlocked_by": null, "difficulty": 5, - "slug": "linked-list", "topics": [ "algorithms", "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", - "data-structures", + "control_flow_conditionals", + "control_flow_loops", + "data_structures", "lists", - "optional-values" - ], - "uuid": "ecc41237-f629-458f-873e-2cc51ba1a385" + "optional_values" + ] }, { + "slug": "pascals-triangle", + "uuid": "a96ab45d-10a0-42cf-a754-c2466037ceaf", "core": true, + "unlocked_by": null, "difficulty": 5, - "slug": "pascals-triangle", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "mathematics", "strings", - "text-formatting" - ], - "uuid": "a96ab45d-10a0-42cf-a754-c2466037ceaf" + "text_formatting" + ] }, { + "slug": "secret-handshake", + "uuid": "0a3a452c-f734-47eb-8e65-34c8ae710ef0", "core": true, + "unlocked_by": null, "difficulty": 6, - "slug": "secret-handshake", "topics": [ "algorithms", "arrays", - "bitwise-operations", - "control-flow-(conditionals)", - "control-flow-(loops)", + "bitwise_operations", + "control_flow_conditionals", + "control_flow_loops", "games" - ], - "uuid": "0a3a452c-f734-47eb-8e65-34c8ae710ef0" + ] }, { + "slug": "rotational-cipher", + "uuid": "7078b1a4-ef73-4c02-809d-b2de62e9af11", "core": false, + "unlocked_by": "secret-handshake", "difficulty": 6, - "slug": "rotational-cipher", "topics": [ "cryptography", "integers", "strings" - ], - "unlocked_by": "secret-handshake", - "uuid": "7078b1a4-ef73-4c02-809d-b2de62e9af11" + ] }, { + "slug": "grade-school", + "uuid": "029bc3ed-772d-439b-bd0a-1ba1196a79ec", "core": true, + "unlocked_by": null, "difficulty": 6, - "slug": "grade-school", "topics": [ "arrays", "maps", "sorting" - ], - "uuid": "029bc3ed-772d-439b-bd0a-1ba1196a79ec" + ] }, { + "slug": "robot-name", + "uuid": "3005340b-a8d6-46ac-9075-125f9adccc2a", "core": true, + "unlocked_by": null, "difficulty": 6, - "slug": "robot-name", "topics": [ - "control-flow-(conditionals)", - "exception-handling", + "control_flow_conditionals", + "exception_handling", "randomness", - "regular-expressions", + "regular_expressions", "sets" - ], - "uuid": "3005340b-a8d6-46ac-9075-125f9adccc2a" + ] }, { + "slug": "wordy", + "uuid": "bb54bf08-24ba-45e1-bdf7-08db161e5843", "core": true, + "unlocked_by": null, "difficulty": 7, - "slug": "wordy", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "parsing", - "pattern-recognition", - "regular-expressions", + "pattern_recognition", + "regular_expressions", "strings" - ], - "uuid": "bb54bf08-24ba-45e1-bdf7-08db161e5843" + ] }, { + "slug": "list-ops", + "uuid": "e70defe4-5944-4392-956c-63cb92e7fd9c", "core": true, + "unlocked_by": null, "difficulty": 8, - "slug": "list-ops", "topics": [ - "data-structures", + "data_structures", "lists", "recursion" - ], - "uuid": "e70defe4-5944-4392-956c-63cb92e7fd9c" + ] }, { + "slug": "rational-numbers", + "uuid": "2de5677e-5759-4a21-93c7-39a3d88242e8", "core": false, + "unlocked_by": "pascals-triangle", "difficulty": 5, - "slug": "rational-numbers", "topics": [ + "algorithms", "floating_point_numbers", - "mathematics", - "algorithms" - ], - "unlocked_by": "pascals-triangle", - "uuid": "2de5677e-5759-4a21-93c7-39a3d88242e8" + "mathematics" + ] }, { + "slug": "hamming", + "uuid": "3e1358c8-2bea-41f9-bc9e-8277f354a4e0", "core": false, + "unlocked_by": "rna-transcription", "difficulty": 2, - "slug": "hamming", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "equality", "strings" - ], - "unlocked_by": "rna-transcription", - "uuid": "3e1358c8-2bea-41f9-bc9e-8277f354a4e0" + ] }, { + "slug": "run-length-encoding", + "uuid": "d66c2b56-b465-4922-af35-ae78944c0aac", "core": false, + "unlocked_by": null, "difficulty": 2, - "slug": "run-length-encoding", "topics": [ - "control-flow-(conditionals)", - "exception-handling", + "control_flow_conditionals", + "exception_handling", "parsing", - "pattern-recognition", - "regular-expressions", + "pattern_recognition", + "regular_expressions", "strings", - "text-formatting" - ], - "unlocked_by": null, - "uuid": "d66c2b56-b465-4922-af35-ae78944c0aac" + "text_formatting" + ] }, { + "slug": "isogram", + "uuid": "35821375-5c94-4d4b-aa56-e3b079a45ca0", "core": false, + "unlocked_by": "pangram", "difficulty": 2, - "slug": "isogram", "topics": [ "filtering", "strings" - ], - "unlocked_by": "pangram", - "uuid": "35821375-5c94-4d4b-aa56-e3b079a45ca0" + ] }, { + "slug": "beer-song", + "uuid": "6f315fc3-095a-4387-aefb-cc5fee97110a", "core": false, + "unlocked_by": "bob", "difficulty": 5, - "slug": "beer-song", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "strings" - ], - "unlocked_by": "bob", - "uuid": "6f315fc3-095a-4387-aefb-cc5fee97110a" + ] }, { + "slug": "phone-number", + "uuid": "347f9f54-a0d9-469d-babf-b3edb34d9d70", "core": false, + "unlocked_by": "pangram", "difficulty": 3, - "slug": "phone-number", "topics": [ "parsing", "transforming" - ], - "unlocked_by": "pangram", - "uuid": "347f9f54-a0d9-469d-babf-b3edb34d9d70" + ] }, { + "slug": "anagram", + "uuid": "432ec2ce-c919-4142-aea2-389b67503252", "core": false, + "unlocked_by": "pangram", "difficulty": 1, - "slug": "anagram", "topics": [ "filtering", "strings" - ], - "unlocked_by": "pangram", - "uuid": "432ec2ce-c919-4142-aea2-389b67503252" + ] }, { + "slug": "food-chain", + "uuid": "a717745f-da00-4a5f-8bf3-6876e20cdf17", "core": false, + "unlocked_by": "bob", "difficulty": 4, - "slug": "food-chain", "topics": [ "algorithms", - "text-formatting" - ], - "unlocked_by": "bob", - "uuid": "a717745f-da00-4a5f-8bf3-6876e20cdf17" + "text_formatting" + ] }, { + "slug": "etl", + "uuid": "a2a19f61-62ba-447a-8f57-537c8baa2e7a", "core": false, + "unlocked_by": "rna-transcription", "difficulty": 2, - "slug": "etl", "topics": [ - "control-flow-(loops)", + "control_flow_loops", "integers", "maps", "transforming" - ], - "unlocked_by": "rna-transcription", - "uuid": "a2a19f61-62ba-447a-8f57-537c8baa2e7a" + ] }, { + "slug": "sublist", + "uuid": "4a83a72c-db0a-45b6-b77c-1949cb24fbae", "core": false, + "unlocked_by": "linked-list", "difficulty": 4, - "slug": "sublist", "topics": [ "arrays", "lists" - ], - "unlocked_by": "linked-list", - "uuid": "4a83a72c-db0a-45b6-b77c-1949cb24fbae" + ] }, { + "slug": "grains", + "uuid": "c5be6908-f45c-4278-ba99-3701024f4eda", "core": false, + "unlocked_by": "space-age", "difficulty": 5, - "slug": "grains", "topics": [ - "control-flow-(loops)", + "control_flow_loops", "integers", "mathematics" - ], - "unlocked_by": "space-age", - "uuid": "c5be6908-f45c-4278-ba99-3701024f4eda" + ] }, { + "slug": "triangle", + "uuid": "fde792fa-84e9-4b86-8ecb-8466ad92a99d", "core": false, + "unlocked_by": "leap", "difficulty": 3, - "slug": "triangle", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "integers", "mathematics" - ], - "unlocked_by": "leap", - "uuid": "fde792fa-84e9-4b86-8ecb-8466ad92a99d" + ] }, { + "slug": "clock", + "uuid": "1ff85150-6c51-4758-af02-4484cf35658e", "core": false, + "unlocked_by": "gigasecond", "difficulty": 5, - "slug": "clock", "topics": [ "dates", "globalization", "time" - ], - "unlocked_by": "gigasecond", - "uuid": "1ff85150-6c51-4758-af02-4484cf35658e" + ] }, { + "slug": "perfect-numbers", + "uuid": "51aa5429-b2db-43ad-83cf-84e2ead22cb6", "core": false, + "unlocked_by": "space-age", "difficulty": 3, - "slug": "perfect-numbers", "topics": [ "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "integers", "mathematics" - ], - "unlocked_by": "space-age", - "uuid": "51aa5429-b2db-43ad-83cf-84e2ead22cb6" + ] }, { + "slug": "word-count", + "uuid": "9a4ea3da-ad43-4850-bdf3-2c578c5de838", "core": false, + "unlocked_by": "pangram", "difficulty": 1, - "slug": "word-count", "topics": [ - "control-flow-(loops)", + "control_flow_loops", "lists", - "regular-expressions", + "regular_expressions", "strings", "unicode" - ], - "unlocked_by": "pangram", - "uuid": "9a4ea3da-ad43-4850-bdf3-2c578c5de838" + ] }, { + "slug": "acronym", + "uuid": "0c1c4788-0372-42e7-81c1-b090bb7ebc8b", "core": false, + "unlocked_by": "pangram", "difficulty": 2, - "slug": "acronym", "topics": [ - "control-flow-(loops)", - "regular-expressions", + "control_flow_loops", + "regular_expressions", "strings", "transforming" - ], - "unlocked_by": "pangram", - "uuid": "0c1c4788-0372-42e7-81c1-b090bb7ebc8b" + ] }, { + "slug": "scrabble-score", + "uuid": "a6bd8126-3879-4593-8380-39ebfa87801b", "core": false, + "unlocked_by": "rna-transcription", "difficulty": 5, - "slug": "scrabble-score", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "maps", "strings" - ], - "unlocked_by": "rna-transcription", - "uuid": "a6bd8126-3879-4593-8380-39ebfa87801b" + ] }, { + "slug": "roman-numerals", + "uuid": "4226e3c6-99d4-406d-998a-bcf11845b211", "core": false, + "unlocked_by": null, "difficulty": 3, - "slug": "roman-numerals", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "mathematics", - "pattern-recognition", + "pattern_recognition", "transforming" - ], - "unlocked_by": null, - "uuid": "4226e3c6-99d4-406d-998a-bcf11845b211" + ] }, { + "slug": "circular-buffer", + "uuid": "f1943e87-182a-44f5-a885-3d68a0c0a0dc", "core": false, + "unlocked_by": "linked-list", "difficulty": 8, - "slug": "circular-buffer", "topics": [ "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", - "data-structures", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "data_structures", + "exception_handling", "lists" - ], - "unlocked_by": "linked-list", - "uuid": "f1943e87-182a-44f5-a885-3d68a0c0a0dc" + ] }, { + "slug": "raindrops", + "uuid": "86b1acf1-9e2d-4b04-b8b0-e9ae6beb5f3d", "core": false, + "unlocked_by": "rna-transcription", "difficulty": 2, - "slug": "raindrops", "topics": [ - "control-flow-(conditionals)", + "control_flow_conditionals", "integers", "strings", "transforming" - ], - "unlocked_by": "rna-transcription", - "uuid": "86b1acf1-9e2d-4b04-b8b0-e9ae6beb5f3d" + ] }, { + "slug": "allergies", + "uuid": "23210e9e-81f6-4279-a776-00459c7ccd02", "core": false, + "unlocked_by": "rna-transcription", "difficulty": 6, - "slug": "allergies", "topics": [ "arrays", - "bitwise-operations", - "control-flow-(conditionals)", - "control-flow-(loops)" - ], - "unlocked_by": "rna-transcription", - "uuid": "23210e9e-81f6-4279-a776-00459c7ccd02" + "bitwise_operations", + "control_flow_conditionals", + "control_flow_loops" + ] }, { + "slug": "strain", + "uuid": "e61f3d54-55d2-4d32-9d2a-e7d6af3a3247", "core": false, + "unlocked_by": "list-ops", "difficulty": 4, - "slug": "strain", "topics": [ "algorithms", "arrays", "callbacks", - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "filtering", "lists" - ], - "unlocked_by": "list-ops", - "uuid": "e61f3d54-55d2-4d32-9d2a-e7d6af3a3247" + ] }, { + "slug": "atbash-cipher", + "uuid": "99974454-0736-4cc0-b88f-ed5701397a97", "core": false, + "unlocked_by": "simple-cipher", "difficulty": 7, - "slug": "atbash-cipher", "topics": [ "algorithms", "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", - "regular-expressions", - "text-formatting" - ], - "unlocked_by": "simple-cipher", - "uuid": "99974454-0736-4cc0-b88f-ed5701397a97" + "control_flow_conditionals", + "control_flow_loops", + "regular_expressions", + "text_formatting" + ] }, { + "slug": "accumulate", + "uuid": "dc9b2598-9757-4b20-82f9-8049ad081ac9", "core": false, + "unlocked_by": "list-ops", "difficulty": 5, - "slug": "accumulate", "topics": [ "algorithms", "callbacks", - "control-flow-(loops)", + "control_flow_loops", "lists" - ], - "unlocked_by": "list-ops", - "uuid": "dc9b2598-9757-4b20-82f9-8049ad081ac9" + ] }, { + "slug": "crypto-square", + "uuid": "a98e3593-d5b4-4c2b-8569-ae3ae7e07dad", "core": false, + "unlocked_by": "simple-cipher", "difficulty": 9, - "slug": "crypto-square", "topics": [ "algorithms", "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", - "regular-expressions", + "control_flow_conditionals", + "control_flow_loops", + "regular_expressions", "sorting", - "text-formatting", + "text_formatting", "transforming" - ], - "unlocked_by": "simple-cipher", - "uuid": "a98e3593-d5b4-4c2b-8569-ae3ae7e07dad" + ] }, { + "slug": "trinary", + "uuid": "f317721d-e1f5-4e68-9fdc-f9bc7b6b004d", "core": false, + "unlocked_by": "binary", "difficulty": 4, - "slug": "trinary", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "integers", "mathematics", - "regular-expressions", + "regular_expressions", "strings" - ], - "unlocked_by": "binary", - "uuid": "f317721d-e1f5-4e68-9fdc-f9bc7b6b004d" + ] }, { + "slug": "sieve", + "uuid": "4cad8ee8-40be-4d4d-8c14-45d8c6e29a32", "core": false, + "unlocked_by": "prime-factors", "difficulty": 5, - "slug": "sieve", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "integers", "mathematics", "recursion" - ], - "unlocked_by": "prime-factors", - "uuid": "4cad8ee8-40be-4d4d-8c14-45d8c6e29a32" + ] }, { + "slug": "octal", + "uuid": "9892d47d-97a0-4a2f-8284-6f84c86559e8", "core": false, + "unlocked_by": "binary", "difficulty": 4, - "slug": "octal", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "integers", "mathematics", - "regular-expressions", + "regular_expressions", "strings" - ], - "unlocked_by": "binary", - "uuid": "9892d47d-97a0-4a2f-8284-6f84c86559e8" + ] }, { + "slug": "luhn", + "uuid": "bb46e832-8c37-45ee-9ee7-5037015b965c", "core": false, + "unlocked_by": "space-age", "difficulty": 4, - "slug": "luhn", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "integers", "mathematics", "strings" - ], - "unlocked_by": "space-age", - "uuid": "bb46e832-8c37-45ee-9ee7-5037015b965c" + ] }, { + "slug": "pig-latin", + "uuid": "9a515ad0-34c7-4191-8784-5c4cd6385b38", "core": false, + "unlocked_by": "bob", "difficulty": 4, - "slug": "pig-latin", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "games", - "regular-expressions", + "regular_expressions", "strings", "transforming" - ], - "unlocked_by": "bob", - "uuid": "9a515ad0-34c7-4191-8784-5c4cd6385b38" + ] }, { + "slug": "pythagorean-triplet", + "uuid": "26a973dd-d72e-40fb-abeb-0ba306356ed6", "core": false, + "unlocked_by": "space-age", "difficulty": 5, - "slug": "pythagorean-triplet", "topics": [ "algorithms", - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "integers", "mathematics" - ], - "unlocked_by": "space-age", - "uuid": "26a973dd-d72e-40fb-abeb-0ba306356ed6" + ] }, { + "slug": "series", + "uuid": "06afdb06-8d2a-4cb0-baf1-48ae997cf1f5", "core": false, + "unlocked_by": "pangram", "difficulty": 3, - "slug": "series", "topics": [ - "control-flow-(loops)", - "exception-handling", + "control_flow_loops", + "exception_handling", "strings", - "text-formatting" - ], - "unlocked_by": "pangram", - "uuid": "06afdb06-8d2a-4cb0-baf1-48ae997cf1f5" + "text_formatting" + ] }, { + "slug": "difference-of-squares", + "uuid": "07110dd5-b879-40b9-9485-685cb0963d8f", "core": false, + "unlocked_by": "space-age", "difficulty": 3, - "slug": "difference-of-squares", "topics": [ "algorithms", - "control-flow-(loops)", + "control_flow_loops", "integers", "mathematics" - ], - "unlocked_by": "space-age", - "uuid": "07110dd5-b879-40b9-9485-685cb0963d8f" + ] }, { + "slug": "proverb", + "uuid": "8786d591-077b-49bc-be8d-d014dc9dc308", "core": false, + "unlocked_by": "bob", "difficulty": 4, - "slug": "proverb", "topics": [ "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", - "optional-values", + "control_flow_conditionals", + "control_flow_loops", + "optional_values", "strings", - "text-formatting" - ], - "unlocked_by": "bob", - "uuid": "8786d591-077b-49bc-be8d-d014dc9dc308" + "text_formatting" + ] }, { + "slug": "flatten-array", + "uuid": "32a0a5fa-c7de-470c-beff-118b448b3916", "core": false, + "unlocked_by": "list-ops", "difficulty": 1, - "slug": "flatten-array", "topics": [ "arrays", "recursion" - ], - "unlocked_by": "list-ops", - "uuid": "32a0a5fa-c7de-470c-beff-118b448b3916" + ] }, { + "slug": "hexadecimal", + "uuid": "33b8f4c0-3210-478a-9225-5c30ad6df870", "core": false, + "unlocked_by": "binary", "difficulty": 4, - "slug": "hexadecimal", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "integers", "mathematics", - "regular-expressions", + "regular_expressions", "strings" - ], - "unlocked_by": "binary", - "uuid": "33b8f4c0-3210-478a-9225-5c30ad6df870" + ] }, { + "slug": "largest-series-product", + "uuid": "44bd02a7-0e3a-4441-ab76-524e36d4661c", "core": false, + "unlocked_by": "pangram", "difficulty": 7, - "slug": "largest-series-product", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "integers", "mathematics", - "regular-expressions", + "regular_expressions", "strings" - ], - "unlocked_by": "pangram", - "uuid": "44bd02a7-0e3a-4441-ab76-524e36d4661c" + ] }, { + "slug": "kindergarten-garden", + "uuid": "2702ac90-0be2-43a2-91b6-7256a25fec87", "core": false, + "unlocked_by": "wordy", "difficulty": 7, - "slug": "kindergarten-garden", "topics": [ "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "strings", - "text-formatting" - ], - "unlocked_by": "wordy", - "uuid": "2702ac90-0be2-43a2-91b6-7256a25fec87" + "text_formatting" + ] }, { + "slug": "binary-search", + "uuid": "5991c379-f033-4b46-9702-6b7fd03640e8", "core": false, + "unlocked_by": "linked-list", "difficulty": 7, - "slug": "binary-search", "topics": [ "algorithms", "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "recursion" - ], - "unlocked_by": "linked-list", - "uuid": "5991c379-f033-4b46-9702-6b7fd03640e8" + ] }, { + "slug": "binary-search-tree", + "uuid": "865806e0-950f-49a5-a6e5-26472b90ab85", "core": false, + "unlocked_by": "linked-list", "difficulty": 6, - "slug": "binary-search-tree", "topics": [ "algorithms", - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "recursion" - ], - "unlocked_by": "linked-list", - "uuid": "865806e0-950f-49a5-a6e5-26472b90ab85" + ] }, { + "slug": "robot-simulator", + "uuid": "00002977-ea1e-45e2-b66e-09d793b5c1ad", "core": false, + "unlocked_by": "wordy", "difficulty": 5, - "slug": "robot-simulator", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "games", "parsing", "strings" - ], - "unlocked_by": "wordy", - "uuid": "00002977-ea1e-45e2-b66e-09d793b5c1ad" + ] }, { + "slug": "nth-prime", + "uuid": "8fa51380-ec2c-4806-8833-cf543579de17", "core": false, + "unlocked_by": "prime-factors", "difficulty": 5, - "slug": "nth-prime", "topics": [ "algorithms", - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "integers", "mathematics" - ], - "unlocked_by": "prime-factors", - "uuid": "8fa51380-ec2c-4806-8833-cf543579de17" + ] }, { + "slug": "palindrome-products", + "uuid": "fde83f66-d927-48f8-a599-efb98927f0b1", "core": false, + "unlocked_by": "prime-factors", "difficulty": 7, - "slug": "palindrome-products", "topics": [ "algorithms", - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "integers", "mathematics" - ], - "unlocked_by": "prime-factors", - "uuid": "fde83f66-d927-48f8-a599-efb98927f0b1" + ] }, { + "slug": "say", + "uuid": "01d286f6-5f29-4d4b-a4de-e217a4833bfa", "core": false, + "unlocked_by": "bob", "difficulty": 6, - "slug": "say", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "integers", "mathematics", "strings", - "text-formatting" - ], - "unlocked_by": "bob", - "uuid": "01d286f6-5f29-4d4b-a4de-e217a4833bfa" + "text_formatting" + ] }, { + "slug": "custom-set", + "uuid": "d4ec15c4-2742-493b-97fe-9d5121f0b659", "core": false, + "unlocked_by": "linked-list", "difficulty": 6, - "slug": "custom-set", "topics": [ "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", - "data-structures", + "control_flow_conditionals", + "control_flow_loops", + "data_structures", "equality", "lists", "recursion", "sets" - ], - "unlocked_by": "linked-list", - "uuid": "d4ec15c4-2742-493b-97fe-9d5121f0b659" + ] }, { + "slug": "sum-of-multiples", + "uuid": "f30463c4-9d8c-4238-a691-e594291b4425", "core": false, + "unlocked_by": "prime-factors", "difficulty": 5, - "slug": "sum-of-multiples", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "integers", "lists" - ], - "unlocked_by": "prime-factors", - "uuid": "f30463c4-9d8c-4238-a691-e594291b4425" + ] }, { + "slug": "queen-attack", + "uuid": "fefcfeba-59ec-4c63-a562-374201ee39a7", "core": false, + "unlocked_by": null, "difficulty": 8, - "slug": "queen-attack", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "equality", - "exception-handling", - "optional-values", + "exception_handling", + "optional_values", "parsing", - "text-formatting" - ], - "unlocked_by": null, - "uuid": "fefcfeba-59ec-4c63-a562-374201ee39a7" + "text_formatting" + ] }, { + "slug": "saddle-points", + "uuid": "98cbae4f-78b6-4745-b922-39e8db9a12bb", "core": false, + "unlocked_by": "matrix", "difficulty": 6, - "slug": "saddle-points", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "equality", - "exception-handling", + "exception_handling", "integers", "mathematics", "matrices", - "optional-values", + "optional_values", "parsing" - ], - "unlocked_by": "matrix", - "uuid": "98cbae4f-78b6-4745-b922-39e8db9a12bb" + ] }, { + "slug": "ocr-numbers", + "uuid": "759618b1-7ccc-46cd-889d-aea58ec88756", "core": false, + "unlocked_by": "matrix", "difficulty": 5, - "slug": "ocr-numbers", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "equality", - "exception-handling", + "exception_handling", "integers", "parsing", - "text-formatting" - ], - "unlocked_by": "matrix", - "uuid": "759618b1-7ccc-46cd-889d-aea58ec88756" + "text_formatting" + ] }, { + "slug": "meetup", + "uuid": "86b1b6ba-c1fe-492d-a7ec-c22c525b4da8", "core": false, + "unlocked_by": "gigasecond", "difficulty": 7, - "slug": "meetup", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", + "control_flow_conditionals", + "control_flow_loops", "dates", "equality", - "exception-handling", + "exception_handling", "time" - ], - "unlocked_by": "gigasecond", - "uuid": "86b1b6ba-c1fe-492d-a7ec-c22c525b4da8" + ] }, { + "slug": "bracket-push", + "uuid": "25099f87-5c3b-4a8a-b648-4639d1e9fa84", "core": false, + "unlocked_by": "pangram", "difficulty": 3, - "slug": "bracket-push", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "parsing", "strings" - ], - "unlocked_by": "pangram", - "uuid": "25099f87-5c3b-4a8a-b648-4639d1e9fa84" + ] }, { + "slug": "two-bucket", + "uuid": "4c857b17-33b0-47fa-b981-6b2fe4e394a1", "core": false, + "unlocked_by": "grade-school", "difficulty": 6, - "slug": "two-bucket", "topics": [ "algorithms", "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "games", "parsing" - ], - "unlocked_by": "grade-school", - "uuid": "4c857b17-33b0-47fa-b981-6b2fe4e394a1" + ] }, { + "slug": "bowling", + "uuid": "c168fe1f-f84e-46e6-91fc-7553d048a4e9", "core": false, + "unlocked_by": "grade-school", "difficulty": 8, - "slug": "bowling", "topics": [ "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "games", "parsing", - "text-formatting" - ], - "unlocked_by": "grade-school", - "uuid": "c168fe1f-f84e-46e6-91fc-7553d048a4e9" + "text_formatting" + ] }, { + "slug": "diamond", + "uuid": "04a4ef78-5b61-454f-8c37-798875fb4956", "core": false, + "unlocked_by": "pascals-triangle", "difficulty": 5, - "slug": "diamond", "topics": [ "arrays", - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "games", "parsing", - "text-formatting" - ], - "unlocked_by": "pascals-triangle", - "uuid": "04a4ef78-5b61-454f-8c37-798875fb4956" + "text_formatting" + ] }, { + "slug": "all-your-base", + "uuid": "cdfcec62-f2f3-4408-ad2c-8b5e1e56e791", "core": false, + "unlocked_by": "binary", "difficulty": 5, - "slug": "all-your-base", "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", - "exception-handling", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", "integers", "mathematics", "parsing" - ], - "unlocked_by": "binary", - "uuid": "cdfcec62-f2f3-4408-ad2c-8b5e1e56e791" + ] }, { + "slug": "minesweeper", + "uuid": "22fa5ab4-935b-44cc-b055-9803214ae5f3", "core": false, + "unlocked_by": null, "difficulty": 7, - "slug": "minesweeper", "topics": [ "algorithms", "arrays", "games" - ], - "unlocked_by": null, - "uuid": "22fa5ab4-935b-44cc-b055-9803214ae5f3" + ] }, { + "slug": "alphametics", + "uuid": "42a7fd83-4508-403c-8b5e-f0a3126fac8a", "core": false, + "unlocked_by": "grade-school", "difficulty": 7, - "slug": "alphametics", "topics": [ "algorithms", "games" - ], - "unlocked_by": "grade-school", - "uuid": "42a7fd83-4508-403c-8b5e-f0a3126fac8a" + ] }, { + "slug": "simple-linked-list", + "uuid": "c21ab6e8-b845-49d0-a2f6-1c89c7a07626", "core": false, + "unlocked_by": "linked-list", "difficulty": 8, - "slug": "simple-linked-list", "topics": [ "arrays", - "data-structures", + "data_structures", "lists" - ], - "unlocked_by": "linked-list", - "uuid": "c21ab6e8-b845-49d0-a2f6-1c89c7a07626" + ] }, { - "uuid": "833bd7c7-d3d8-45fd-a218-12dea646065d", "slug": "diffie-hellman", + "uuid": "833bd7c7-d3d8-45fd-a218-12dea646065d", "core": false, "unlocked_by": "simple-cipher", "difficulty": 3, "topics": [ - "Control-flow (conditionals)", - "Control-flow (loops)", - "Algorithms", - "Arrays", - "Exception handling" + "algorithms", + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling" ] }, { - "core" : false, - "difficulty" : 8, - "slug" : "change", - "topics": [ - "Algorithms", - "Mathematics", - "Performance", - "Searching" - ], + "slug": "change", + "uuid": "910fe904-7e3c-11e7-bb31-be2e44b06b34", + "core": false, "unlocked_by": "prime-factors", - "uuid" : "910fe904-7e3c-11e7-bb31-be2e44b06b34" + "difficulty": 8, + "topics": [ + "algorithms", + "mathematics", + "performance", + "searching" + ] }, { - "uuid": "3b779cb8-9544-4e0d-a306-e5478d741be7", "slug": "connect", + "uuid": "3b779cb8-9544-4e0d-a306-e5478d741be7", "core": false, "unlocked_by": "grade-school", "difficulty": 7, "topics": [ - "Control-flow (loops)", - "Control-flow (conditionals)", - "Games", - "Parsing", - "Arrays", - "Maps" - ] - }, - { - "core" : false, - "difficulty" : 1, - "slug" : "collatz-conjecture", - "topics": [ - "Control-flow (loops)", - "Control-flow (conditionals)", - "Recursion", - "Integers", - "Algorithms", - "Mathematics" - ], + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "games", + "maps", + "parsing" + ] + }, + { + "slug": "collatz-conjecture", + "uuid": "fd435dad-311a-4c40-9868-70863455831e", + "core": false, "unlocked_by": null, - "uuid" : "fd435dad-311a-4c40-9868-70863455831e" + "difficulty": 1, + "topics": [ + "algorithms", + "control_flow_conditionals", + "control_flow_loops", + "integers", + "mathematics", + "recursion" + ] }, { - "deprecated": true, "slug": "nucleotide-count", - "uuid": "1b53340d-ea40-44ee-bf2e-42e516704e7c" + "uuid": "1b53340d-ea40-44ee-bf2e-42e516704e7c", + "core": false, + "unlocked_by": null, + "difficulty": 0, + "topics": null, + "deprecated": true }, { - "deprecated": true, "slug": "point-mutations", - "uuid": "e9a6b2ea-a67d-4b75-800d-7b46240094ec" + "uuid": "e9a6b2ea-a67d-4b75-800d-7b46240094ec", + "core": false, + "unlocked_by": null, + "difficulty": 0, + "topics": null, + "deprecated": true }, { - "uuid": "09e10522-9853-11e7-abc4-cec278b6b50a", "slug": "twelve-days", + "uuid": "09e10522-9853-11e7-abc4-cec278b6b50a", "core": false, "unlocked_by": "bob", "difficulty": 4, "topics": [ - "Control-flow (conditionals)", - "Control-flow (loops)", - "Strings", - "Pattern recognition" + "control_flow_conditionals", + "control_flow_loops", + "pattern_recognition", + "strings" ] }, { + "slug": "transpose", + "uuid": "7c024853-0540-473d-b2d9-cad84953c00f", "core": false, + "unlocked_by": "matrix", "difficulty": 1, - "slug": "transpose", "topics": [ - "loops", "arrays", "lists", + "loops", "matrices", "strings", "text_formatting" - ], - "unlocked_by": "matrix", - "uuid": "7c024853-0540-473d-b2d9-cad84953c00f" + ] }, { - "uuid": "52c775a4-7ddb-4cba-8a78-8544220bd1b6", "slug": "protein-translation", + "uuid": "52c775a4-7ddb-4cba-8a78-8544220bd1b6", "core": false, "unlocked_by": null, "difficulty": 1, "topics": [ - "control-flow-(conditionals)", - "control-flow-(loops)", - "strings", - "algorithms" + "algorithms", + "control_flow_conditionals", + "control_flow_loops", + "strings" ] }, { - "uuid": "f4a3d66a-04a8-3e80-6c9a-8a573ccb26fd9ed1d5c", "slug": "zipper", + "uuid": "f4a3d66a-04a8-3e80-6c9a-8a573ccb26fd9ed1d5c", "core": false, "unlocked_by": null, "difficulty": 8, @@ -1197,8 +1226,8 @@ ] }, { - "uuid": "8740af44-002c-4716-a759-a68ae4c68737", "slug": "isbn-verifier", + "uuid": "8740af44-002c-4716-a759-a68ae4c68737", "core": false, "unlocked_by": "bob", "difficulty": 4, @@ -1210,20 +1239,20 @@ ] }, { - "uuid": "b3dbc935-536e-4910-994d-4a519b511b6a", "slug": "forth", + "uuid": "b3dbc935-536e-4910-994d-4a519b511b6a", "core": false, "unlocked_by": "matrix", "difficulty": 8, "topics": [ - "stacks", + "domain_specific_languages", "parsing", - "domain_specific_languages" + "stacks" ] }, { - "uuid": "f82e470d-0bcc-4eba-b9b0-8a0c50a6fd19", "slug": "variable-length-quantity", + "uuid": "f82e470d-0bcc-4eba-b9b0-8a0c50a6fd19", "core": false, "unlocked_by": "grade-school", "difficulty": 5, @@ -1233,30 +1262,27 @@ ] }, { - "uuid": "cb09212c-f2ae-4acf-9177-6c7f42594c1d", "slug": "rectangles", + "uuid": "cb09212c-f2ae-4acf-9177-6c7f42594c1d", "core": false, "unlocked_by": "grade-school", "difficulty": 6, "topics": [ "parsing", - "searching", - "pattern_recognition" + "pattern_recognition", + "searching" ] }, { - "uuid": "0e4b628c-870d-446b-a400-3cc72457f2bc", "slug": "armstrong-numbers", + "uuid": "0e4b628c-870d-446b-a400-3cc72457f2bc", "core": false, "unlocked_by": null, "difficulty": 2, "topics": [ - "mathematics", - "algorithms" + "algorithms", + "mathematics" ] } - ], - "foregone": [], - "language": "JavaScript", - "test_pattern": ".*[.]spec[.]js$" + ] } diff --git a/config/maintainers.json b/config/maintainers.json index 59962c14..79432e03 100644 --- a/config/maintainers.json +++ b/config/maintainers.json @@ -2,84 +2,84 @@ "docs_url": "https://github.com/exercism/docs/blob/master/maintaining-a-track/maintainer-configuration.md", "maintainers": [ { - "alumnus": false, - "avatar_url": null, - "bio": null, "github_username": "ireddick", + "alumnus": false, + "show_on_website": false, + "name": null, "link_text": null, "link_url": null, - "name": null, - "show_on_website": false + "avatar_url": null, + "bio": null }, { - "alumnus": false, - "avatar_url": null, - "bio": "I'm a Web Developer with a passion for taking code that is hard to maintain and cleaning, refactoring, and bringing it back into a manageable state", "github_username": "rchavarria", + "alumnus": false, + "show_on_website": true, + "name": "Rubén Chavarría", "link_text": "Here is where I blog", "link_url": "https://rchavarria.github.io/", - "name": "Rubén Chavarría", - "show_on_website": true + "avatar_url": null, + "bio": "I'm a Web Developer with a passion for taking code that is hard to maintain and cleaning, refactoring, and bringing it back into a manageable state" }, { - "alumnus": false, - "avatar_url": null, - "bio": "Brazilian full-stack web developer. Mentor at Thinkful", "github_username": "joelwallis", + "alumnus": false, + "show_on_website": true, + "name": null, "link_text": null, "link_url": null, - "name": null, - "show_on_website": true + "avatar_url": null, + "bio": "Brazilian full-stack web developer. Mentor at Thinkful" }, { - "alumnus": false, - "avatar_url": null, - "bio": null, "github_username": "drueck", + "alumnus": false, + "show_on_website": false, + "name": null, "link_text": null, "link_url": null, - "name": null, - "show_on_website": false + "avatar_url": null, + "bio": null }, { - "alumnus": false, - "avatar_url": null, - "bio": null, "github_username": "tejasbubane", + "alumnus": false, + "show_on_website": false, + "name": null, "link_text": null, "link_url": null, - "name": null, - "show_on_website": false + "avatar_url": null, + "bio": null }, { - "alumnus": false, - "avatar_url": null, - "bio": null, "github_username": "matthewmorgan", + "alumnus": false, + "show_on_website": false, + "name": null, "link_text": null, "link_url": null, - "name": null, - "show_on_website": false + "avatar_url": null, + "bio": null }, { - "alumnus": false, - "avatar_url": null, - "bio": null, "github_username": "mixolidia", + "alumnus": false, + "show_on_website": false, + "name": null, "link_text": null, "link_url": null, - "name": null, - "show_on_website": false + "avatar_url": null, + "bio": null }, { - "alumnus": false, - "avatar_url": null, - "bio": null, "github_username": "ZacharyRSmith", + "alumnus": false, + "show_on_website": false, + "name": null, "link_text": null, "link_url": null, - "name": null, - "show_on_website": false + "avatar_url": null, + "bio": null } ] } From 9aedefeaa17120caae134aff4a95aebbea977559 Mon Sep 17 00:00:00 2001 From: MadEmperorYuri Date: Mon, 11 Jun 2018 02:38:15 -0500 Subject: [PATCH 32/39] =?UTF-8?q?Removed=20outdated=20mention=20of=20Eloqu?= =?UTF-8?q?ent=20JavaScript=E2=80=99s=20edition=20number=20(#550)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eloquent JavaScript came out with a 3rd edition some time ago. Previously, LEARNING.md mentioned its 2nd edition instead. Now it mentions no edition. The link is thus futureproofed. --- docs/LEARNING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/LEARNING.md b/docs/LEARNING.md index 0e0322cb..462c8cb2 100644 --- a/docs/LEARNING.md +++ b/docs/LEARNING.md @@ -1,4 +1,4 @@ -* [Eloquent JavaScript: A Modern Introduction to Programming (2nd Ed.)](http://eloquentjavascript.net) +* [Eloquent JavaScript: A Modern Introduction to Programming](http://eloquentjavascript.net) * [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) * [Crockford on JavaScript](http://javascript.crockford.com/) * [idiomatic.js: Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwaldron/idiomatic.js) From 1645af5ac21e80edffc3a5b04feff2c248a0a102 Mon Sep 17 00:00:00 2001 From: Aaditya Arvind Kulkarni Date: Tue, 12 Jun 2018 00:53:21 -0400 Subject: [PATCH 33/39] fix: pangram tests as per canonical data (#553) --- exercises/pangram/pangram.spec.js | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/exercises/pangram/pangram.spec.js b/exercises/pangram/pangram.spec.js index 74197329..b2bae495 100644 --- a/exercises/pangram/pangram.spec.js +++ b/exercises/pangram/pangram.spec.js @@ -1,23 +1,28 @@ var Pangram = require('./pangram'); describe('Pangram()', function () { - it('empty sentence', function () { + it('sentence empty', function () { var pangram = new Pangram(''); expect(pangram.isPangram()).toBe(false); }); + xit('recognizes a perfect lower case pangram', function () { + var pangram = new Pangram('abcdefghijklmnopqrstuvwxyz'); + expect(pangram.isPangram()).toBe(true); + }); + xit('pangram with only lower case', function () { var pangram = new Pangram('the quick brown fox jumps over the lazy dog'); expect(pangram.isPangram()).toBe(true); }); - xit("missing character 'x'", function () { + xit("missing character 'x'", function () { var pangram = new Pangram('a quick movement of the enemy will jeopardize five gunboats'); expect(pangram.isPangram()).toBe(false); }); - xit("another missing character 'x'", function () { - var pangram = new Pangram('the quick brown fish jumps over the lazy dog'); + xit("another missing character, e.g. 'h'", function () { + var pangram = new Pangram('five boxing wizards jump quickly at it'); expect(pangram.isPangram()).toBe(false); }); @@ -27,22 +32,22 @@ describe('Pangram()', function () { }); xit('pangram with numbers', function () { - var pangram = new Pangram('the 1 quick brown fox jumps over the 2 lazy dogs'); + var pangram = new Pangram('the 1 quick brown fox jumps over the 2 lazy dog'); expect(pangram.isPangram()).toBe(true); }); - xit('missing letters replaced by numbers', function () { + xit('missing letters replaced by numbers', function () { var pangram = new Pangram('7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog'); expect(pangram.isPangram()).toBe(false); }); xit('pangram with mixed case and punctuation', function () { - var pangram = new Pangram('"Five quacking Zephyrs jolt my wax bed."'); + var pangram = new Pangram('\"Five quacking Zephyrs jolt my wax bed.\"'); expect(pangram.isPangram()).toBe(true); }); - xit('pangram with non-ascii characters', function () { - var pangram = new Pangram('Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich.'); - expect(pangram.isPangram()).toBe(true); + xit('upper and lower case versions of the same character should not be counted separately', function () { + var pangram = new Pangram('the quick brown fox jumps over with lazy FX'); + expect(pangram.isPangram()).toBe(false); }); }); From 12cf744172d75b004e61884cc546df878ad1b1f0 Mon Sep 17 00:00:00 2001 From: Gavin Henderson Date: Thu, 14 Jun 2018 23:46:18 +0100 Subject: [PATCH 34/39] Added more tests to nth prime and improved example (#542) --- exercises/nth-prime/example.js | 6 +++++- exercises/nth-prime/nth-prime.spec.js | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/exercises/nth-prime/example.js b/exercises/nth-prime/example.js index faf7d05c..5deed40c 100644 --- a/exercises/nth-prime/example.js +++ b/exercises/nth-prime/example.js @@ -3,7 +3,11 @@ module.exports = { nth: function (nthPrime) { if (nthPrime === 0) { throw new Error('Prime is not possible'); } - this.generatePrimes(200000); + + // Using prime number theory to approximate the prime + // See https://en.wikipedia.org/wiki/Prime_number_theorem#Approximations_for_the_nth_prime_number + var upperBound = (nthPrime + 2) * Math.log((nthPrime + 2) * Math.log((nthPrime + 2))); + this.generatePrimes(upperBound); return this.realPrimes[nthPrime - 1]; }, generatePrimes: function (uptoNumber) { diff --git a/exercises/nth-prime/nth-prime.spec.js b/exercises/nth-prime/nth-prime.spec.js index 727ce507..70a326d8 100644 --- a/exercises/nth-prime/nth-prime.spec.js +++ b/exercises/nth-prime/nth-prime.spec.js @@ -17,6 +17,14 @@ describe('Prime', function () { expect(prime.nth(10001)).toEqual(104743); }); + xit('massive prime', function () { + expect(prime.nth(20000)).toEqual(224737); + }); + + xit('extreme prime', function () { + expect(prime.nth(30000)).toEqual(350377); + }); + xit('weird case', function () { expect( function () { prime.nth(0); From ae311aba2438c3ea6d28fb9b83fe300dca2b5dda Mon Sep 17 00:00:00 2001 From: Jack Hughes Date: Thu, 14 Jun 2018 23:53:17 +0100 Subject: [PATCH 35/39] Added blurb (#554) --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 4de97d0b..e909c240 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,7 @@ { "language": "JavaScript", "active": true, - "blurb": "", + "blurb": "JavaScript is a scripting language, primarily used for creating dynamic websites and programming web servers. It's a very popular language, and supports a variety of programming paradigms.", "test_pattern": ".*[.]spec[.]js$", "exercises": [ { From 050d9e6bfbf9987bfab9ce9818b435634da8ff60 Mon Sep 17 00:00:00 2001 From: Matthew Morgan Date: Sat, 23 Jun 2018 12:09:11 -0400 Subject: [PATCH 36/39] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 6001444c..503a5a02 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,12 @@ +# DEPRECATION NOTICE + +This track will be deprecated as part of the migration of Exercism to V2. Going forward, the EcmaScript track will replace the JavaScript track as "the new JavaScript" track. +- User's old submissions will be migrated +- PRs unrelated to the deprecation will be closed as `wontfix` +- Issues unrelated to deprecation will be closed as `wontfix` + +Thank you to all the many invested and hardworking contributors who have helped to make this track a success!! + # JavaScript [![Build Status](https://travis-ci.org/exercism/javascript.svg?branch=master)](https://travis-ci.org/exercism/javascript)[![Join the chat at https://gitter.im/exercism/xecmascript](https://badges.gitter.im/exercism/xecmascript.svg)](https://gitter.im/exercism/xecmascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Exercism exercises in JavaScript From b3d601e5d4bb8d849dc07297bed368c0c359b7fe Mon Sep 17 00:00:00 2001 From: Matthew Morgan Date: Mon, 16 Jul 2018 09:34:30 -0400 Subject: [PATCH 37/39] Update maintainers.json --- config/maintainers.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/maintainers.json b/config/maintainers.json index 79432e03..11e72347 100644 --- a/config/maintainers.json +++ b/config/maintainers.json @@ -54,12 +54,12 @@ { "github_username": "matthewmorgan", "alumnus": false, - "show_on_website": false, - "name": null, + "show_on_website": true, + "name": "Matt Morgan", "link_text": null, "link_url": null, "avatar_url": null, - "bio": null + "bio": "Learn, build, teach, repeat!" }, { "github_username": "mixolidia", From 618e65dd7626603b9f5651ef5fe321e26889e509 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Sun, 19 Aug 2018 15:31:57 -0600 Subject: [PATCH 38/39] Deprecate this track --- README.md | 36 +----------------------------------- config.json | 4 ++-- 2 files changed, 3 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 503a5a02..4f5bffa2 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,3 @@ # DEPRECATION NOTICE -This track will be deprecated as part of the migration of Exercism to V2. Going forward, the EcmaScript track will replace the JavaScript track as "the new JavaScript" track. -- User's old submissions will be migrated -- PRs unrelated to the deprecation will be closed as `wontfix` -- Issues unrelated to deprecation will be closed as `wontfix` - -Thank you to all the many invested and hardworking contributors who have helped to make this track a success!! - -# JavaScript [![Build Status](https://travis-ci.org/exercism/javascript.svg?branch=master)](https://travis-ci.org/exercism/javascript)[![Join the chat at https://gitter.im/exercism/xecmascript](https://badges.gitter.im/exercism/xecmascript.svg)](https://gitter.im/exercism/xecmascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -Exercism exercises in JavaScript - -## Installing - -To run the tests, you'll need NodeJS and Jasmine. For information about how to install these tools, see the [Javascript](http://exercism.io/languages/javascript/about) page. - -## Tasks - -The following commands assume that you are in the `javascript` directory: - -### Unit Tests: All Assignments - - make test - -### Unit Tests: Single Assignment - - make test-assignment ASSIGNMENT=wordy - -### Code Style - - npm run lint - -## Contributing Guide - -Please see the [contributing guide](https://github.com/exercism/x-api/blob/master/CONTRIBUTING.md#the-exercise-data) - +This track is deprecated. Please see the https://github.com/exercism/javascript track. diff --git a/config.json b/config.json index e909c240..e11dd1f6 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { - "language": "JavaScript", - "active": true, + "language": "JavaScript (Legacy)", + "active": false, "blurb": "JavaScript is a scripting language, primarily used for creating dynamic websites and programming web servers. It's a very popular language, and supports a variety of programming paradigms.", "test_pattern": ".*[.]spec[.]js$", "exercises": [ From 1a499fa80077bc9b4c718847e0b877d6b902ff1a Mon Sep 17 00:00:00 2001 From: Jeremy Walker Date: Wed, 15 Jan 2020 16:56:51 +0000 Subject: [PATCH 39/39] Clean up maintainers.json This file needs emptying. If anyone who is in it would like to be transferred as an alumni to exercism/javascript, please open a PR there, referencing this, and I'll merge it. --- config/maintainers.json | 80 ----------------------------------------- 1 file changed, 80 deletions(-) diff --git a/config/maintainers.json b/config/maintainers.json index 11e72347..48b19c6a 100644 --- a/config/maintainers.json +++ b/config/maintainers.json @@ -1,85 +1,5 @@ { "docs_url": "https://github.com/exercism/docs/blob/master/maintaining-a-track/maintainer-configuration.md", "maintainers": [ - { - "github_username": "ireddick", - "alumnus": false, - "show_on_website": false, - "name": null, - "link_text": null, - "link_url": null, - "avatar_url": null, - "bio": null - }, - { - "github_username": "rchavarria", - "alumnus": false, - "show_on_website": true, - "name": "Rubén Chavarría", - "link_text": "Here is where I blog", - "link_url": "https://rchavarria.github.io/", - "avatar_url": null, - "bio": "I'm a Web Developer with a passion for taking code that is hard to maintain and cleaning, refactoring, and bringing it back into a manageable state" - }, - { - "github_username": "joelwallis", - "alumnus": false, - "show_on_website": true, - "name": null, - "link_text": null, - "link_url": null, - "avatar_url": null, - "bio": "Brazilian full-stack web developer. Mentor at Thinkful" - }, - { - "github_username": "drueck", - "alumnus": false, - "show_on_website": false, - "name": null, - "link_text": null, - "link_url": null, - "avatar_url": null, - "bio": null - }, - { - "github_username": "tejasbubane", - "alumnus": false, - "show_on_website": false, - "name": null, - "link_text": null, - "link_url": null, - "avatar_url": null, - "bio": null - }, - { - "github_username": "matthewmorgan", - "alumnus": false, - "show_on_website": true, - "name": "Matt Morgan", - "link_text": null, - "link_url": null, - "avatar_url": null, - "bio": "Learn, build, teach, repeat!" - }, - { - "github_username": "mixolidia", - "alumnus": false, - "show_on_website": false, - "name": null, - "link_text": null, - "link_url": null, - "avatar_url": null, - "bio": null - }, - { - "github_username": "ZacharyRSmith", - "alumnus": false, - "show_on_website": false, - "name": null, - "link_text": null, - "link_url": null, - "avatar_url": null, - "bio": null - } ] }