From 16b810357322adc769d139dff619e1a38532a40b Mon Sep 17 00:00:00 2001 From: BethanyG Date: Thu, 4 Apr 2019 06:01:48 -0700 Subject: [PATCH 01/21] high-scores: OOP HINTS (#1708) OOP hints for High Scores. --- exercises/high-scores/.meta/HINTS.md | 5 +++ exercises/high-scores/README.md | 48 +++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 exercises/high-scores/.meta/HINTS.md diff --git a/exercises/high-scores/.meta/HINTS.md b/exercises/high-scores/.meta/HINTS.md new file mode 100644 index 00000000000..d1d5af1196e --- /dev/null +++ b/exercises/high-scores/.meta/HINTS.md @@ -0,0 +1,5 @@ +In this exercise you're going to create a **class** and use lists to organize scores. _Don't worry, it's not as complicated as you think!_ + +- [**A First Look at Classes**](https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes) from the Python 3 documentation. +- [**How to Define a Class in Python**](https://realpython.com/python3-object-oriented-programming/#how-to-define-a-class-in-python) from the Real Python website. +- [**Data Structures in Python**](https://docs.python.org/3/tutorial/datastructures.html) from the Python 3 documentation. diff --git a/exercises/high-scores/README.md b/exercises/high-scores/README.md index 802ad5ac1ee..6b08db6eb92 100644 --- a/exercises/high-scores/README.md +++ b/exercises/high-scores/README.md @@ -4,19 +4,59 @@ Manage a game player's High Score list. Your task is to build a high-score component of the classic Frogger game, one of the highest selling and addictive games of all time, and a classic of the arcade era. Your task is to write methods that return the highest score from the list, the last added score and the three highest scores. -## Submitting Exercises +In this exercise you're going to create a **class** and use lists to organize scores. _Don't worry, it's not as complicated as you think!_ + +- [**A First Look at Classes**](https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes) from the Python 3 documentation. +- [**How to Define a Class in Python**](https://realpython.com/python3-object-oriented-programming/#how-to-define-a-class-in-python) from the Real Python website. +- [**Data Structures in Python**](https://docs.python.org/3/tutorial/datastructures.html) from the Python 3 documentation. + + + +## Exception messages + +Sometimes it is necessary to raise an exception. When you do this, you should include a meaningful error message to +indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. Not +every exercise will require you to raise an exception, but for those that do, the tests will only pass if you include +a message. + +To raise a message with an exception, just write it as an argument to the exception type. For example, instead of +`raise Exception`, you should write: + +```python +raise Exception("Meaningful message indicating the source of the error") +``` + +## Running the tests -Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/` directory. +To run the tests, run the appropriate command below ([why they are different](https://github.com/pytest-dev/pytest/issues/1629#issue-161422224)): -For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit /python/bob/bob.py`. +- Python 2.7: `py.test high_scores_test.py` +- Python 3.4+: `pytest high_scores_test.py` +Alternatively, you can tell Python to run the pytest module (allowing the same command to be used regardless of Python version): +`python -m pytest high_scores_test.py` + +### Common `pytest` options + +- `-v` : enable verbose output +- `-x` : stop running tests on first failure +- `--ff` : run failures from previous test before running other test cases + +For other options, see `python -m pytest -h` + +## Submitting Exercises + +Note that, when trying to submit an exercise, make sure the solution is in the `$EXERCISM_WORKSPACE/python/high-scores` directory. + +You can find your Exercism workspace by running `exercism debug` and looking for the line that starts with `Workspace`. For more detailed information about running tests, code style and linting, -please see the [help page](http://exercism.io/languages/python). +please see [Running the Tests](http://exercism.io/tracks/python/tests). ## Source Tribute to the eighties' arcade game Frogger ## Submitting Incomplete Solutions + It's possible to submit an incomplete solution so you can see how others have completed the exercise. From f34e3287b6383cf691418493b5897b26bf76f5fc Mon Sep 17 00:00:00 2001 From: omer-g Date: Thu, 4 Apr 2019 21:03:56 +0300 Subject: [PATCH 02/21] knapsack: implement exercise (#1740) Resolves #1736 --- config.json | 12 ++++ exercises/knapsack/README.md | 87 +++++++++++++++++++++++++++++ exercises/knapsack/example.py | 11 ++++ exercises/knapsack/knapsack.py | 2 + exercises/knapsack/knapsack_test.py | 66 ++++++++++++++++++++++ 5 files changed, 178 insertions(+) create mode 100644 exercises/knapsack/README.md create mode 100644 exercises/knapsack/example.py create mode 100644 exercises/knapsack/knapsack.py create mode 100644 exercises/knapsack/knapsack_test.py diff --git a/config.json b/config.json index f80b140e3fd..67e26edfdb1 100644 --- a/config.json +++ b/config.json @@ -1564,6 +1564,18 @@ "topics": [ "arrays" ] + }, + { + "slug": "knapsack", + "uuid": "b0301d0b-d97a-4043-bd82-ba1edf8c1b16", + "core": false, + "unlocked_by": "clock", + "difficulty": 5, + "topics": [ + "algorithms", + "lists", + "loops" + ] } ] } diff --git a/exercises/knapsack/README.md b/exercises/knapsack/README.md new file mode 100644 index 00000000000..0a21d980a5c --- /dev/null +++ b/exercises/knapsack/README.md @@ -0,0 +1,87 @@ +# Knapsack + +In this exercise, let's try to solve a classic problem. + +Bob is a thief. After months of careful planning, he finally manages to +crack the security systems of a high-class apartment. + +In front of him are many items, each with a value (v) and weight (w). Bob, +of course, wants to maximize the total value he can get; he would gladly +take all of the items if he could. However, to his horror, he realizes that +the knapsack he carries with him can only hold so much weight (W). + +Given a knapsack with a specific carrying capacity (W), help Bob determine +the maximum value he can get from the items in the house. Note that Bob can +take only one of each item. + +All values given will be strictly positive. Items will be represented as a +list of pairs, `wi` and `vi`, where the first element `wi` is the weight of +the *i*th item and `vi` is the value for that item. + +For example: + +Items: [ + { "weight": 5, "value": 10 }, + { "weight": 4, "value": 40 }, + { "weight": 6, "value": 30 }, + { "weight": 4, "value": 50 } +] + +Knapsack Limit: 10 + +For the above, the first item has weight 5 and value 10, the second item has +weight 4 and value 40, and so on. + +In this example, Bob should take the second and fourth item to maximize his +value, which, in this case, is 90. He cannot get more than 90 as his +knapsack has a weight limit of 10. + + +## Exception messages + +Sometimes it is necessary to raise an exception. When you do this, you should include a meaningful error message to +indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. Not +every exercise will require you to raise an exception, but for those that do, the tests will only pass if you include +a message. + +To raise a message with an exception, just write it as an argument to the exception type. For example, instead of +`raise Exception`, you should write: + +```python +raise Exception("Meaningful message indicating the source of the error") +``` + +## Running the tests + +To run the tests, run the appropriate command below ([why they are different](https://github.com/pytest-dev/pytest/issues/1629#issue-161422224)): + +- Python 2.7: `py.test knapsack_test.py` +- Python 3.4+: `pytest knapsack_test.py` + +Alternatively, you can tell Python to run the pytest module (allowing the same command to be used regardless of Python version): +`python -m pytest knapsack_test.py` + +### Common `pytest` options + +- `-v` : enable verbose output +- `-x` : stop running tests on first failure +- `--ff` : run failures from previous test before running other test cases + +For other options, see `python -m pytest -h` + +## Submitting Exercises + +Note that, when trying to submit an exercise, make sure the solution is in the `$EXERCISM_WORKSPACE/python/knapsack` directory. + +You can find your Exercism workspace by running `exercism debug` and looking for the line that starts with `Workspace`. + +For more detailed information about running tests, code style and linting, +please see [Running the Tests](http://exercism.io/tracks/python/tests). + +## Source + +Wikipedia [https://en.wikipedia.org/wiki/Knapsack_problem](https://en.wikipedia.org/wiki/Knapsack_problem) + +## 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/knapsack/example.py b/exercises/knapsack/example.py new file mode 100644 index 00000000000..f19d066e951 --- /dev/null +++ b/exercises/knapsack/example.py @@ -0,0 +1,11 @@ +def solve_knapsack(max_weight, items): + t = [[0 for _ in range(len(items) + 1)] for _ in range(max_weight + 1)] + for weight in range(1, max_weight + 1): + for i, item in enumerate(items, 1): + if item["weight"] <= weight: + value = item["value"] + t[weight - item["weight"]][i - 1] + value_without_item = t[weight][i - 1] + t[weight][i] = max(value, value_without_item) + else: + t[weight][i] = t[weight][i - 1] + return t[max_weight][len(items)] diff --git a/exercises/knapsack/knapsack.py b/exercises/knapsack/knapsack.py new file mode 100644 index 00000000000..9458bb3c2af --- /dev/null +++ b/exercises/knapsack/knapsack.py @@ -0,0 +1,2 @@ +def solve_knapsack(max_weight, items): + pass diff --git a/exercises/knapsack/knapsack_test.py b/exercises/knapsack/knapsack_test.py new file mode 100644 index 00000000000..14be85f6ad6 --- /dev/null +++ b/exercises/knapsack/knapsack_test.py @@ -0,0 +1,66 @@ +import unittest + +from knapsack import solve_knapsack + + +# Tests adapted from `problem-specifications//canonical-data.json` @ v1.0.0 + +class ChangeTest(unittest.TestCase): + def test_no_items(self): + self.assertEqual(solve_knapsack(100, []), 0) + + def test_one_item_too_heavy(self): + self.assertEqual(solve_knapsack(10, [{"weight": 100, "value": 1}]), 0) + + def test_cannot_be_greedy_by_weight(self): + self.assertEqual(solve_knapsack(10, + [{"weight": 2, "value": 5}, + {"weight": 2, "value": 5}, + {"weight": 2, "value": 5}, + {"weight": 2, "value": 5}, + {"weight": 10, "value": 21}]), 21) + + def test_cannot_be_greedy_by_value(self): + self.assertEqual(solve_knapsack(10, [{"weight": 2, "value": 20}, + {"weight": 2, "value": 20}, + {"weight": 2, "value": 20}, + {"weight": 2, "value": 20}, + {"weight": 10, "value": 50}]), 80) + + def test_example_knapsack(self): + self.assertEqual(solve_knapsack(10, [{"weight": 5, "value": 10}, + {"weight": 4, "value": 40}, + {"weight": 6, "value": 30}, + {"weight": 4, "value": 50}]), 90) + + def test_eight_items(self): + self.assertEqual(solve_knapsack(104, [{"weight": 25, "value": 350}, + {"weight": 35, "value": 400}, + {"weight": 45, "value": 450}, + {"weight": 5, "value": 20}, + {"weight": 25, "value": 70}, + {"weight": 3, "value": 8}, + {"weight": 2, "value": 5}, + {"weight": 2, "value": 5}]), 900) + + def test_fifteen_items(self): + self.assertEqual(solve_knapsack(750, + [{"weight": 70, "value": 135}, + {"weight": 73, "value": 139}, + {"weight": 77, "value": 149}, + {"weight": 80, "value": 150}, + {"weight": 82, "value": 156}, + {"weight": 87, "value": 163}, + {"weight": 90, "value": 173}, + {"weight": 94, "value": 184}, + {"weight": 98, "value": 192}, + {"weight": 106, "value": 201}, + {"weight": 110, "value": 210}, + {"weight": 113, "value": 214}, + {"weight": 115, "value": 221}, + {"weight": 118, "value": 229}, + {"weight": 120, "value": 240}]), 1458) + + +if __name__ == "__main__": + unittest.main() From db120c5915e4137e1f875c002661473d3400577f Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Fri, 5 Apr 2019 08:35:12 -0400 Subject: [PATCH 03/21] resistor-colors: rename to resistor-color-duo RE: https://github.com/exercism/problem-specifications/issues/1495 --- config.json | 2 +- exercises/{resistor-colors => resistor-color-duo}/README.md | 0 exercises/{resistor-colors => resistor-color-duo}/example.py | 0 .../resistor_color_duo.py} | 0 .../resistor_color_duo_test.py} | 4 ++-- 5 files changed, 3 insertions(+), 3 deletions(-) rename exercises/{resistor-colors => resistor-color-duo}/README.md (100%) rename exercises/{resistor-colors => resistor-color-duo}/example.py (100%) rename exercises/{resistor-colors/resistor_colors.py => resistor-color-duo/resistor_color_duo.py} (100%) rename exercises/{resistor-colors/resistor_colors_test.py => resistor-color-duo/resistor_color_duo_test.py} (86%) diff --git a/config.json b/config.json index 67e26edfdb1..803c1835618 100644 --- a/config.json +++ b/config.json @@ -1556,7 +1556,7 @@ ] }, { - "slug": "resistor-colors", + "slug": "resistor-color-duo", "uuid": "089f06a6-0759-479c-8c00-d699525a1e22", "core": false, "unlocked_by": null, diff --git a/exercises/resistor-colors/README.md b/exercises/resistor-color-duo/README.md similarity index 100% rename from exercises/resistor-colors/README.md rename to exercises/resistor-color-duo/README.md diff --git a/exercises/resistor-colors/example.py b/exercises/resistor-color-duo/example.py similarity index 100% rename from exercises/resistor-colors/example.py rename to exercises/resistor-color-duo/example.py diff --git a/exercises/resistor-colors/resistor_colors.py b/exercises/resistor-color-duo/resistor_color_duo.py similarity index 100% rename from exercises/resistor-colors/resistor_colors.py rename to exercises/resistor-color-duo/resistor_color_duo.py diff --git a/exercises/resistor-colors/resistor_colors_test.py b/exercises/resistor-color-duo/resistor_color_duo_test.py similarity index 86% rename from exercises/resistor-colors/resistor_colors_test.py rename to exercises/resistor-color-duo/resistor_color_duo_test.py index f3681dad4c4..ad0867be08e 100644 --- a/exercises/resistor-colors/resistor_colors_test.py +++ b/exercises/resistor-color-duo/resistor_color_duo_test.py @@ -1,11 +1,11 @@ import unittest -from resistor_colors import value +from resistor_color_duo import value # Tests adapted from `problem-specifications//canonical-data.json` @ v1.0.0 -class ResistorColorsTest(unittest.TestCase): +class ResistorColorDuoTest(unittest.TestCase): def test_brown_and_black(self): self.assertEqual(value(['brown', 'black']), 10) From e034295d774d1c37e1b00354468f84a1ad3e42b0 Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Fri, 5 Apr 2019 08:43:06 -0400 Subject: [PATCH 04/21] resistor-color-duo: regenerate README to apply rename --- exercises/resistor-color-duo/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/exercises/resistor-color-duo/README.md b/exercises/resistor-color-duo/README.md index aa49ca44cb0..9ba682dc10b 100644 --- a/exercises/resistor-color-duo/README.md +++ b/exercises/resistor-color-duo/README.md @@ -1,4 +1,4 @@ -# Resistor Colors +# Resistor Color Duo If you want to build something using a Raspberry Pi, you'll probably use _resistors_. For this exercise, you need to know two things about them: @@ -40,11 +40,11 @@ raise Exception("Meaningful message indicating the source of the error") To run the tests, run the appropriate command below ([why they are different](https://github.com/pytest-dev/pytest/issues/1629#issue-161422224)): -- Python 2.7: `py.test resistor_colors_test.py` -- Python 3.4+: `pytest resistor_colors_test.py` +- Python 2.7: `py.test resistor_color_duo_test.py` +- Python 3.4+: `pytest resistor_color_duo_test.py` Alternatively, you can tell Python to run the pytest module (allowing the same command to be used regardless of Python version): -`python -m pytest resistor_colors_test.py` +`python -m pytest resistor_color_duo_test.py` ### Common `pytest` options @@ -56,7 +56,7 @@ For other options, see `python -m pytest -h` ## Submitting Exercises -Note that, when trying to submit an exercise, make sure the solution is in the `$EXERCISM_WORKSPACE/python/resistor-colors` directory. +Note that, when trying to submit an exercise, make sure the solution is in the `$EXERCISM_WORKSPACE/python/resistor-color-duo` directory. You can find your Exercism workspace by running `exercism debug` and looking for the line that starts with `Workspace`. From e7760a1bfae903060d35a396e9d9142f5441a9ae Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Fri, 5 Apr 2019 08:45:45 -0400 Subject: [PATCH 05/21] Move all active exercises before deprecated ones in config.json --- config.json | 64 ++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/config.json b/config.json index 803c1835618..8176083ed8a 100644 --- a/config.json +++ b/config.json @@ -1446,6 +1446,38 @@ "math" ] }, + { + "slug": "resistor-color", + "uuid": "d17bee9c-e803-4745-85ea-864f255fb04e", + "core": false, + "unlocked_by": null, + "difficulty": 1, + "topics": [ + "arrays" + ] + }, + { + "slug": "resistor-color-duo", + "uuid": "089f06a6-0759-479c-8c00-d699525a1e22", + "core": false, + "unlocked_by": null, + "difficulty": 1, + "topics": [ + "arrays" + ] + }, + { + "slug": "knapsack", + "uuid": "b0301d0b-d97a-4043-bd82-ba1edf8c1b16", + "core": false, + "unlocked_by": "clock", + "difficulty": 5, + "topics": [ + "algorithms", + "lists", + "loops" + ] + }, { "slug": "accumulate", "uuid": "e7351e8e-d3ff-4621-b818-cd55cf05bffd", @@ -1544,38 +1576,6 @@ "difficulty": 0, "topics": null, "deprecated": true - }, - { - "slug": "resistor-color", - "uuid": "d17bee9c-e803-4745-85ea-864f255fb04e", - "core": false, - "unlocked_by": null, - "difficulty": 1, - "topics": [ - "arrays" - ] - }, - { - "slug": "resistor-color-duo", - "uuid": "089f06a6-0759-479c-8c00-d699525a1e22", - "core": false, - "unlocked_by": null, - "difficulty": 1, - "topics": [ - "arrays" - ] - }, - { - "slug": "knapsack", - "uuid": "b0301d0b-d97a-4043-bd82-ba1edf8c1b16", - "core": false, - "unlocked_by": "clock", - "difficulty": 5, - "topics": [ - "algorithms", - "lists", - "loops" - ] } ] } From 86be10e3e626bf15f3d7bc3ea85a774759fae58a Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Mon, 15 Apr 2019 08:55:12 -0400 Subject: [PATCH 06/21] bracket-push: rename to matching-brackets RE: https://github.com/exercism/problem-specifications/pull/1501 --- config.json | 2 +- .../{bracket-push => matching-brackets}/README.md | 11 ++++++----- .../{bracket-push => matching-brackets}/example.py | 0 .../matching_brackets.py} | 0 .../matching_brackets_test.py} | 6 +++--- 5 files changed, 10 insertions(+), 9 deletions(-) rename exercises/{bracket-push => matching-brackets}/README.md (88%) rename exercises/{bracket-push => matching-brackets}/example.py (100%) rename exercises/{bracket-push/bracket_push.py => matching-brackets/matching_brackets.py} (100%) rename exercises/{bracket-push/bracket_push_test.py => matching-brackets/matching_brackets_test.py} (95%) diff --git a/config.json b/config.json index 8176083ed8a..36d3cfe5e1c 100644 --- a/config.json +++ b/config.json @@ -798,7 +798,7 @@ ] }, { - "slug": "bracket-push", + "slug": "matching-brackets", "uuid": "45229a7c-6703-4240-8287-16645881a043", "core": false, "unlocked_by": "isogram", diff --git a/exercises/bracket-push/README.md b/exercises/matching-brackets/README.md similarity index 88% rename from exercises/bracket-push/README.md rename to exercises/matching-brackets/README.md index 7ee2aa2e3ad..bbd62d63ee8 100644 --- a/exercises/bracket-push/README.md +++ b/exercises/matching-brackets/README.md @@ -1,9 +1,10 @@ -# Bracket Push +# Matching Brackets Given a string containing brackets `[]`, braces `{}`, parentheses `()`, or any combination thereof, verify that any and all pairs are matched and nested correctly. + ## Exception messages Sometimes it is necessary to raise an exception. When you do this, you should include a meaningful error message to @@ -22,11 +23,11 @@ raise Exception("Meaningful message indicating the source of the error") To run the tests, run the appropriate command below ([why they are different](https://github.com/pytest-dev/pytest/issues/1629#issue-161422224)): -- Python 2.7: `py.test bracket_push_test.py` -- Python 3.4+: `pytest bracket_push_test.py` +- Python 2.7: `py.test matching_brackets_test.py` +- Python 3.4+: `pytest matching_brackets_test.py` Alternatively, you can tell Python to run the pytest module (allowing the same command to be used regardless of Python version): -`python -m pytest bracket_push_test.py` +`python -m pytest matching_brackets_test.py` ### Common `pytest` options @@ -38,7 +39,7 @@ For other options, see `python -m pytest -h` ## Submitting Exercises -Note that, when trying to submit an exercise, make sure the solution is in the `$EXERCISM_WORKSPACE/python/bracket-push` directory. +Note that, when trying to submit an exercise, make sure the solution is in the `$EXERCISM_WORKSPACE/python/matching-brackets` directory. You can find your Exercism workspace by running `exercism debug` and looking for the line that starts with `Workspace`. diff --git a/exercises/bracket-push/example.py b/exercises/matching-brackets/example.py similarity index 100% rename from exercises/bracket-push/example.py rename to exercises/matching-brackets/example.py diff --git a/exercises/bracket-push/bracket_push.py b/exercises/matching-brackets/matching_brackets.py similarity index 100% rename from exercises/bracket-push/bracket_push.py rename to exercises/matching-brackets/matching_brackets.py diff --git a/exercises/bracket-push/bracket_push_test.py b/exercises/matching-brackets/matching_brackets_test.py similarity index 95% rename from exercises/bracket-push/bracket_push_test.py rename to exercises/matching-brackets/matching_brackets_test.py index 9dfd06489bf..3ed117f18de 100644 --- a/exercises/bracket-push/bracket_push_test.py +++ b/exercises/matching-brackets/matching_brackets_test.py @@ -1,11 +1,11 @@ import unittest -from bracket_push import is_paired +from matching_brackets import is_paired -# Tests adapted from `problem-specifications//canonical-data.json` @ v1.5.0 +# Tests adapted from `problem-specifications//canonical-data.json` @ v2.0.0 -class BracketPushTest(unittest.TestCase): +class MatchingBracketsTest(unittest.TestCase): def test_paired_square_brackets(self): self.assertEqual(is_paired("[]"), True) From ccee45e83b8556454ffd058d0727d10821dfef30 Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Mon, 15 Apr 2019 09:14:07 -0400 Subject: [PATCH 07/21] check-test-version.py: handle missing canonical data --- bin/check-test-version.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/check-test-version.py b/bin/check-test-version.py index 723bca0ba2c..6105a3e2653 100755 --- a/bin/check-test-version.py +++ b/bin/check-test-version.py @@ -323,5 +323,9 @@ def check_test_version( if opts.ignore and exercise in opts.ignore: continue if os.path.isdir(os.path.join('exercises', exercise)): - result = check_test_version(exercise, **kwargs) and result + try: + result = check_test_version(exercise, **kwargs) and result + except FileNotFoundError as e: + print(str(e)) + result = False sys.exit(0 if result else 1) From 222c02976c2c0e75d03440893f543c760ca39ba9 Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Mon, 15 Apr 2019 10:02:40 -0400 Subject: [PATCH 08/21] sgf-parsing: regenerate README (#1761) --- exercises/sgf-parsing/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/exercises/sgf-parsing/README.md b/exercises/sgf-parsing/README.md index 597520c4cf7..6db23421ff7 100644 --- a/exercises/sgf-parsing/README.md +++ b/exercises/sgf-parsing/README.md @@ -18,9 +18,10 @@ An SGF file may look like this: This is a tree with three nodes: -- The top level node has two properties: FF\[4\] (key = "FF", value = - "4") and C\[root\](key = "C", value = "root"). (FF indicates the - version of SGF and C is a comment.) +- The top level node has three properties: FF\[4\] (key = "FF", value + = "4"), C\[root\](key = "C", value = "root") and SZ\[19\] (key = + "SZ", value = "19"). (FF indicates the version of SGF, C is a + comment and SZ is the size of the board.) - The top level node has a single child which has a single property: B\[aa\]. (Black plays on the point encoded as "aa", which is the 1-1 point (which is a stupid place to play)). @@ -64,6 +65,7 @@ structure of properties. You do not need to encode knowledge about the data types of properties, just use the rules for the [text](http://www.red-bean.com/sgf/sgf4.html#text) type everywhere. + ## Exception messages Sometimes it is necessary to raise an exception. When you do this, you should include a meaningful error message to From 0aa3391d216cf7d2a56f76fccbf73ca655c2782c Mon Sep 17 00:00:00 2001 From: Nathan Parsons Date: Sat, 20 Apr 2019 22:38:57 +0100 Subject: [PATCH 09/21] Remove N-Parsons from maintainers list --- config/maintainers.json | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/config/maintainers.json b/config/maintainers.json index 01188382e82..a1296a7ba44 100644 --- a/config/maintainers.json +++ b/config/maintainers.json @@ -20,16 +20,6 @@ "link_url": null, "avatar_url": null }, - { - "github_username": "N-Parsons", - "show_on_website": true, - "alumnus": false, - "name": "Nathan Parsons", - "bio": "Python fits with how I think and allows me to quickly write powerful, maintainable, and extensible code.", - "link_text": null, - "link_url": null, - "avatar_url": null - }, { "github_username": "m-a-ge", "show_on_website": false, From 839636c0ab9c5eb5792c5220c733d7286e66752e Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Wed, 24 Apr 2019 16:37:22 -0600 Subject: [PATCH 10/21] Update copyright in license (#1765) This ensures that the year is up to date, and that the copyright is assigned to the not-for-profit Exercism, rather than the (now-defunct) Delaware Corporation that we had in place as a temporary measure for legal protection until we could figure out how to structure things properly. --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index eee993a55dc..a7527f968fb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 Exercism, Inc +Copyright (c) 2019 Exercism Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From f5d312df8dfba5a0b36cfd170973204a49003a14 Mon Sep 17 00:00:00 2001 From: Pavlin Angelov Date: Thu, 25 Apr 2019 19:10:07 +0300 Subject: [PATCH 11/21] Add class HINTS to Matrix. (#1766) Previously it was included in High-Scores. Now this is the first execrsise that contain classes. --- exercises/matrix/.meta/HINTS.md | 5 +++++ exercises/matrix/README.md | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 exercises/matrix/.meta/HINTS.md diff --git a/exercises/matrix/.meta/HINTS.md b/exercises/matrix/.meta/HINTS.md new file mode 100644 index 00000000000..fe997c63097 --- /dev/null +++ b/exercises/matrix/.meta/HINTS.md @@ -0,0 +1,5 @@ +In this exercise you're going to create a **class**. _Don't worry, it's not as complicated as you think!_ + +- [**A First Look at Classes**](https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes) from the Python 3 documentation. +- [**How to Define a Class in Python**](https://realpython.com/python3-object-oriented-programming/#how-to-define-a-class-in-python) from the Real Python website. +- [**Data Structures in Python**](https://docs.python.org/3/tutorial/datastructures.html) from the Python 3 documentation. diff --git a/exercises/matrix/README.md b/exercises/matrix/README.md index 2165e6fe802..285e5b9d515 100644 --- a/exercises/matrix/README.md +++ b/exercises/matrix/README.md @@ -40,6 +40,14 @@ And its columns: - 8, 3, 6 - 7, 2, 7 +In this exercise you're going to create a **class**. _Don't worry, it's not as complicated as you think!_ + +- [**A First Look at Classes**](https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes) from the Python 3 documentation. +- [**How to Define a Class in Python**](https://realpython.com/python3-object-oriented-programming/#how-to-define-a-class-in-python) from the Real Python website. +- [**Data Structures in Python**](https://docs.python.org/3/tutorial/datastructures.html) from the Python 3 documentation. + + + ## Exception messages Sometimes it is necessary to raise an exception. When you do this, you should include a meaningful error message to From 4a85fe051c067f7c2e63adc49bd7ed62d932a79e Mon Sep 17 00:00:00 2001 From: Xitang Date: Mon, 29 Apr 2019 15:03:20 -0400 Subject: [PATCH 12/21] luhn: update tests to v1.5.0 (#1767) --- exercises/luhn/luhn_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/exercises/luhn/luhn_test.py b/exercises/luhn/luhn_test.py index c82e08b9842..7457a5a4a33 100644 --- a/exercises/luhn/luhn_test.py +++ b/exercises/luhn/luhn_test.py @@ -5,7 +5,7 @@ from luhn import Luhn -# Tests adapted from `problem-specifications//canonical-data.json` @ v1.4.0 +# Tests adapted from `problem-specifications//canonical-data.json` @ v1.5.0 class LuhnTest(unittest.TestCase): def test_single_digit_strings_can_not_be_valid(self): @@ -32,9 +32,6 @@ def test_invalid_credit_card(self): def test_valid_number_with_an_even_number_of_digits(self): self.assertIs(Luhn("095 245 88").is_valid(), True) - def test_valid_strings_with_a_non_digit_included_become_invalid(self): - self.assertIs(Luhn("055a 444 285").is_valid(), False) - def test_valid_strings_with_non_digit_added_at_end_become_invalid(self): self.assertIs(Luhn("059a").is_valid(), False) @@ -53,7 +50,10 @@ def test_more_than_a_single_zero_is_valid(self): def test_input_digit_9_is_correctly_converted_to_output_digit_9(self): self.assertIs(Luhn("091").is_valid(), True) - def test_strings_with_non_digits_is_invalid(self): + def test_using_ascii_value_for_non_doubled_non_digit_isnot_allowed(self): + self.assertIs(Luhn("055b 444 285").is_valid(), False) + + def test_using_ascii_value_for_doubled_non_digit_isnot_allowed(self): self.assertIs(Luhn(":9").is_valid(), False) def test_is_valid_can_be_called_repeatedly(self): From 534ceae3b41ba9c11c1f2fa79c1f6664a7208ba2 Mon Sep 17 00:00:00 2001 From: Xitang Date: Mon, 29 Apr 2019 15:38:05 -0400 Subject: [PATCH 13/21] triangle: update tests to v1.2.1 (#1757) (#1769) --- exercises/triangle/triangle_test.py | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/exercises/triangle/triangle_test.py b/exercises/triangle/triangle_test.py index 88f97e53fb0..1a61dd1dd4e 100644 --- a/exercises/triangle/triangle_test.py +++ b/exercises/triangle/triangle_test.py @@ -3,19 +3,19 @@ from triangle import is_equilateral, is_isosceles, is_scalene -# Tests adapted from `problem-specifications//canonical-data.json` @ v1.2.0 +# Tests adapted from `problem-specifications//canonical-data.json` @ v1.2.1 class is_equilateralTests(unittest.TestCase): - def test_true_if_all_sides_are_equal(self): + def test_all_sides_are_equal(self): self.assertIs(is_equilateral([2, 2, 2]), True) - def test_false_if_any_side_is_unequal(self): + def test_any_side_is_unequal(self): self.assertIs(is_equilateral([2, 3, 2]), False) - def test_false_if_no_sides_are_equal(self): + def test_no_sides_are_equal(self): self.assertIs(is_equilateral([5, 4, 6]), False) - def test_false_if_all_sides_are_zero(self): + def test_all_zero_sides_is_not_a_triangle(self): self.assertIs(is_equilateral([0, 0, 0]), False) def test_sides_may_be_floats(self): @@ -23,28 +23,28 @@ def test_sides_may_be_floats(self): class is_isoscelesTests(unittest.TestCase): - def test_true_if_last_two_sides_are_equal(self): + def test_last_two_sides_are_equal(self): self.assertIs(is_isosceles([3, 4, 4]), True) - def test_true_if_first_two_sides_are_equal(self): + def test_first_two_sides_are_equal(self): self.assertIs(is_isosceles([4, 4, 3]), True) - def test_true_if_first_and_last_sides_are_equal(self): + def test_first_and_last_sides_are_equal(self): self.assertIs(is_isosceles([4, 3, 4]), True) - def test_is_equilateral_triangles_are_also_is_isosceles(self): + def test_equilateral_triangles_are_also_isosceles(self): self.assertIs(is_isosceles([4, 4, 4]), True) - def test_false_if_no_sides_are_equal(self): + def test_no_sides_are_equal(self): self.assertIs(is_isosceles([2, 3, 4]), False) - def test_violation_of_triangle_inequality_is_not_isosceles_1(self): + def test_first_triangle_inequality_violation(self): self.assertIs(is_isosceles([1, 1, 3]), False) - def test_violation_of_triangle_inequality_is_not_isosceles_2(self): + def test_second_triangle_inequality_violation(self): self.assertIs(is_isosceles([1, 3, 1]), False) - def test_violation_of_triangle_inequality_is_not_isosceles_3(self): + def test_third_triangle_inequality_violation(self): self.assertIs(is_isosceles([3, 1, 1]), False) def test_sides_may_be_floats(self): @@ -52,16 +52,16 @@ def test_sides_may_be_floats(self): class is_scaleneTests(unittest.TestCase): - def test_true_if_no_sides_are_equal(self): + def test_no_sides_are_equal(self): self.assertIs(is_scalene([5, 4, 6]), True) - def test_false_if_all_sides_are_equal(self): + def test_all_sides_are_equal(self): self.assertIs(is_scalene([4, 4, 4]), False) - def test_false_if_two_sides_are_equal(self): + def test_two_sides_are_equal(self): self.assertIs(is_scalene([4, 4, 3]), False) - def test_violation_of_triangle_inequality_not_is_scalene(self): + def test_may_not_violate_triangle_inequality(self): self.assertIs(is_scalene([7, 3, 2]), False) def test_sides_may_be_floats(self): From 93ceb8f962fe64d15e824e79009f74617a24f5a5 Mon Sep 17 00:00:00 2001 From: Milan Suk Date: Wed, 1 May 2019 20:42:49 +0200 Subject: [PATCH 14/21] alphametics: sync with problem-specifications (#1768) --- exercises/alphametics/alphametics_test.py | 4 ++-- exercises/alphametics/example.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/exercises/alphametics/alphametics_test.py b/exercises/alphametics/alphametics_test.py index daa47cbd8bc..01f7d9130a6 100644 --- a/exercises/alphametics/alphametics_test.py +++ b/exercises/alphametics/alphametics_test.py @@ -10,10 +10,10 @@ def test_puzzle_with_three_letters(self): self.assertEqual(solve("I + BB == ILL"), {"I": 1, "B": 9, "L": 0}) def test_solution_must_have_unique_value_for_each_letter(self): - self.assertEqual(solve("A == B"), {}) + self.assertEqual(solve("A == B"), None) def test_leading_zero_solution_is_invalid(self): - self.assertEqual(solve("ACA + DD == BD"), {}) + self.assertEqual(solve("ACA + DD == BD"), None) def test_puzzle_with_two_digits_final_carry(self): self.assertEqual( diff --git a/exercises/alphametics/example.py b/exercises/alphametics/example.py index 7543bebabb3..6a7a869961b 100644 --- a/exercises/alphametics/example.py +++ b/exercises/alphametics/example.py @@ -108,11 +108,11 @@ def check_rec(eqparams, tracecombo=(dict(), 0, set(range(10))), p=0): # if the recursive call returned a non-empty dictionary # this means the recursion has found a solution # otherwise, proceed to the new permutation - if len(rectest) > 0: + if rectest and len(rectest) > 0: return rectest # if no permutations are avaialble or no - # permutation gave the result return the empty dictionary - return dict() + # permutation gave the result return None + return None def solve(an): From 3d66f2bd1a860888d66303fe987e8bd2a92fdef1 Mon Sep 17 00:00:00 2001 From: Milan Suk Date: Thu, 2 May 2019 15:03:11 +0200 Subject: [PATCH 15/21] armstrong-numbers: sync with problem-specifications (#1771) --- .../armstrong-numbers/armstrong_numbers.py | 2 +- .../armstrong_numbers_test.py | 23 +++++++++++-------- exercises/armstrong-numbers/example.py | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/exercises/armstrong-numbers/armstrong_numbers.py b/exercises/armstrong-numbers/armstrong_numbers.py index d046e348db3..b8829fac575 100644 --- a/exercises/armstrong-numbers/armstrong_numbers.py +++ b/exercises/armstrong-numbers/armstrong_numbers.py @@ -1,2 +1,2 @@ -def is_armstrong(number): +def is_armstrong_number(number): pass diff --git a/exercises/armstrong-numbers/armstrong_numbers_test.py b/exercises/armstrong-numbers/armstrong_numbers_test.py index ec52be9a76d..46b7fc5dd01 100644 --- a/exercises/armstrong-numbers/armstrong_numbers_test.py +++ b/exercises/armstrong-numbers/armstrong_numbers_test.py @@ -1,35 +1,38 @@ import unittest -from armstrong_numbers import is_armstrong +from armstrong_numbers import is_armstrong_number -# Tests adapted from `problem-specifications//canonical-data.json` @ v1.0.0 +# Tests adapted from `problem-specifications//canonical-data.json` @ v1.1.0 class ArmstrongNumbersTest(unittest.TestCase): + def test_zero_is_an_armstrong_number(self): + self.assertIs(is_armstrong_number(0), True) + def test_single_digit_numbers_are_armstrong_numbers(self): - self.assertIs(is_armstrong(5), True) + self.assertIs(is_armstrong_number(5), True) def test_there_are_no_two_digit_armstrong_numbers(self): - self.assertIs(is_armstrong(10), False) + self.assertIs(is_armstrong_number(10), False) def test_three_digit_number_that_is_an_armstrong_number(self): - self.assertIs(is_armstrong(153), True) + self.assertIs(is_armstrong_number(153), True) def test_three_digit_number_that_is_not_an_armstrong_number(self): - self.assertIs(is_armstrong(100), False) + self.assertIs(is_armstrong_number(100), False) def test_four_digit_number_that_is_an_armstrong_number(self): - self.assertIs(is_armstrong(9474), True) + self.assertIs(is_armstrong_number(9474), True) def test_four_digit_number_that_is_not_an_armstrong_number(self): - self.assertIs(is_armstrong(9475), False) + self.assertIs(is_armstrong_number(9475), False) def test_seven_digit_number_that_is_an_armstrong_number(self): - self.assertIs(is_armstrong(9926315), True) + self.assertIs(is_armstrong_number(9926315), True) def test_seven_digit_number_that_is_not_an_armstrong_number(self): - self.assertIs(is_armstrong(9926314), False) + self.assertIs(is_armstrong_number(9926314), False) if __name__ == '__main__': diff --git a/exercises/armstrong-numbers/example.py b/exercises/armstrong-numbers/example.py index 4dc0a3eef6e..9bc1a3a5918 100644 --- a/exercises/armstrong-numbers/example.py +++ b/exercises/armstrong-numbers/example.py @@ -1,2 +1,2 @@ -def is_armstrong(number): +def is_armstrong_number(number): return sum(pow(int(d), len(str(number))) for d in str(number)) == number From f1e36035f5452f21eb885e76de441150829df665 Mon Sep 17 00:00:00 2001 From: Xitang Date: Fri, 3 May 2019 14:21:25 -0400 Subject: [PATCH 16/21] queen-attack: update tests to v2.3.0 (#1775) --- exercises/queen-attack/queen_attack_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/queen-attack/queen_attack_test.py b/exercises/queen-attack/queen_attack_test.py index f4212093b11..11868b35d89 100644 --- a/exercises/queen-attack/queen_attack_test.py +++ b/exercises/queen-attack/queen_attack_test.py @@ -3,7 +3,7 @@ from queen_attack import Queen -# Tests adapted from `problem-specifications//canonical-data.json` @ v2.2.0 +# Tests adapted from `problem-specifications//canonical-data.json` @ v2.3.0 class QueenAttackTest(unittest.TestCase): @@ -50,7 +50,7 @@ def test_attack_diagonal3(self): self.assertIs(Queen(2, 2).can_attack(Queen(1, 1)), True) def test_attack_diagonal4(self): - self.assertIs(Queen(2, 2).can_attack(Queen(5, 5)), True) + self.assertIs(Queen(1, 7).can_attack(Queen(0, 6)), True) # Track-specific tests def test_queens_same_position_can_attack(self): From 839e3fe2581ee5c7df2f1978931db9137fe2f68c Mon Sep 17 00:00:00 2001 From: Xitang Date: Fri, 3 May 2019 14:26:38 -0400 Subject: [PATCH 17/21] resistor-color-duo: update tests to v2.0.0 (#1773) --- exercises/resistor-color-duo/resistor_color_duo_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/resistor-color-duo/resistor_color_duo_test.py b/exercises/resistor-color-duo/resistor_color_duo_test.py index ad0867be08e..6c9384407bb 100644 --- a/exercises/resistor-color-duo/resistor_color_duo_test.py +++ b/exercises/resistor-color-duo/resistor_color_duo_test.py @@ -3,7 +3,7 @@ from resistor_color_duo import value -# Tests adapted from `problem-specifications//canonical-data.json` @ v1.0.0 +# Tests adapted from `problem-specifications//canonical-data.json` @ v2.0.0 class ResistorColorDuoTest(unittest.TestCase): def test_brown_and_black(self): From 89bb17a15563b1bfb47e6f7659c5c82d8d20021f Mon Sep 17 00:00:00 2001 From: Pavlin Angelov Date: Fri, 3 May 2019 21:30:18 +0300 Subject: [PATCH 18/21] Simplify High-scores exercise. Replace Class with functions (#1764) * Simplify High-scores exercise. Replace Class with functions Exercise text edited. Tests made to expect functions. One test removed, cause was no longer valid. Make new example.py using functions. Add the functions as starting point in the exercise file. (This also make the tests not complain of missing imports and such.) Added __init__.py to the package for the people that still run 2.7+ Added pytest cache to gitignore file * Fix style problems * Made requested changes in PR Remove __init__.py Remove content of HINTS.md Generate the README.md Remove the comments in stub file * Add new hints to high-score Added hints for some docs around list and tuples - thanks @BethanyG for that Moved original hints for classes in matrix ( cause is the next exercise for now which use class) slightly edited to not refer to high-score Regenerate both README.md * Remove changes to matrix from this PR * Update exercises/high-scores/.meta/HINTS.md Co-Authored-By: simmol * Update exercises/matrix/README.md Co-Authored-By: simmol * Regenerate README --- .gitignore | 1 + exercises/high-scores/.meta/HINTS.md | 8 ++++---- exercises/high-scores/README.md | 8 ++++---- exercises/high-scores/example.py | 16 +++++++--------- exercises/high-scores/high_scores.py | 13 ++++++++++--- exercises/high-scores/high_scores_test.py | 20 ++++++++------------ 6 files changed, 34 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index edce8452bfc..6f97f3570a0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ bin/configlet bin/configlet.exe .idea/ .cache +.pytest_cache __pycache__ diff --git a/exercises/high-scores/.meta/HINTS.md b/exercises/high-scores/.meta/HINTS.md index d1d5af1196e..b1de85b1839 100644 --- a/exercises/high-scores/.meta/HINTS.md +++ b/exercises/high-scores/.meta/HINTS.md @@ -1,5 +1,5 @@ -In this exercise you're going to create a **class** and use lists to organize scores. _Don't worry, it's not as complicated as you think!_ +In this exercise, you're going to use and manipulate lists. Python lists are very versatile, and you'll find yourself using them again and again in problems both simple and complex. -- [**A First Look at Classes**](https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes) from the Python 3 documentation. -- [**How to Define a Class in Python**](https://realpython.com/python3-object-oriented-programming/#how-to-define-a-class-in-python) from the Real Python website. -- [**Data Structures in Python**](https://docs.python.org/3/tutorial/datastructures.html) from the Python 3 documentation. +- [**Data Structures (Python 3 Documentation Tutorial)**](https://docs.python.org/3/tutorial/datastructures.html) +- [**Lists and Tuples in Python (Real Python)**](https://realpython.com/python-lists-tuples/) +- [**Python Lists (Google for Education)**](https://developers.google.com/edu/python/lists) diff --git a/exercises/high-scores/README.md b/exercises/high-scores/README.md index 6b08db6eb92..fa7934d4d37 100644 --- a/exercises/high-scores/README.md +++ b/exercises/high-scores/README.md @@ -4,11 +4,11 @@ Manage a game player's High Score list. Your task is to build a high-score component of the classic Frogger game, one of the highest selling and addictive games of all time, and a classic of the arcade era. Your task is to write methods that return the highest score from the list, the last added score and the three highest scores. -In this exercise you're going to create a **class** and use lists to organize scores. _Don't worry, it's not as complicated as you think!_ +In this exercise, you're going to use and manipulate lists. Python lists are very versatile, and you'll find yourself using them again and again in problems both simple and complex. -- [**A First Look at Classes**](https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes) from the Python 3 documentation. -- [**How to Define a Class in Python**](https://realpython.com/python3-object-oriented-programming/#how-to-define-a-class-in-python) from the Real Python website. -- [**Data Structures in Python**](https://docs.python.org/3/tutorial/datastructures.html) from the Python 3 documentation. +- [**Data Structures (Python 3 Documentation Tutorial)**](https://docs.python.org/3/tutorial/datastructures.html) +- [**Lists and Tuples in Python (Real Python)**](https://realpython.com/python-lists-tuples/) +- [**Python Lists (Google for Education)**](https://developers.google.com/edu/python/lists) diff --git a/exercises/high-scores/example.py b/exercises/high-scores/example.py index 0c77d73af86..fd168ffc526 100644 --- a/exercises/high-scores/example.py +++ b/exercises/high-scores/example.py @@ -1,12 +1,10 @@ -class HighScores(object): - def __init__(self, scores): - self.scores = scores +def latest(scores): + return scores[-1] - def latest(self): - return self.scores[-1] - def personal_best(self): - return max(self.scores) +def personal_best(scores): + return max(scores) - def personal_top_three(self): - return sorted(self.scores, reverse=True)[:3] + +def personal_top_three(scores): + return sorted(scores, reverse=True)[:3] diff --git a/exercises/high-scores/high_scores.py b/exercises/high-scores/high_scores.py index 3bfba4d0b57..0d24cdb1c1d 100644 --- a/exercises/high-scores/high_scores.py +++ b/exercises/high-scores/high_scores.py @@ -1,3 +1,10 @@ -class HighScores(object): - def __init__(self, scores): - pass +def latest(scores): + pass + + +def personal_best(scores): + pass + + +def personal_top_three(scores): + pass diff --git a/exercises/high-scores/high_scores_test.py b/exercises/high-scores/high_scores_test.py index 17d69c0e15d..40bd76c5ed1 100644 --- a/exercises/high-scores/high_scores_test.py +++ b/exercises/high-scores/high_scores_test.py @@ -1,51 +1,47 @@ import unittest -from high_scores import HighScores +from high_scores import latest, personal_best, personal_top_three # Tests adapted from `problem-specifications//canonical-data.json` @ v4.0.0 class HighScoreTest(unittest.TestCase): - def test_list_of_scores(self): - scores = [30, 50, 20, 70] - expected = [30, 50, 20, 70] - self.assertEqual(HighScores(scores).scores, expected) def test_latest_score(self): scores = [100, 0, 90, 30] expected = 30 - self.assertEqual(HighScores(scores).latest(), expected) + self.assertEqual(latest(scores), expected) def test_personal_best(self): scores = [40, 100, 70] expected = 100 - self.assertEqual(HighScores(scores).personal_best(), expected) + self.assertEqual(personal_best(scores), expected) def test_personal_top_three_from_a_long_list(self): scores = [10, 30, 90, 30, 100, 20, 10, 0, 30, 40, 40, 70, 70] expected = [100, 90, 70] - self.assertEqual(HighScores(scores).personal_top_three(), expected) + self.assertEqual(personal_top_three(scores), expected) def test_personal_top_three_highest_to_lowest(self): scores = [20, 10, 30] expected = [30, 20, 10] - self.assertEqual(HighScores(scores).personal_top_three(), expected) + self.assertEqual(personal_top_three(scores), expected) def test_personal_top_three_when_there_is_a_tie(self): scores = [40, 20, 40, 30] expected = [40, 40, 30] - self.assertEqual(HighScores(scores).personal_top_three(), expected) + self.assertEqual(personal_top_three(scores), expected) def test_personal_top_three_when_there_are_less_than_3(self): scores = [30, 70] expected = [70, 30] - self.assertEqual(HighScores(scores).personal_top_three(), expected) + self.assertEqual(personal_top_three(scores), expected) def test_personal_top_three_when_there_is_only_one(self): scores = [40] expected = [40] - self.assertEqual(HighScores(scores).personal_top_three(), expected) + self.assertEqual(personal_top_three(scores), expected) if __name__ == "__main__": From 09920ddd89436a861acfb6396829bc7eee6030e1 Mon Sep 17 00:00:00 2001 From: Xitang Date: Mon, 6 May 2019 08:36:08 -0400 Subject: [PATCH 19/21] darts: update tests to v2.0.0 (#1774) --- exercises/darts/darts_test.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/exercises/darts/darts_test.py b/exercises/darts/darts_test.py index 1b359709095..40882f15dbe 100644 --- a/exercises/darts/darts_test.py +++ b/exercises/darts/darts_test.py @@ -2,7 +2,7 @@ from darts import score -# Tests adapted from `problem-specifications//canonical-data.json` @ v1.1.0 +# Tests adapted from `problem-specifications//canonical-data.json` @ v2.0.0 class darts_test(unittest.TestCase): def test_dart_lands_outside_target(self): @@ -26,6 +26,15 @@ def test_dart_lands_border_betweeen_middle_inner(self): def test_dart_lands_inner_circle(self): self.assertEqual(score(-0.1, -0.1), 10) + def test_dart_coord_sum_more_than_1_radius_less_than_1_is_in_inner(self): + self.assertEqual(score(0.4, 0.8), 10) + + def test_dart_coord_sum_more_than_5_radius_less_than_5_is_in_middle(self): + self.assertEqual(score(2, 4), 5) + + def test_dart_coord_sum_more_than_10_radius_less_than_10_is_in_outer(self): + self.assertEqual(score(4, 8), 1) + if __name__ == '__main__': unittest.main() From 8a23959ca70f0da27743cfec9167b2c374ff0d95 Mon Sep 17 00:00:00 2001 From: spencer51324312 Date: Wed, 8 May 2019 11:04:17 -0400 Subject: [PATCH 20/21] Changed tournament_tests files (#1776) * update tournament tests Made it so it is more like the problem-specifications --- exercises/tournament/example.py | 5 +- exercises/tournament/tournament_test.py | 136 ++++++++++++------------ 2 files changed, 70 insertions(+), 71 deletions(-) diff --git a/exercises/tournament/example.py b/exercises/tournament/example.py index e7b62874cd9..88494049440 100644 --- a/exercises/tournament/example.py +++ b/exercises/tournament/example.py @@ -31,14 +31,13 @@ def format_table(results): team_fmt = '{0:30} | {1:2} | {3:2} | {4:2} | {5:2} | {2:2}' table.append( team_fmt.format(team, sum(games), calculate_points(games), *games)) - - return '\n'.join(table) + return table def tally(data): table = defaultdict(lambda: [0, 0, 0]) - for line in data.split('\n'): + for line in data: for team, result in parse_game(line): table[team][result] += 1 diff --git a/exercises/tournament/tournament_test.py b/exercises/tournament/tournament_test.py index fa3791db4bd..d9f19168a7a 100644 --- a/exercises/tournament/tournament_test.py +++ b/exercises/tournament/tournament_test.py @@ -8,107 +8,107 @@ class TournamentTest(unittest.TestCase): def test_just_the_header_if_no_input(self): self.assertEqual( - tally(''), - 'Team | MP | W | D | L | P' + tally([]), + ['Team | MP | W | D | L | P'] ) def test_a_win_is_three_points_and_a_loss_is_zero_points(self): - results = 'Allegoric Alaskans;Blithering Badgers;win' - table = ('Team | MP | W | D | L | P\n' - 'Allegoric Alaskans | 1 | 1 | 0 | 0 | 3\n' - 'Blithering Badgers | 1 | 0 | 0 | 1 | 0') + results = ['Allegoric Alaskans;Blithering Badgers;win'] + table = ['Team | MP | W | D | L | P', + 'Allegoric Alaskans | 1 | 1 | 0 | 0 | 3', + 'Blithering Badgers | 1 | 0 | 0 | 1 | 0'] self.assertEqual(tally(results), table) def test_a_win_can_also_be_expressed_as_a_loss(self): - results = 'Blithering Badgers;Allegoric Alaskans;loss' - table = ('Team | MP | W | D | L | P\n' - 'Allegoric Alaskans | 1 | 1 | 0 | 0 | 3\n' - 'Blithering Badgers | 1 | 0 | 0 | 1 | 0') + results = ['Blithering Badgers;Allegoric Alaskans;loss'] + table = ['Team | MP | W | D | L | P', + 'Allegoric Alaskans | 1 | 1 | 0 | 0 | 3', + 'Blithering Badgers | 1 | 0 | 0 | 1 | 0'] self.assertEqual(tally(results), table) def test_a_different_team_can_win(self): - results = 'Blithering Badgers;Allegoric Alaskans;win' - table = ('Team | MP | W | D | L | P\n' - 'Blithering Badgers | 1 | 1 | 0 | 0 | 3\n' - 'Allegoric Alaskans | 1 | 0 | 0 | 1 | 0') + results = ['Blithering Badgers;Allegoric Alaskans;win'] + table = ['Team | MP | W | D | L | P', + 'Blithering Badgers | 1 | 1 | 0 | 0 | 3', + 'Allegoric Alaskans | 1 | 0 | 0 | 1 | 0'] self.assertEqual(tally(results), table) def test_a_draw_is_one_point_each(self): - results = 'Allegoric Alaskans;Blithering Badgers;draw' - table = ('Team | MP | W | D | L | P\n' - 'Allegoric Alaskans | 1 | 0 | 1 | 0 | 1\n' - 'Blithering Badgers | 1 | 0 | 1 | 0 | 1') + results = ['Allegoric Alaskans;Blithering Badgers;draw'] + table = ['Team | MP | W | D | L | P', + 'Allegoric Alaskans | 1 | 0 | 1 | 0 | 1', + 'Blithering Badgers | 1 | 0 | 1 | 0 | 1'] self.assertEqual(tally(results), table) def test_there_can_be_more_than_one_match(self): - results = ('Allegoric Alaskans;Blithering Badgers;win\n' - 'Allegoric Alaskans;Blithering Badgers;win') - table = ('Team | MP | W | D | L | P\n' - 'Allegoric Alaskans | 2 | 2 | 0 | 0 | 6\n' - 'Blithering Badgers | 2 | 0 | 0 | 2 | 0') + results = ['Allegoric Alaskans;Blithering Badgers;win', + 'Allegoric Alaskans;Blithering Badgers;win'] + table = ['Team | MP | W | D | L | P', + 'Allegoric Alaskans | 2 | 2 | 0 | 0 | 6', + 'Blithering Badgers | 2 | 0 | 0 | 2 | 0'] self.assertEqual(tally(results), table) def test_there_can_be_more_than_one_winner(self): - results = ('Allegoric Alaskans;Blithering Badgers;loss\n' - 'Allegoric Alaskans;Blithering Badgers;win') - table = ('Team | MP | W | D | L | P\n' - 'Allegoric Alaskans | 2 | 1 | 0 | 1 | 3\n' - 'Blithering Badgers | 2 | 1 | 0 | 1 | 3') + results = ['Allegoric Alaskans;Blithering Badgers;loss', + 'Allegoric Alaskans;Blithering Badgers;win'] + table = ['Team | MP | W | D | L | P', + 'Allegoric Alaskans | 2 | 1 | 0 | 1 | 3', + 'Blithering Badgers | 2 | 1 | 0 | 1 | 3'] self.assertEqual(tally(results), table) def test_there_can_be_more_than_two_teams(self): - results = ('Allegoric Alaskans;Blithering Badgers;win\n' - 'Blithering Badgers;Courageous Californians;win\n' - 'Courageous Californians;Allegoric Alaskans;loss') - table = ('Team | MP | W | D | L | P\n' - 'Allegoric Alaskans | 2 | 2 | 0 | 0 | 6\n' - 'Blithering Badgers | 2 | 1 | 0 | 1 | 3\n' - 'Courageous Californians | 2 | 0 | 0 | 2 | 0') + results = ['Allegoric Alaskans;Blithering Badgers;win', + 'Blithering Badgers;Courageous Californians;win', + 'Courageous Californians;Allegoric Alaskans;loss'] + table = ['Team | MP | W | D | L | P', + 'Allegoric Alaskans | 2 | 2 | 0 | 0 | 6', + 'Blithering Badgers | 2 | 1 | 0 | 1 | 3', + 'Courageous Californians | 2 | 0 | 0 | 2 | 0'] self.assertEqual(tally(results), table) def test_typical_input(self): - results = ('Allegoric Alaskans;Blithering Badgers;win\n' - 'Devastating Donkeys;Courageous Californians;draw\n' - 'Devastating Donkeys;Allegoric Alaskans;win\n' - 'Courageous Californians;Blithering Badgers;loss\n' - 'Blithering Badgers;Devastating Donkeys;loss\n' - 'Allegoric Alaskans;Courageous Californians;win') - - table = ('Team | MP | W | D | L | P\n' - 'Devastating Donkeys | 3 | 2 | 1 | 0 | 7\n' - 'Allegoric Alaskans | 3 | 2 | 0 | 1 | 6\n' - 'Blithering Badgers | 3 | 1 | 0 | 2 | 3\n' - 'Courageous Californians | 3 | 0 | 1 | 2 | 1') + results = ['Allegoric Alaskans;Blithering Badgers;win', + 'Devastating Donkeys;Courageous Californians;draw', + 'Devastating Donkeys;Allegoric Alaskans;win', + 'Courageous Californians;Blithering Badgers;loss', + 'Blithering Badgers;Devastating Donkeys;loss', + 'Allegoric Alaskans;Courageous Californians;win'] + + table = ['Team | MP | W | D | L | P', + 'Devastating Donkeys | 3 | 2 | 1 | 0 | 7', + 'Allegoric Alaskans | 3 | 2 | 0 | 1 | 6', + 'Blithering Badgers | 3 | 1 | 0 | 2 | 3', + 'Courageous Californians | 3 | 0 | 1 | 2 | 1'] self.assertEqual(tally(results), table) def test_incomplete_competitionnot_not_all_pairs_have_played(self): - results = ('Allegoric Alaskans;Blithering Badgers;loss\n' - 'Devastating Donkeys;Allegoric Alaskans;loss\n' - 'Courageous Californians;Blithering Badgers;draw\n' - 'Allegoric Alaskans;Courageous Californians;win') + results = ['Allegoric Alaskans;Blithering Badgers;loss', + 'Devastating Donkeys;Allegoric Alaskans;loss', + 'Courageous Californians;Blithering Badgers;draw', + 'Allegoric Alaskans;Courageous Californians;win'] - table = ('Team | MP | W | D | L | P\n' - 'Allegoric Alaskans | 3 | 2 | 0 | 1 | 6\n' - 'Blithering Badgers | 2 | 1 | 1 | 0 | 4\n' - 'Courageous Californians | 2 | 0 | 1 | 1 | 1\n' - 'Devastating Donkeys | 1 | 0 | 0 | 1 | 0') + table = ['Team | MP | W | D | L | P', + 'Allegoric Alaskans | 3 | 2 | 0 | 1 | 6', + 'Blithering Badgers | 2 | 1 | 1 | 0 | 4', + 'Courageous Californians | 2 | 0 | 1 | 1 | 1', + 'Devastating Donkeys | 1 | 0 | 0 | 1 | 0'] self.assertEqual(tally(results), table) def test_ties_broken_alphabetically(self): - results = ('Courageous Californians;Devastating Donkeys;win\n' - 'Allegoric Alaskans;Blithering Badgers;win\n' - 'Devastating Donkeys;Allegoric Alaskans;loss\n' - 'Courageous Californians;Blithering Badgers;win\n' - 'Blithering Badgers;Devastating Donkeys;draw\n' - 'Allegoric Alaskans;Courageous Californians;draw') - - table = ('Team | MP | W | D | L | P\n' - 'Allegoric Alaskans | 3 | 2 | 1 | 0 | 7\n' - 'Courageous Californians | 3 | 2 | 1 | 0 | 7\n' - 'Blithering Badgers | 3 | 0 | 1 | 2 | 1\n' - 'Devastating Donkeys | 3 | 0 | 1 | 2 | 1') + results = ['Courageous Californians;Devastating Donkeys;win', + 'Allegoric Alaskans;Blithering Badgers;win', + 'Devastating Donkeys;Allegoric Alaskans;loss', + 'Courageous Californians;Blithering Badgers;win', + 'Blithering Badgers;Devastating Donkeys;draw', + 'Allegoric Alaskans;Courageous Californians;draw'] + + table = ['Team | MP | W | D | L | P', + 'Allegoric Alaskans | 3 | 2 | 1 | 0 | 7', + 'Courageous Californians | 3 | 2 | 1 | 0 | 7', + 'Blithering Badgers | 3 | 0 | 1 | 2 | 1', + 'Devastating Donkeys | 3 | 0 | 1 | 2 | 1'] self.assertEqual(tally(results), table) From ec506dfbb6cc34eeb8275fc8ea6a4b170924c134 Mon Sep 17 00:00:00 2001 From: spencer51324312 Date: Thu, 9 May 2019 08:38:46 -0400 Subject: [PATCH 21/21] allergies: update tests to v2.0.0 (#1777) * Fixes #1756 Updated it for canonical-data v2.0.0 --- exercises/allergies/allergies.py | 2 +- exercises/allergies/allergies_test.py | 163 +++++++++++++++++++++----- exercises/allergies/example.py | 4 +- 3 files changed, 134 insertions(+), 35 deletions(-) diff --git a/exercises/allergies/allergies.py b/exercises/allergies/allergies.py index f1eb64b0f06..8299b31e552 100644 --- a/exercises/allergies/allergies.py +++ b/exercises/allergies/allergies.py @@ -3,7 +3,7 @@ class Allergies(object): def __init__(self, score): pass - def is_allergic_to(self, item): + def allergic_to(self, item): pass @property diff --git a/exercises/allergies/allergies_test.py b/exercises/allergies/allergies_test.py index ad371cf3f5a..ad67eae3c52 100644 --- a/exercises/allergies/allergies_test.py +++ b/exercises/allergies/allergies_test.py @@ -7,62 +7,161 @@ unittest.TestCase.assertCountEqual = unittest.TestCase.assertItemsEqual -# Tests adapted from `problem-specifications//canonical-data.json` @ v1.2.0 +# Tests adapted from `problem-specifications//canonical-data.json` @ v2.0.0 class AllergiesTest(unittest.TestCase): - def test_no_allergies_means_not_allergic(self): - allergies = Allergies(0) - self.assertIs(allergies.is_allergic_to('peanuts'), False) - self.assertIs(allergies.is_allergic_to('cats'), False) - self.assertIs(allergies.is_allergic_to('strawberries'), False) - - def test_is_allergic_to_eggs(self): - self.assertIs(Allergies(1).is_allergic_to('eggs'), True) - - def test_allergic_to_eggs_in_addition_to_other_stuff(self): - allergies = Allergies(5) - self.assertIs(allergies.is_allergic_to('eggs'), True) - self.assertIs(allergies.is_allergic_to('shellfish'), True) - self.assertIs(allergies.is_allergic_to('strawberries'), False) - - def test_allergic_to_strawberries_but_not_peanuts(self): - allergies = Allergies(9) - self.assertIs(allergies.is_allergic_to('eggs'), True) - self.assertIs(allergies.is_allergic_to('peanuts'), False) - self.assertIs(allergies.is_allergic_to('shellfish'), False) - self.assertIs(allergies.is_allergic_to('strawberries'), True) - - def test_no_allergies_at_all(self): + + def test_eggs_not_allergic_to_anything(self): + self.assertIs(Allergies(0).allergic_to("eggs"), False) + + def test_allergic_only_to_eggs(self): + self.assertIs(Allergies(1).allergic_to("eggs"), True) + + def test_allergic_to_eggs_and_something_else(self): + self.assertIs(Allergies(3).allergic_to("eggs"), True) + + def test_allergic_to_something_but_not_eggs(self): + self.assertIs(Allergies(2).allergic_to("eggs"), False) + + def test_eggs_allergic_to_everything(self): + self.assertIs(Allergies(255).allergic_to("eggs"), True) + + def test_peanuts_not_allergic_to_anything(self): + self.assertIs(Allergies(0).allergic_to("peanuts"), False) + + def test_allergic_only_to_peanuts(self): + self.assertIs(Allergies(2).allergic_to("peanuts"), True) + + def test_allergic_to_peanuts_and_something_else(self): + self.assertIs(Allergies(7).allergic_to("peanuts"), True) + + def test_allergic_to_something_but_not_peanuts(self): + self.assertIs(Allergies(5).allergic_to("peanuts"), False) + + def test_peanuts_allergic_to_everything(self): + self.assertIs(Allergies(255).allergic_to("peanuts"), True) + + def test_shellfish_not_allergic_to_anything(self): + self.assertIs(Allergies(0).allergic_to("shellfish"), False) + + def test_allergic_only_to_shellfish(self): + self.assertIs(Allergies(4).allergic_to("shellfish"), True) + + def test_allergic_to_shellfish_and_something_else(self): + self.assertIs(Allergies(14).allergic_to("shellfish"), True) + + def test_allergic_to_something_but_not_shellfish(self): + self.assertIs(Allergies(10).allergic_to("shellfish"), False) + + def test_shellfish_allergic_to_everything(self): + self.assertIs(Allergies(255).allergic_to("shellfish"), True) + + def test_strawberries_not_allergic_to_anything(self): + self.assertIs(Allergies(0).allergic_to("strawberries"), False) + + def test_allergic_only_to_strawberries(self): + self.assertIs(Allergies(8).allergic_to("strawberries"), True) + + def test_allergic_to_strawberries_and_something_else(self): + self.assertIs(Allergies(28).allergic_to("strawberries"), True) + + def test_allergic_to_something_but_not_strawberries(self): + self.assertIs(Allergies(20).allergic_to("strawberries"), False) + + def test_strawberries_allergic_to_everything(self): + self.assertIs(Allergies(255).allergic_to("strawberries"), True) + + def test_tomatoes_not_allergic_to_anything(self): + self.assertIs(Allergies(0).allergic_to("tomatoes"), False) + + def test_allergic_only_to_tomatoes(self): + self.assertIs(Allergies(16).allergic_to("tomatoes"), True) + + def test_allergic_to_tomatoes_and_something_else(self): + self.assertIs(Allergies(56).allergic_to("tomatoes"), True) + + def test_allergic_to_something_but_not_tomatoes(self): + self.assertIs(Allergies(40).allergic_to("tomatoes"), False) + + def test_tomatoes_allergic_to_everything(self): + self.assertIs(Allergies(255).allergic_to("tomatoes"), True) + + def test_chocolate_not_allergic_to_anything(self): + self.assertIs(Allergies(0).allergic_to("chocolate"), False) + + def test_allergic_only_to_chocolate(self): + self.assertIs(Allergies(32).allergic_to("chocolate"), True) + + def test_allergic_to_chocolate_and_something_else(self): + self.assertIs(Allergies(112).allergic_to("chocolate"), True) + + def test_allergic_to_something_but_not_chocolate(self): + self.assertIs(Allergies(80).allergic_to("chocolate"), False) + + def test_chocolate_alergic_to_everything(self): + self.assertIs(Allergies(255).allergic_to("chocolate"), True) + + def test_pollen_not_alergic_to_anything(self): + self.assertIs(Allergies(0).allergic_to("pollen"), False) + + def test_allergic_only_to_pollen(self): + self.assertIs(Allergies(64).allergic_to("pollen"), True) + + def test_allergic_to_pollen_and_something_else(self): + self.assertIs(Allergies(224).allergic_to("pollen"), True) + + def test_allergic_to_something_but_not_pollen(self): + self.assertIs(Allergies(160).allergic_to("pollen"), False) + + def test_pollen_allergic_to_everything(self): + self.assertIs(Allergies(255).allergic_to("pollen"), True) + + def test_cats_not_allergic_to_anything(self): + self.assertIs(Allergies(0).allergic_to("cats"), False) + + def test_allergic_only_to_cats(self): + self.assertIs(Allergies(128).allergic_to("cats"), True) + + def test_allergic_to_cats_and_something_else(self): + self.assertIs(Allergies(192).allergic_to("cats"), True) + + def test_allergic_to_something_but_not_cats(self): + self.assertIs(Allergies(64).allergic_to("cats"), False) + + def test_cats_allergic_to_everything(self): + self.assertIs(Allergies(255).allergic_to('cats'), True) + + def test_no_allergies(self): self.assertEqual(Allergies(0).lst, []) - def test_allergic_to_just_eggs(self): + def test_just_eggs(self): self.assertEqual(Allergies(1).lst, ['eggs']) - def test_allergic_to_just_peanuts(self): + def test_just_peanuts(self): self.assertEqual(Allergies(2).lst, ['peanuts']) - def test_allergic_to_just_strawberries(self): + def test_just_strawberries(self): self.assertEqual(Allergies(8).lst, ['strawberries']) - def test_allergic_to_eggs_and_peanuts(self): + def test_eggs_and_peanuts(self): self.assertCountEqual(Allergies(3).lst, ['eggs', 'peanuts']) - def test_allergic_to_more_than_eggs_but_not_peanuts(self): + def test_more_than_eggs_but_not_peanuts(self): self.assertCountEqual(Allergies(5).lst, ['eggs', 'shellfish']) - def test_allergic_to_lots_of_stuff(self): + def test_lots_of_stuff(self): self.assertCountEqual( Allergies(248).lst, ['strawberries', 'tomatoes', 'chocolate', 'pollen', 'cats']) - def test_allergic_to_everything(self): + def test_everything(self): self.assertCountEqual( Allergies(255).lst, [ 'eggs', 'peanuts', 'shellfish', 'strawberries', 'tomatoes', 'chocolate', 'pollen', 'cats' ]) - def test_ignore_non_allergen_score_parts(self): + def test_no_allergen_score_parts(self): self.assertCountEqual( Allergies(509).lst, [ 'eggs', 'shellfish', 'strawberries', 'tomatoes', 'chocolate', diff --git a/exercises/allergies/example.py b/exercises/allergies/example.py index a88674ca97d..9e534667f36 100644 --- a/exercises/allergies/example.py +++ b/exercises/allergies/example.py @@ -14,10 +14,10 @@ class Allergies(object): def __init__(self, score): self.score = score - def is_allergic_to(self, allergy): + def allergic_to(self, allergy): return bool(self.score & 1 << self._allergies.index(allergy)) @property def lst(self): return [allergy for allergy in self._allergies - if self.is_allergic_to(allergy)] + if self.allergic_to(allergy)]