diff --git a/python/allergies/.exercism/metadata.json b/python/allergies/.exercism/metadata.json new file mode 100644 index 0000000..7c7f29e --- /dev/null +++ b/python/allergies/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"allergies","id":"c7cf9ff0b73d460aa125b5433fc72182","url":"https://exercism.io/my/solutions/c7cf9ff0b73d460aa125b5433fc72182","handle":"Xevion","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/allergies/README.md b/python/allergies/README.md new file mode 100644 index 0000000..01dcf05 --- /dev/null +++ b/python/allergies/README.md @@ -0,0 +1,79 @@ +# Allergies + +Given a person's allergy score, determine whether or not they're allergic to a given item, and their full list of allergies. + +An allergy test produces a single numeric score which contains the +information about all the allergies the person has (that they were +tested for). + +The list of items (and their value) that were tested are: + +* eggs (1) +* peanuts (2) +* shellfish (4) +* strawberries (8) +* tomatoes (16) +* chocolate (32) +* pollen (64) +* cats (128) + +So if Tom is allergic to peanuts and chocolate, he gets a score of 34. + +Now, given just that score of 34, your program should be able to say: + +- Whether Tom is allergic to any one of those allergens listed above. +- All the allergens Tom is allergic to. + +Note: a given score may include allergens **not** listed above (i.e. +allergens that score 256, 512, 1024, etc.). Your program should +ignore those components of the score. For example, if the allergy +score is 257, your program should only report the eggs (1) allergy. + +## 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 allergies_test.py` +- Python 3.4+: `pytest allergies_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 allergies_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/allergies` 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 + +Jumpstart Lab Warm-up [http://jumpstartlab.com](http://jumpstartlab.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/python/allergies/allergies.py b/python/allergies/allergies.py new file mode 100644 index 0000000..901f436 --- /dev/null +++ b/python/allergies/allergies.py @@ -0,0 +1,30 @@ +from math import log2, ceil + +scores = { + 1 : 'eggs', + 2 : 'peanuts', + 4 : 'shellfish', + 8 : 'strawberries', + 16 :'tomatoes', + 32 : 'chocolate', + 64 : 'pollen', + 128 : 'cats' +} + +class Allergies(object): + def __init__(self, score): + self.score = score + + def allergic_to(self, item): + return item.lower().strip() in self.lst + + @property + def lst(self): + temp1 = [] + if self.score > (2 ** len(scores)): + self.score -= (2 ** (ceil(log2(self.score)) - 1)) + while self.score > 0: + temp2 = max(scores.keys(), key= lambda item : 0 if item > self.score else item) + self.score -= temp2 + temp1.append(scores[temp2]) + return list(dict.fromkeys(temp1)) \ No newline at end of file diff --git a/python/allergies/allergies_test.py b/python/allergies/allergies_test.py new file mode 100644 index 0000000..ad67eae --- /dev/null +++ b/python/allergies/allergies_test.py @@ -0,0 +1,173 @@ +import unittest + +from allergies import Allergies + +# Python 2/3 compatibility +if not hasattr(unittest.TestCase, 'assertCountEqual'): + unittest.TestCase.assertCountEqual = unittest.TestCase.assertItemsEqual + + +# Tests adapted from `problem-specifications//canonical-data.json` @ v2.0.0 + +class AllergiesTest(unittest.TestCase): + + 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_just_eggs(self): + self.assertEqual(Allergies(1).lst, ['eggs']) + + def test_just_peanuts(self): + self.assertEqual(Allergies(2).lst, ['peanuts']) + + def test_just_strawberries(self): + self.assertEqual(Allergies(8).lst, ['strawberries']) + + def test_eggs_and_peanuts(self): + self.assertCountEqual(Allergies(3).lst, ['eggs', 'peanuts']) + + def test_more_than_eggs_but_not_peanuts(self): + self.assertCountEqual(Allergies(5).lst, ['eggs', 'shellfish']) + + def test_lots_of_stuff(self): + self.assertCountEqual( + Allergies(248).lst, + ['strawberries', 'tomatoes', 'chocolate', 'pollen', 'cats']) + + def test_everything(self): + self.assertCountEqual( + Allergies(255).lst, [ + 'eggs', 'peanuts', 'shellfish', 'strawberries', 'tomatoes', + 'chocolate', 'pollen', 'cats' + ]) + + def test_no_allergen_score_parts(self): + self.assertCountEqual( + Allergies(509).lst, [ + 'eggs', 'shellfish', 'strawberries', 'tomatoes', 'chocolate', + 'pollen', 'cats' + ]) + + +if __name__ == '__main__': + unittest.main()