From e6c7977320f841eb49a8440def41a40cb1d66684 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Mon, 25 Mar 2024 10:10:25 +0100 Subject: [PATCH] Add new exercises for python --- python/black-jack/.exercism/config.json | 27 ++ python/black-jack/.exercism/metadata.json | 1 + python/black-jack/HELP.md | 130 ++++++ python/black-jack/HINTS.md | 45 ++ python/black-jack/README.md | 395 ++++++++++++++++++ python/black-jack/black_jack.py | 81 ++++ python/black-jack/black_jack_test.py | 114 +++++ python/bob/.exercism/config.json | 47 +++ python/bob/.exercism/metadata.json | 1 + python/bob/HELP.md | 130 ++++++ python/bob/README.md | 72 ++++ python/bob/bob.py | 2 + python/bob/bob_test.py | 102 +++++ .../.exercism/config.json | 19 + .../.exercism/metadata.json | 1 + python/little-sisters-vocab/HELP.md | 130 ++++++ python/little-sisters-vocab/HINTS.md | 37 ++ python/little-sisters-vocab/README.md | 340 +++++++++++++++ python/little-sisters-vocab/strings.py | 54 +++ python/little-sisters-vocab/strings_test.py | 126 ++++++ python/pig-latin/.exercism/config.json | 30 ++ python/pig-latin/.exercism/metadata.json | 1 + python/pig-latin/HELP.md | 130 ++++++ python/pig-latin/README.md | 47 +++ python/pig-latin/pig_latin.py | 2 + python/pig-latin/pig_latin_test.py | 77 ++++ python/raindrops/.exercism/config.json | 32 ++ python/raindrops/.exercism/metadata.json | 1 + python/raindrops/HELP.md | 130 ++++++ python/raindrops/README.md | 75 ++++ python/raindrops/raindrops.py | 2 + python/raindrops/raindrops_test.py | 67 +++ 32 files changed, 2448 insertions(+) create mode 100644 python/black-jack/.exercism/config.json create mode 100644 python/black-jack/.exercism/metadata.json create mode 100644 python/black-jack/HELP.md create mode 100644 python/black-jack/HINTS.md create mode 100644 python/black-jack/README.md create mode 100644 python/black-jack/black_jack.py create mode 100644 python/black-jack/black_jack_test.py create mode 100644 python/bob/.exercism/config.json create mode 100644 python/bob/.exercism/metadata.json create mode 100644 python/bob/HELP.md create mode 100644 python/bob/README.md create mode 100644 python/bob/bob.py create mode 100644 python/bob/bob_test.py create mode 100644 python/little-sisters-vocab/.exercism/config.json create mode 100644 python/little-sisters-vocab/.exercism/metadata.json create mode 100644 python/little-sisters-vocab/HELP.md create mode 100644 python/little-sisters-vocab/HINTS.md create mode 100644 python/little-sisters-vocab/README.md create mode 100644 python/little-sisters-vocab/strings.py create mode 100644 python/little-sisters-vocab/strings_test.py create mode 100644 python/pig-latin/.exercism/config.json create mode 100644 python/pig-latin/.exercism/metadata.json create mode 100644 python/pig-latin/HELP.md create mode 100644 python/pig-latin/README.md create mode 100644 python/pig-latin/pig_latin.py create mode 100644 python/pig-latin/pig_latin_test.py create mode 100644 python/raindrops/.exercism/config.json create mode 100644 python/raindrops/.exercism/metadata.json create mode 100644 python/raindrops/HELP.md create mode 100644 python/raindrops/README.md create mode 100644 python/raindrops/raindrops.py create mode 100644 python/raindrops/raindrops_test.py diff --git a/python/black-jack/.exercism/config.json b/python/black-jack/.exercism/config.json new file mode 100644 index 0000000..a23fa9e --- /dev/null +++ b/python/black-jack/.exercism/config.json @@ -0,0 +1,27 @@ +{ + "authors": [ + "Ticktakto", + "Yabby1997", + "limm-jk", + "OMEGA-Y", + "wnstj2007", + "pranasziaukas", + "bethanyG" + ], + "contributors": [ + "PaulT89" + ], + "files": { + "solution": [ + "black_jack.py" + ], + "test": [ + "black_jack_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "poker", + "blurb": "Learn about comparisons by implementing some Black Jack judging rules." +} diff --git a/python/black-jack/.exercism/metadata.json b/python/black-jack/.exercism/metadata.json new file mode 100644 index 0000000..0878f5d --- /dev/null +++ b/python/black-jack/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"black-jack","id":"1717580736c8411a9af5b913da36035f","url":"https://exercism.org/tracks/python/exercises/black-jack","handle":"DanielSiepmann","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/black-jack/HELP.md b/python/black-jack/HELP.md new file mode 100644 index 0000000..970b1fa --- /dev/null +++ b/python/black-jack/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit black_jack.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/black-jack/HINTS.md b/python/black-jack/HINTS.md new file mode 100644 index 0000000..aaa0273 --- /dev/null +++ b/python/black-jack/HINTS.md @@ -0,0 +1,45 @@ +# Hints + +[The Python comparisons tutorial][python comparisons tutorial] and [Python comparisons examples][python comparisons examples] are a great introduction covering the content of this exercise. + +## 1. Calculate the value of a card + +- You can use the equality comparison operator `==` to determine if a card is an ace card: `card == 'A'`. +- You can use the containment operator `in` to determine if a substring is contained inside a string: `'Q' in 'KJQ'`. +- You can use the [`int` constructor][int constructor] to convert a `str` of an `int` to an `int`: `int('13')`. + +## 2. Determine which card has a higher value + +- Once you have defined the `value_of_card` function, you can call it from other functions. +- You can use the value comparison operators `>` and `<` to determine if specific cards are _greater than_ or _less than_ a given value: `3 < 12`. +- You can use the equality comparison operator `==` to determine if two values are equal to one another. + +## 3. Calculate the value of an ace + +- Once you have defined the `value_of_card` function, you can call it from other functions. +- You can use the order comparison operator `>` to decide the appropriate course of action here. + +## 4. Determine Blackjack + +- Remember, you can use the [`if`/`elif`/`else` syntax][if syntax] to handle different combinations of cards. +- You can chain BOTH comparison operators and boolean operators _arbitrarily_: `y < z < x` or `(y or z) and (x or z)` +- You can reuse the already implemented `value_of_card` function. + +## 5. Splitting pairs + +- You can reuse the already implemented `value_of_card` function. +- You can handle the `A` case (when at least one of the cards in an ace) separately. + +## 6. Doubling down + +- An `A` scored at 11 will never allow doubling down if there are two cards in the hand. +- Given the first point, you _should_ be able to reuse the already implemented `value_of_card` function. +- You can chain comparison operators _arbitrarily_: `y < z < x`. +- You can use the [conditional expression][conditional expression] (_sometimes called a "ternary operator"_) + to shorten simple `if`/`else` statements: `13 if letter == 'M' else 3`. + +[conditional expression]: https://docs.python.org/3/reference/expressions.html#conditional-expressions +[if syntax]: https://docs.python.org/3/tutorial/controlflow.html#if-statements +[int constructor]: https://docs.python.org/3/library/functions.html#int +[python comparisons examples]: https://www.tutorialspoint.com/python/comparison_operators_example.htm +[python comparisons tutorial]: https://docs.python.org/3/reference/expressions.html#comparisons \ No newline at end of file diff --git a/python/black-jack/README.md b/python/black-jack/README.md new file mode 100644 index 0000000..96b7036 --- /dev/null +++ b/python/black-jack/README.md @@ -0,0 +1,395 @@ +# Black Jack + +Welcome to Black Jack on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +## Comparisons + +Python supports the following basic comparison operators: + +| Operator | Operation | Description | +| -------- | -------------------------- | ------------------------------------------------------------------------- | +| `>` | "greater than" | `a > b` is `True` if `a` is **strictly** greater in value than `b` | +| `<` | "less than" | `a < b` is `True` if `a` is **strictly** less in value than `b` | +| `==` | "equal to" | `a == b` is `True` if `a` is **strictly** equal to `b` in value | +| `>=` | "greater than or equal to" | `a >= b` is `True` if `a > b` OR `a == b` in value | +| `<=` | "less than or equal to" | `a <= b` is `True` if `a < b` or `a == b` in value | +| `!=` | "not equal to" | `a != b` is `True` if `a == b` is `False` | +| `is` | "identity" | `a is b` is `True` if **_and only if_** `a` and `b` are the same _object_ | +| `is not` | "negated identity" | `a is not b` is `True` if `a` and `b` are **not** the same _object_ | +| `in` | "containment test" | `a in b` is `True` if `a` is member, subset, or element of `b` | +| `not in` | "negated containment test" | `a not in b` is `True` if `a` is not a member, subset, or element of `b` | + +They all have the same priority (_which is higher than that of [Boolean operations][boolean operations], but lower than that of arithmetic or bitwise operations_). + +## Comparison between different data types + +Objects that are different types (_except numeric types_) never compare equal by default. +Non-identical instances of a `class` will also _**not**_ compare as equal unless the `class` defines special [rich comparison][rich comparisons] methods that customize the default `object` comparison behavior. +Customizing via `rich comparisons` will be covered in a follow-on exercise. +For (much) more detail on this topic, see [Value comparisons][value comparisons] in the Python documentation. + +Numeric types are (mostly) an exception to this type matching rule. +An `integer` **can** be considered equal to a `float` (_or an [`octal`][octal] equal to a [`hexadecimal`][hex]_), as long as the types can be implicitly converted for comparison. + +For the other numeric types in the Python standard library ([complex][complex numbers], [decimal][decimal numbers], [fractions][rational numbers]), comparison operators are defined where they "make sense" (_where implicit conversion does not change the outcome_), but throw a `TypeError` if the underlying objects cannot be accurately converted for comparison. +For more information on the rules that python uses for _numeric conversion_, see [arithmetic conversions][arithmetic conversions] in the Python documentation. + +```python +>>> import fractions + +# A string cannot be converted to an int. +>>> 17 == '17' +False + +# An int can be converted to float for comparison. +>>> 17 == 17.0 +True + +# The fraction 6/3 can be converted to the int 2 +# The int 2 can be converted to 0b10 in binary. +>>> 6/3 == 0b10 +True + +# An int can be converted to a complex number with a 0 imaginary part. +>>> 17 == complex(17) +True + +# The fraction 2/5 can be converted to the float 0.4 +>>> 0.4 == 2/5 +True + +>>> complex(2/5, 1/2) == complex(0.4, 0.5) +True +``` + +Any ordered comparison of a number to a `NaN` (_not a number_) type is `False`. +A confusing side effect of Python's `NaN` definition is that `NaN` never compares equal to `NaN`. + +```python +>>> x = float('NaN') + +>>> 3 < x +False + +>>> x < 3 +False + +# NaN never compares equal to NaN +>>> x == x +False +``` + +## Comparing Strings + +Unlike numbers, strings (`str`) are compared [_lexicographically_][lexographic order], using their individual Unicode code points (_the result of passing each code point in the `str` to the built-in function [`ord()`][ord], which returns an `int`_). +If all code points in both strings match and are _**in the same order**_, the two strings are considered equal. +This comparison is done in a 'pair-wise' fashion - first-to-first, second-to-second, etc. +In Python 3.x, `str` and `bytes` cannot be directly coerced/compared. + +```python +>>> 'Python' > 'Rust' +False + +>>> 'Python' > 'JavaScript' +True + +# Examples with Mandarin. +# hello < goodbye +>>> '你好' < '再见' +True + +# ord() of first characters +>>> ord('你'), ord('再') +(20320, 20877) + +# ord() of second characters +>>> ord('好'), ord('见') +(22909, 35265) + +# And with Korean words. +# Pretty < beautiful. +>>> '예쁜' < '아름다운' +False + +>>> ord('예'), ord('아') +(50696, 50500) +``` + +## Comparison Chaining + +Comparison operators can be chained _arbitrarily_ -- meaning that they can be used in any combination of any length. +Note that the evaluation of an expression takes place from `left` to `right`. + +As an example, `x < y <= z` is equivalent to `x < y` `and` `y <= z`, except that `y` is evaluated **only once**. +In both cases, `z` is _not_ evaluated **at all** when `x < y` is found to be `False`. +This is often called `short-circuit evaluation` - the evaluation stops if the truth value of the expression has already been determined. + +`Short circuiting` is supported by various boolean operators, functions, and also by comparison chaining in Python. +Unlike many other programming languages, including `C`, `C++`, `C#`, and `Java`, chained expressions like `a < b < c` in Python have a conventional [mathematical interpretation][three way boolean comparison] and precedence. + +```python +>>> x = 2 +>>> y = 5 +>>> z = 10 + +>>> x < y < z +True + +>>> x < y > z +False + +>>> x > y < z +False +``` + +## Comparing object identity + +The operators `is` and `is not` test for object [_identity_][object identity], as opposed to object _value_. +An object's identity never changes after creation and can be found by using the [`id()`][id function] function. + +` is ` evaluates to `True` if _**and only if**_ `id()` == `id()`. +` is not ` yields the inverse. + +Due to their singleton status, `None` and `NotImplemented` should always be compared to items using `is` and `is not`. +See the Python reference docs on [value comparisons][value comparisons none] and [PEP8][pep8 programming recommendations] for more details on this convention. + +```python +>>> my_fav_numbers = [1, 2, 3] + +>>> your_fav_numbers = my_fav_numbers + +>>> my_fav_numbers is your_fav_numbers +True + +# The returned id will differ by system and python version. +>>> id(my_fav_numbers) +4517478208 + +# your_fav_numbers is only an alias pointing to the original my_fav_numbers object. +# Assigning a new name does not create a new object. +>>> id(your_fav_numbers) +4517478208 + + +>>> my_fav_numbers is not your_fav_numbers +False + +>>> my_fav_numbers is not None +True + +>>> my_fav_numbers is NotImplemented +False +``` + +## Membership comparisons + +The operators `in` and `not in` test for _membership_. +` in ` evaluates to `True` if `` is a member of `` (_if `` is a subset of or is contained within ``_), and evaluates `False` otherwise. +` not in ` returns the negation, or _opposite of_ ` in `. + +For string and bytes types, ` in ` is `True` _**if and only if**_ `` is a substring of ``. + +```python +# A set of lucky numbers. +>>> lucky_numbers = {11, 22, 33} +>>> 22 in lucky_numbers +True + +>>> 44 in lucky_numbers +False + +# A dictionary of employee information. +>>> employee = {'name': 'John Doe', + 'id': 67826, 'age': 33, + 'title': 'ceo'} + +# Checking for the membership of certain keys. +>>> 'age' in employee +True + +>>> 33 in employee +False + +>>> 'lastname' not in employee +True + +# Checking for substring membership +>>> name = 'Super Batman' +>>> 'Bat' in name +True + +>>> 'Batwoman' in name +False +``` + +[arithmetic conversions]: https://docs.python.org/3/reference/expressions.html?highlight=number%20conversion#arithmetic-conversions +[boolean operations]: https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not +[complex numbers]: https://docs.python.org/3/library/functions.html#complex +[decimal numbers]: https://docs.python.org/3/library/decimal.html +[hex]: https://docs.python.org/3/library/functions.html?highlight=hex#hex +[id function]: https://docs.python.org/3/library/functions.html#id +[lexographic order]: https://en.wikipedia.org/wiki/Lexicographic_order +[object identity]: https://docs.python.org/3/reference/datamodel.html +[octal]: https://docs.python.org/3/library/functions.html?#oct +[ord]: https://docs.python.org/3/library/functions.html#ord +[pep8 programming recommendations]: https://pep8.org/#programming-recommendations +[rational numbers]: https://docs.python.org/3/library/fractions.html +[rich comparisons]: https://docs.python.org/3/reference/datamodel.html#object.__lt__ +[three way boolean comparison]: https://en.wikipedia.org/wiki/Three-way_comparison +[value comparisons none]: https://docs.python.org/3/reference/expressions.html?highlight=none#value-comparisons +[value comparisons]: https://docs.python.org/3/reference/expressions.html?highlight=nan#value-comparisons + +## Instructions + +In this exercise you are going to implement some rules of [Blackjack][blackjack], +such as the way the game is played and scored. + +**Note** : In this exercise, _`A`_ means ace, _`J`_ means jack, _`Q`_ means queen, and _`K`_ means king. +Jokers are discarded. +A [standard French-suited 52-card deck][standard_deck] is assumed, but in most versions, several decks are shuffled together for play. + +## 1. Calculate the value of a card + +In Blackjack, it is up to each individual player if an ace is worth 1 or 11 points (_more on that later_). +Face cards (`J`, `Q`, `K`) are scored at 10 points and any other card is worth its "pip" (_numerical_) value. + +Define the `value_of_card()` function with parameter `card`. +The function should return the _numerical value_ of the passed-in card string. +Since an ace can take on multiple values (1 **or** 11), this function should fix the value of an ace card at 1 for the time being. +Later on, you will implement a function to determine the value of an ace card, given an existing hand. + +```python +>>> value_of_card('K') +10 + +>>> value_of_card('4') +4 + +>>> value_of_card('A') +1 +``` + +## 2. Determine which card has a higher value + +Define the `higher_card(, )` function having parameters `card_one` and `card_two`. +For scoring purposes, the value of `J`, `Q` or `K` is 10. +The function should return which card has the higher value for scoring. +If both cards have an equal value, return both. +Returning both cards can be done by using a comma in the `return` statement: + +```python +# Using a comma in a return creates a Tuple. Tuples will be covered in a later exercise. +>>> def returning_two_values(value_one, value_two): + return value_one, value_two + +>>> returning_two_values('K', '3') +('K', '3') +``` + +An ace can take on multiple values, so we will fix `A` cards to a value of 1 for this task. + +```python +>>> higher_card('K', '10') +('K', '10') + +>>> higher_card('4', '6') +'6' + +>>> higher_card('K', 'A') +'K' +``` + +## 3. Calculate the value of an ace + +As mentioned before, an ace can be worth _either_ 1 **or** 11 points. +Players try to get as close as possible to a score of 21, without going _over_ 21 (_going "bust"_). + +Define the `value_of_ace(, )` function with parameters `card_one` and `card_two`, which are a pair of cards already in the hand _before_ getting an ace card. +Your function will have to decide if the upcoming ace will get a value of 1 or a value of 11, and return that value. +Remember: the value of the hand with the ace needs to be as high as possible _without_ going over 21. + +**Hint**: if we already have an ace in hand, then the value for the upcoming ace would be 1. + +```python +>>> value_of_ace('6', 'K') +1 + +>>> value_of_ace('7', '3') +11 +``` + +## 4. Determine a "Natural" or "Blackjack" Hand + +If the first two cards a player is dealt are an ace (A) and a ten-card (_10, K , Q or J_), then the player has a score of 21. +This is known as a blackjack hand. + + +Define the `is_blackjack(, )` function with parameters `card_one` and `card_two`, which are a pair of cards. +Determine if the two-card hand is a `blackjack`, and return the boolean `True` if it is, `False` otherwise. + +**Note** : The score _calculation_ can be done in many ways. +But if possible, we'd like you to check if there is an ace and a ten-card **_in_** the hand (or at a certain position), as opposed to _summing_ the hand values. + +```python +>>> is_blackjack('A', 'K') +True + +>>> is_blackjack('10', '9') +False +``` + +## 5. Splitting pairs + +If the players first two cards are of the same value, such as two sixes, or a `Q` and `K` a player may choose to treat them as two separate hands. +This is known as "splitting pairs". + +Define the `can_split_pairs(, )` function with parameters `card_one` and `card_two`, which are a pair of cards. +Determine if this two-card hand can be split into two pairs. +If the hand can be split, return the boolean `True` otherwise, return `False` + +```python +>>> can_split_pairs('Q', 'K') +True + +>>> can_split_pairs('10', 'A') +False +``` + +## 6. Doubling down + +When the original two cards dealt total 9, 10, or 11 points, a player can place an additional bet equal to their original bet. +This is known as "doubling down". + +Define the `can_double_down(, )` function with parameters `card_one` and `card_two`, which are a pair of cards. +Determine if the two-card hand can be "doubled down", and return the boolean `True` if it can, `False` otherwise. + +```python +>>> can_double_down('A', '9') +True + +>>> can_double_down('10', '2') +False +``` + +[blackjack]: https://bicyclecards.com/how-to-play/blackjack/ +[standard_deck]: https://en.wikipedia.org/wiki/Standard_52-card_deck + +## Source + +### Created by + +- @Ticktakto +- @Yabby1997 +- @limm-jk +- @OMEGA-Y +- @wnstj2007 +- @pranasziaukas +- @bethanyG + +### Contributed to by + +- @PaulT89 \ No newline at end of file diff --git a/python/black-jack/black_jack.py b/python/black-jack/black_jack.py new file mode 100644 index 0000000..9ce6ca5 --- /dev/null +++ b/python/black-jack/black_jack.py @@ -0,0 +1,81 @@ +"""Functions to help play and score a game of blackjack. + +How to play blackjack: https://bicyclecards.com/how-to-play/blackjack/ +"Standard" playing cards: https://en.wikipedia.org/wiki/Standard_52-card_deck +""" + + +def value_of_card(card): + """Determine the scoring value of a card. + + :param card: str - given card. + :return: int - value of a given card. See below for values. + + 1. 'J', 'Q', or 'K' (otherwise known as "face cards") = 10 + 2. 'A' (ace card) = 1 + 3. '2' - '10' = numerical value. + """ + + pass + + +def higher_card(card_one, card_two): + """Determine which card has a higher value in the hand. + + :param card_one, card_two: str - cards dealt in hand. See below for values. + :return: str or tuple - resulting Tuple contains both cards if they are of equal value. + + 1. 'J', 'Q', or 'K' (otherwise known as "face cards") = 10 + 2. 'A' (ace card) = 1 + 3. '2' - '10' = numerical value. + """ + + pass + + +def value_of_ace(card_one, card_two): + """Calculate the most advantageous value for the ace card. + + :param card_one, card_two: str - card dealt. See below for values. + :return: int - either 1 or 11 value of the upcoming ace card. + + 1. 'J', 'Q', or 'K' (otherwise known as "face cards") = 10 + 2. 'A' (ace card) = 11 (if already in hand) + 3. '2' - '10' = numerical value. + """ + + pass + + +def is_blackjack(card_one, card_two): + """Determine if the hand is a 'natural' or 'blackjack'. + + :param card_one, card_two: str - card dealt. See below for values. + :return: bool - is the hand is a blackjack (two cards worth 21). + + 1. 'J', 'Q', or 'K' (otherwise known as "face cards") = 10 + 2. 'A' (ace card) = 11 (if already in hand) + 3. '2' - '10' = numerical value. + """ + + pass + + +def can_split_pairs(card_one, card_two): + """Determine if a player can split their hand into two hands. + + :param card_one, card_two: str - cards dealt. + :return: bool - can the hand be split into two pairs? (i.e. cards are of the same value). + """ + + pass + + +def can_double_down(card_one, card_two): + """Determine if a blackjack player can place a double down bet. + + :param card_one, card_two: str - first and second cards in hand. + :return: bool - can the hand can be doubled down? (i.e. totals 9, 10 or 11 points). + """ + + pass diff --git a/python/black-jack/black_jack_test.py b/python/black-jack/black_jack_test.py new file mode 100644 index 0000000..0962781 --- /dev/null +++ b/python/black-jack/black_jack_test.py @@ -0,0 +1,114 @@ +import unittest +import pytest + +from black_jack import ( + value_of_card, + higher_card, + value_of_ace, + is_blackjack, + can_split_pairs, + can_double_down + ) + + +class BlackJackTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_value_of_card(self): + test_data = [('2', 2), ('5', 5), ('8', 8), + ('A', 1), ('10', 10), ('J', 10), + ('Q', 10), ('K', 10)] + + for variant, (card, expected) in enumerate(test_data, 1): + with self.subTest(f'variation #{variant}', card=card, expected=expected): + actual_result = value_of_card(card) + error_msg = (f'Called value_of_card({card}). ' + f'The function returned {actual_result} as the value of the {card} card, ' + f'but the test expected {expected} as the {card} card value.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + + @pytest.mark.task(taskno=2) + def test_higher_card(self): + test_data = [('A', 'A', ('A', 'A')), + ('10', 'J', ('10', 'J')), + ('3', 'A', '3'), + ('3', '6', '6'), + ('Q', '10', ('Q', '10')), + ('4', '4', ('4', '4')), + ('9', '10', '10'), + ('6', '9', '9'), + ('4', '8', '8')] + + for variant, (card_one, card_two, expected) in enumerate(test_data, 1): + with self.subTest(f'variation #{variant}', card_one=card_one, card_two=card_two, expected=expected): + actual_result = higher_card(card_one, card_two) + error_msg = (f'Called higher_card({card_one}, {card_two}). ' + f'The function returned {actual_result}, ' + f'but the test expected {expected} as the result for the cards {card_one, card_two}.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=3) + def test_value_of_ace(self): + test_data = [('2', '3', 11), ('3', '6', 11), ('5', '2', 11), + ('8', '2', 11), ('5', '5', 11), ('Q', 'A', 1), + ('10', '2', 1), ('7', '8', 1), ('J', '9', 1), + ('K', 'K', 1), ('2', 'A', 1), ('A', '2', 1)] + + for variant, (card_one, card_two, ace_value) in enumerate(test_data, 1): + with self.subTest(f'variation #{variant}', card_one=card_one, card_two=card_two, ace_value=ace_value): + actual_result = value_of_ace(card_one, card_two) + error_msg = (f'Called value_of_ace({card_one}, {card_two}). ' + f'The function returned {actual_result}, ' + f'but the test expected {ace_value} as the value of an ace card ' + f'when the hand includes {card_one, card_two}.') + + self.assertEqual(value_of_ace(card_one, card_two), ace_value, msg=error_msg) + + @pytest.mark.task(taskno=4) + def test_is_blackjack(self): + test_data = [(('A', 'K'), True), (('10', 'A'), True), + (('10', '9'), False), (('A', 'A'), False), + (('4', '7'), False), (('9', '2'), False), + (('Q', 'K'), False)] + + for variant, (hand, expected) in enumerate(test_data, 1): + with self.subTest(f'variation #{variant}', hand=hand, expected=expected): + actual_result = is_blackjack(*hand) + error_msg = (f'Called is_blackjack({hand[0]}, {hand[1]}). ' + f'The function returned {actual_result}, ' + f'but hand {hand} {"is" if expected else "is not"} a blackjack.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=5) + def test_can_split_pairs(self): + test_data = [(('Q', 'K'), True), (('6', '6'), True), + (('A', 'A'), True),(('10', 'A'), False), + (('10', '9'), False)] + + for variant, (hand, expected) in enumerate(test_data, 1): + with self.subTest(f'variation #{variant}', input=hand, expected=expected): + actual_result = can_split_pairs(*hand) + error_msg = (f'Called can_split_pairs({hand[0]}, {hand[1]}). ' + f'The function returned {actual_result}, ' + f'but hand {hand} {"can" if expected else "cannot"} be split into pairs.') + + self.assertEqual(actual_result, expected, msg=error_msg) + + @pytest.mark.task(taskno=6) + def test_can_double_down(self): + test_data = [(('A', '9'), True), (('K', 'A'), True), + (('4', '5'), True),(('A', 'A'), False), + (('10', '2'), False), (('10', '9'), False)] + + for variant, (hand, expected) in enumerate(test_data, 1): + with self.subTest(f'variation #{variant}', hand=hand, expected=expected): + actual_result = can_double_down(*hand) + error_msg = (f'Called can_double_down({hand[0]}, {hand[1]}). ' + f'The function returned {actual_result}, ' + f'but hand {hand} {"can" if expected else "cannot"} be doubled down.') + + self.assertEqual(actual_result, expected, msg=error_msg) diff --git a/python/bob/.exercism/config.json b/python/bob/.exercism/config.json new file mode 100644 index 0000000..ec0fc61 --- /dev/null +++ b/python/bob/.exercism/config.json @@ -0,0 +1,47 @@ +{ + "authors": [], + "contributors": [ + "0xae", + "aldraco", + "atg-abhishek", + "austinlyons", + "behrtam", + "BethanyG", + "cmccandless", + "cypher", + "Dog", + "etrepum", + "ikhadykin", + "janetriley", + "jremmen", + "koljakube", + "kytrinyx", + "lowks", + "lucasdpau", + "miketamis", + "N-Parsons", + "patricksjackson", + "pheanex", + "sdublish", + "sjakobi", + "stonemirror", + "thenigan", + "thomasjpfan", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "bob.py" + ], + "test": [ + "bob_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Bob is a lackadaisical teenager. In conversation, his responses are very limited.", + "source": "Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial.", + "source_url": "https://pine.fm/LearnToProgram/?Chapter=06" +} diff --git a/python/bob/.exercism/metadata.json b/python/bob/.exercism/metadata.json new file mode 100644 index 0000000..0cf4d20 --- /dev/null +++ b/python/bob/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"bob","id":"43ba401157eb4fbdbe509c56987c49c3","url":"https://exercism.org/tracks/python/exercises/bob","handle":"DanielSiepmann","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/bob/HELP.md b/python/bob/HELP.md new file mode 100644 index 0000000..c92dfd6 --- /dev/null +++ b/python/bob/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit bob.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/bob/README.md b/python/bob/README.md new file mode 100644 index 0000000..823897d --- /dev/null +++ b/python/bob/README.md @@ -0,0 +1,72 @@ +# Bob + +Welcome to Bob on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +Bob is a [lackadaisical][] teenager. +He likes to think that he's very cool. +And he definitely doesn't get excited about things. +That wouldn't be cool. + +When people talk to him, his responses are pretty limited. + +[lackadaisical]: https://www.collinsdictionary.com/dictionary/english/lackadaisical + +## Instructions + +Your task is to determine what Bob will reply to someone when they say something to him or ask him a question. + +Bob only ever answers one of five things: + +- **"Sure."** + This is his response if you ask him a question, such as "How are you?" + The convention used for questions is that it ends with a question mark. +- **"Whoa, chill out!"** + This is his answer if you YELL AT HIM. + The convention used for yelling is ALL CAPITAL LETTERS. +- **"Calm down, I know what I'm doing!"** + This is what he says if you yell a question at him. +- **"Fine. Be that way!"** + This is how he responds to silence. + The convention used for silence is nothing, or various combinations of whitespace characters. +- **"Whatever."** + This is what he answers to anything else. + +## Source + +### Contributed to by + +- @0xae +- @aldraco +- @atg-abhishek +- @austinlyons +- @behrtam +- @BethanyG +- @cmccandless +- @cypher +- @Dog +- @etrepum +- @ikhadykin +- @janetriley +- @jremmen +- @koljakube +- @kytrinyx +- @lowks +- @lucasdpau +- @miketamis +- @N-Parsons +- @patricksjackson +- @pheanex +- @sdublish +- @sjakobi +- @stonemirror +- @thenigan +- @thomasjpfan +- @tqa236 +- @yawpitch + +### Based on + +Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. - https://pine.fm/LearnToProgram/?Chapter=06 \ No newline at end of file diff --git a/python/bob/bob.py b/python/bob/bob.py new file mode 100644 index 0000000..94a7315 --- /dev/null +++ b/python/bob/bob.py @@ -0,0 +1,2 @@ +def response(hey_bob): + pass diff --git a/python/bob/bob_test.py b/python/bob/bob_test.py new file mode 100644 index 0000000..faba5f9 --- /dev/null +++ b/python/bob/bob_test.py @@ -0,0 +1,102 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/bob/canonical-data.json +# File last updated on 2023-07-20 + +import unittest + +from bob import ( + response, +) + + +class BobTest(unittest.TestCase): + def test_stating_something(self): + self.assertEqual(response("Tom-ay-to, tom-aaaah-to."), "Whatever.") + + def test_shouting(self): + self.assertEqual(response("WATCH OUT!"), "Whoa, chill out!") + + def test_shouting_gibberish(self): + self.assertEqual(response("FCECDFCAAB"), "Whoa, chill out!") + + def test_asking_a_question(self): + self.assertEqual( + response("Does this cryogenic chamber make me look fat?"), "Sure." + ) + + def test_asking_a_numeric_question(self): + self.assertEqual(response("You are, what, like 15?"), "Sure.") + + def test_asking_gibberish(self): + self.assertEqual(response("fffbbcbeab?"), "Sure.") + + def test_talking_forcefully(self): + self.assertEqual(response("Hi there!"), "Whatever.") + + def test_using_acronyms_in_regular_speech(self): + self.assertEqual( + response("It's OK if you don't want to go work for NASA."), "Whatever." + ) + + def test_forceful_question(self): + self.assertEqual( + response("WHAT'S GOING ON?"), "Calm down, I know what I'm doing!" + ) + + def test_shouting_numbers(self): + self.assertEqual(response("1, 2, 3 GO!"), "Whoa, chill out!") + + def test_no_letters(self): + self.assertEqual(response("1, 2, 3"), "Whatever.") + + def test_question_with_no_letters(self): + self.assertEqual(response("4?"), "Sure.") + + def test_shouting_with_special_characters(self): + self.assertEqual( + response("ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!"), + "Whoa, chill out!", + ) + + def test_shouting_with_no_exclamation_mark(self): + self.assertEqual(response("I HATE THE DENTIST"), "Whoa, chill out!") + + def test_statement_containing_question_mark(self): + self.assertEqual(response("Ending with ? means a question."), "Whatever.") + + def test_non_letters_with_question(self): + self.assertEqual(response(":) ?"), "Sure.") + + def test_prattling_on(self): + self.assertEqual(response("Wait! Hang on. Are you going to be OK?"), "Sure.") + + def test_silence(self): + self.assertEqual(response(""), "Fine. Be that way!") + + def test_prolonged_silence(self): + self.assertEqual(response(" "), "Fine. Be that way!") + + def test_alternate_silence(self): + self.assertEqual(response("\t\t\t\t\t\t\t\t\t\t"), "Fine. Be that way!") + + def test_multiple_line_question(self): + self.assertEqual( + response("\nDoes this cryogenic chamber make me look fat?\nNo."), + "Whatever.", + ) + + def test_starting_with_whitespace(self): + self.assertEqual(response(" hmmmmmmm..."), "Whatever.") + + def test_ending_with_whitespace(self): + self.assertEqual( + response("Okay if like my spacebar quite a bit? "), "Sure." + ) + + def test_other_whitespace(self): + self.assertEqual(response("\n\r \t"), "Fine. Be that way!") + + def test_non_question_ending_with_whitespace(self): + self.assertEqual( + response("This is a statement ending with whitespace "), "Whatever." + ) diff --git a/python/little-sisters-vocab/.exercism/config.json b/python/little-sisters-vocab/.exercism/config.json new file mode 100644 index 0000000..2e1cd93 --- /dev/null +++ b/python/little-sisters-vocab/.exercism/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "aldraco", + "BethanyG" + ], + "files": { + "solution": [ + "strings.py" + ], + "test": [ + "strings_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "two-fer", + "blurb": "Learn about strings by helping your little sister with her vocabulary homework." +} diff --git a/python/little-sisters-vocab/.exercism/metadata.json b/python/little-sisters-vocab/.exercism/metadata.json new file mode 100644 index 0000000..80503bc --- /dev/null +++ b/python/little-sisters-vocab/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"little-sisters-vocab","id":"67360f1a7adb4d37ab110d2e3d1dc2fc","url":"https://exercism.org/tracks/python/exercises/little-sisters-vocab","handle":"DanielSiepmann","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/little-sisters-vocab/HELP.md b/python/little-sisters-vocab/HELP.md new file mode 100644 index 0000000..67c4eaa --- /dev/null +++ b/python/little-sisters-vocab/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit strings.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/little-sisters-vocab/HINTS.md b/python/little-sisters-vocab/HINTS.md new file mode 100644 index 0000000..dafc089 --- /dev/null +++ b/python/little-sisters-vocab/HINTS.md @@ -0,0 +1,37 @@ +# Hints + +## General + +- The Python Docs [Tutorial for strings][python-str-doc] has an overview of the Python `str` type. +- String methods [`str.join()`][str-join] and [`str.split()`][str-split] ar very helpful when processing strings. +- The Python Docs on [Sequence Types][common sequence operations] has a rundown of operations common to all sequences, including `strings`, `lists`, `tuples`, and `ranges`. + +There's four activities in the assignment, each with a set of text or words to work with. + +## 1. Add a prefix to a word + +- Small strings can be concatenated with the `+` operator. + +## 2. Add prefixes to word groups + +- Believe it or not, [`str.join()`][str-join] is all you need here. +- Like [`str.split()`][str-split]`, `str.join()` can take an arbitrary-length string, made up of any unicode code points. + +## 3. Remove a suffix from a word + +- Strings can be indexed or sliced from either the left (starting at 0) or the right (starting at -1). +- If you want the last code point of an arbitrary-length string, you can use [-1]. +- The last three letters in a string can be "sliced off" using a negative index. e.g. 'beautiful'[:-3] == 'beauti' + +## 4. Extract and transform a word + +- Using [`str.split()`][str-split] returns a `list` of strings broken on white space. +- `lists` are sequences, and can be indexed. +- [`str.split()`][str-split] can be directly indexed: `'Exercism rocks!'.split()[0] == 'Exercism'` +- Be careful of punctuation! Periods can be removed via slice: `'dark.'[:-1] == 'dark'` + + +[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str +[python-str-doc]: https://docs.python.org/3/tutorial/introduction.html#strings +[str-join]: https://docs.python.org/3/library/stdtypes.html#str.join +[str-split]: https://docs.python.org/3/library/stdtypes.html#str.split \ No newline at end of file diff --git a/python/little-sisters-vocab/README.md b/python/little-sisters-vocab/README.md new file mode 100644 index 0000000..6300a72 --- /dev/null +++ b/python/little-sisters-vocab/README.md @@ -0,0 +1,340 @@ +# Little Sister's Vocabulary + +Welcome to Little Sister's Vocabulary on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +A `str` in Python is an [immutable sequence][text sequence] of [Unicode code points][unicode code points]. +These could include letters, diacritical marks, positioning characters, numbers, currency symbols, emoji, punctuation, space and line break characters, and more. + Being immutable, a `str` object's value in memory doesn't change; methods that appear to modify a string return a new copy or instance of that `str` object. + + +A `str` literal can be declared via single `'` or double `"` quotes. The escape `\` character is available as needed. + + +```python + +>>> single_quoted = 'These allow "double quoting" without "escape" characters.' + +>>> double_quoted = "These allow embedded 'single quoting', so you don't have to use an 'escape' character". + +>>> escapes = 'If needed, a \'slash\' can be used as an escape character within a string when switching quote styles won\'t work.' +``` + +Multi-line strings are declared with `'''` or `"""`. + + +```python +>>> triple_quoted = '''Three single quotes or "double quotes" in a row allow for multi-line string literals. + Line break characters, tabs and other whitespace are fully supported. + + You\'ll most often encounter these as "doc strings" or "doc tests" written just below the first line of a function or class definition. + They\'re often used with auto documentation ✍ tools. + ''' +``` + +Strings can be concatenated using the `+` operator. + This method should be used sparingly, as it is not very performant or easily maintained. + + +```python +language = "Ukrainian" +number = "nine" +word = "дев'ять" + +sentence = word + " " + "means" + " " + number + " in " + language + "." + +>>> print(sentence) +... +"дев'ять means nine in Ukrainian." +``` + +If a `list`, `tuple`, `set` or other collection of individual strings needs to be combined into a single `str`, [`.join()`][str-join], is a better option: + + +```python +# str.join() makes a new string from the iterables elements. +>>> chickens = ["hen", "egg", "rooster"] +>>> ' '.join(chickens) +'hen egg rooster' + +# Any string can be used as the joining element. +>>> ' :: '.join(chickens) +'hen :: egg :: rooster' + +>>> ' 🌿 '.join(chickens) +'hen 🌿 egg 🌿 rooster' +``` + +Code points within a `str` can be referenced by `0-based index` number from the left: + + +```python +creative = '창의적인' + +>>> creative[0] +'창' + +>>> creative[2] +'적' + +>>> creative[3] +'인' +``` + +Indexing also works from the right, starting with a `-1-based index`: + + +```python +creative = '창의적인' + +>>> creative[-4] +'창' + +>>> creative[-2] +'적' + +>>> creative[-1] +'인' + +``` + + +There is no separate “character” or "rune" type in Python, so indexing a string produces a new `str` of length 1: + + +```python + +>>> website = "exercism" +>>> type(website[0]) + + +>>> len(website[0]) +1 + +>>> website[0] == website[0:1] == 'e' +True +``` + +Substrings can be selected via _slice notation_, using [`[:stop:]`][common sequence operations] to produce a new string. + Results exclude the `stop` index. + If no `start` is given, the starting index will be 0. + If no `stop` is given, the `stop` index will be the end of the string. + + +```python +moon_and_stars = '🌟🌟🌙🌟🌟⭐' +sun_and_moon = '🌞🌙🌞🌙🌞🌙🌞🌙🌞' + +>>> moon_and_stars[1:4] +'🌟🌙🌟' + +>>> moon_and_stars[:3] +'🌟🌟🌙' + +>>> moon_and_stars[3:] +'🌟🌟⭐' + +>>> moon_and_stars[:-1] +'🌟🌟🌙🌟🌟' + +>>> moon_and_stars[:-3] +'🌟🌟🌙' + +>>> sun_and_moon[::2] +'🌞🌞🌞🌞🌞' + +>>> sun_and_moon[:-2:2] +'🌞🌞🌞🌞' + +>>> sun_and_moon[1:-1:2] +'🌙🌙🌙🌙' +``` + +Strings can also be broken into smaller strings via [`.split()`][str-split], which will return a `list` of substrings. + The list can then be further indexed or split, if needed. + Using `.split()` without any arguments will split the string on whitespace. + + +```python +>>> cat_ipsum = "Destroy house in 5 seconds mock the hooman." +>>> cat_ipsum.split() +... +['Destroy', 'house', 'in', '5', 'seconds', 'mock', 'the', 'hooman.'] + + +>>> cat_ipsum.split()[-1] +'hooman.' + + +>>> cat_words = "feline, four-footed, ferocious, furry" +>>> cat_words.split(', ') +... +['feline', 'four-footed', 'ferocious', 'furry'] +``` + + +Separators for `.split()` can be more than one character. +The **whole string** is used for split matching. + + +```python + +>>> colors = """red, +orange, +green, +purple, +yellow""" + +>>> colors.split(',\n') +['red', 'orange', 'green', 'purple', 'yellow'] +``` + +Strings support all [common sequence operations][common sequence operations]. + Individual code points can be iterated through in a loop via `for item in `. + Indexes _with_ items can be iterated through in a loop via `for index, item in enumerate()`. + + +```python + +>>> exercise = 'လေ့ကျင့်' + +# Note that there are more code points than perceived glyphs or characters +>>> for code_point in exercise: +... print(code_point) +... +လ +ေ +့ +က +ျ +င +် +့ + +# Using enumerate will give both the value and index position of each element. +>>> for index, code_point in enumerate(exercise): +... print(index, ": ", code_point) +... +0 : လ +1 : ေ +2 : ့ +3 : က +4 : ျ +5 : င +6 : ် +7 : ့ +``` + + +[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#common-sequence-operations +[str-join]: https://docs.python.org/3/library/stdtypes.html#str.join +[str-split]: https://docs.python.org/3/library/stdtypes.html#str.split +[text sequence]: https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str +[unicode code points]: https://stackoverflow.com/questions/27331819/whats-the-difference-between-a-character-a-code-point-a-glyph-and-a-grapheme + +## Instructions + +You are helping your younger sister with her English vocabulary homework, which she is finding very tedious. + Her class is learning to create new words by adding _prefixes_ and _suffixes_. + Given a set of words, the teacher is looking for correctly transformed words with correct spelling by adding the prefix to the beginning or the suffix to the ending. + +There's four activities in the assignment, each with a set of text or words to work with. + + +## 1. Add a prefix to a word + +One of the most common prefixes in English is `un`, meaning "not". + In this activity, your sister needs to make negative, or "not" words by adding `un` to them. + +Implement the `add_prefix_un()` function that takes `word` as a parameter and returns a new `un` prefixed word: + + +```python +>>> add_prefix_un("happy") +'unhappy' + +>>> add_prefix_un("manageable") +'unmanageable' +``` + + +## 2. Add prefixes to word groups + +There are four more common prefixes that your sister's class is studying: + `en` (_meaning to 'put into' or 'cover with'_), + `pre` (_meaning 'before' or 'forward'_), + `auto` (_meaning 'self' or 'same'_), + and `inter` (_meaning 'between' or 'among'_). + + In this exercise, the class is creating groups of vocabulary words using these prefixes, so they can be studied together. + Each prefix comes in a list with common words it's used with. + The students need to apply the prefix and produce a string that shows the prefix applied to all of the words. + +Implement the `make_word_groups()` function that takes a `vocab_words` as a parameter in the following form: + `[, , .... ]`, and returns a string with the prefix applied to each word that looks like: + `' :: :: :: '`. + + +```python +>>> make_word_groups(['en', 'close', 'joy', 'lighten']) +'en :: enclose :: enjoy :: enlighten' + +>>> make_word_groups(['pre', 'serve', 'dispose', 'position']) +'pre :: preserve :: predispose :: preposition' + +>> make_word_groups(['auto', 'didactic', 'graph', 'mate']) +'auto :: autodidactic :: autograph :: automate' + +>>> make_word_groups(['inter', 'twine', 'connected', 'dependent']) +'inter :: intertwine :: interconnected :: interdependent' +``` + + +## 3. Remove a suffix from a word + +`ness` is a common suffix that means _'state of being'_. + In this activity, your sister needs to find the original root word by removing the `ness` suffix. + But of course there are pesky spelling rules: If the root word originally ended in a consonant followed by a 'y', then the 'y' was changed to 'i'. + Removing 'ness' needs to restore the 'y' in those root words. e.g. `happiness` --> `happi` --> `happy`. + +Implement the `remove_suffix_ness()` function that takes in a `word`, and returns the root word without the `ness` suffix. + + +```python +>>> remove_suffix_ness("heaviness") +'heavy' + +>>> remove_suffix_ness("sadness") +'sad' +``` + +## 4. Extract and transform a word + +Suffixes are often used to change the part of speech a word is assigned to. + A common practice in English is "verbing" or "verbifying" -- where an adjective _becomes_ a verb by adding an `en` suffix. + +In this task, your sister is going to practice "verbing" words by extracting an adjective from a sentence and turning it into a verb. + Fortunately, all the words that need to be transformed here are "regular" - they don't need spelling changes to add the suffix. + +Implement the `adjective_to_verb(, )` function that takes two parameters. + A `sentence` using the vocabulary word, and the `index` of the word, once that sentence is split apart. + The function should return the extracted adjective as a verb. + + +```python +>>> adjective_to_verb('I need to make that bright.', -1 ) +'brighten' + +>>> adjective_to_verb('It got dark as the sun set.', 2) +'darken' +``` + +## Source + +### Created by + +- @aldraco +- @BethanyG \ No newline at end of file diff --git a/python/little-sisters-vocab/strings.py b/python/little-sisters-vocab/strings.py new file mode 100644 index 0000000..39ae7bb --- /dev/null +++ b/python/little-sisters-vocab/strings.py @@ -0,0 +1,54 @@ +"""Functions for creating, transforming, and adding prefixes to strings.""" + + +def add_prefix_un(word): + """Take the given word and add the 'un' prefix. + + :param word: str - containing the root word. + :return: str - of root word prepended with 'un'. + """ + + pass + + +def make_word_groups(vocab_words): + """Transform a list containing a prefix and words into a string with the prefix followed by the words with prefix prepended. + + :param vocab_words: list - of vocabulary words with prefix in first index. + :return: str - of prefix followed by vocabulary words with + prefix applied. + + This function takes a `vocab_words` list and returns a string + with the prefix and the words with prefix applied, separated + by ' :: '. + + For example: list('en', 'close', 'joy', 'lighten'), + produces the following string: 'en :: enclose :: enjoy :: enlighten'. + """ + + pass + + +def remove_suffix_ness(word): + """Remove the suffix from the word while keeping spelling in mind. + + :param word: str - of word to remove suffix from. + :return: str - of word with suffix removed & spelling adjusted. + + For example: "heaviness" becomes "heavy", but "sadness" becomes "sad". + """ + + pass + + +def adjective_to_verb(sentence, index): + """Change the adjective within the sentence to a verb. + + :param sentence: str - that uses the word in sentence. + :param index: int - index of the word to remove and transform. + :return: str - word that changes the extracted adjective to a verb. + + For example, ("It got dark as the sun set.", 2) becomes "darken". + """ + + pass diff --git a/python/little-sisters-vocab/strings_test.py b/python/little-sisters-vocab/strings_test.py new file mode 100644 index 0000000..b13d4e9 --- /dev/null +++ b/python/little-sisters-vocab/strings_test.py @@ -0,0 +1,126 @@ +import unittest +import pytest +from strings import (add_prefix_un, + make_word_groups, + remove_suffix_ness, + adjective_to_verb) + + +class LittleSistersVocabTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_add_prefix_un(self): + input_data = ['happy', 'manageable', 'fold', 'eaten', 'avoidable', 'usual'] + result_data = [f'un{item}' for item in input_data] + + for variant, (word, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', word=word, expected=expected): + + actual_result = add_prefix_un(word) + error_message = (f'Called add_prefix_un("{word}"). ' + f'The function returned "{actual_result}", but the ' + f'tests expected "{expected}" after adding "un" as a prefix.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_make_word_groups_en(self): + input_data = ['en', 'circle', 'fold', 'close', 'joy', 'lighten', 'tangle', 'able', 'code', 'culture'] + expected = ('en :: encircle :: enfold :: enclose :: enjoy :: enlighten ::' + ' entangle :: enable :: encode :: enculture') + + actual_result = make_word_groups(input_data) + error_message = (f'Called make_word_groups({input_data}). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" for the ' + 'word groups.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_make_word_groups_pre(self): + input_data = ['pre', 'serve', 'dispose', 'position', 'requisite', 'digest', + 'natal', 'addressed', 'adolescent', 'assumption', 'mature', 'compute'] + expected = ('pre :: preserve :: predispose :: preposition :: prerequisite :: ' + 'predigest :: prenatal :: preaddressed :: preadolescent :: preassumption :: ' + 'premature :: precompute') + + actual_result = make_word_groups(input_data) + error_message = (f'Called make_word_groups({input_data}). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" for the ' + 'word groups.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_make_word_groups_auto(self): + input_data = ['auto', 'didactic', 'graph', 'mate', 'chrome', 'centric', 'complete', + 'echolalia', 'encoder', 'biography'] + expected = ('auto :: autodidactic :: autograph :: automate :: autochrome :: ' + 'autocentric :: autocomplete :: autoecholalia :: autoencoder :: ' + 'autobiography') + + actual_result = make_word_groups(input_data) + error_message = (f'Called make_word_groups({input_data}). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" for the ' + 'word groups.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_make_words_groups_inter(self): + input_data = ['inter', 'twine', 'connected', 'dependent', 'galactic', 'action', + 'stellar', 'cellular', 'continental', 'axial', 'operative', 'disciplinary'] + expected = ('inter :: intertwine :: interconnected :: interdependent :: ' + 'intergalactic :: interaction :: interstellar :: intercellular :: ' + 'intercontinental :: interaxial :: interoperative :: interdisciplinary') + + actual_result = make_word_groups(input_data) + error_message = (f'Called make_word_groups({input_data}). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" for the ' + 'word groups.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_remove_suffix_ness(self): + input_data = ['heaviness', 'sadness', 'softness', 'crabbiness', 'lightness', 'artiness', 'edginess'] + result_data = ['heavy', 'sad', 'soft', 'crabby', 'light', 'arty', 'edgy'] + + for variant, (word, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', word=word, expected=expected): + actual_result = remove_suffix_ness(word) + error_message = (f'Called remove_suffix_ness("{word}"). ' + f'The function returned "{actual_result}", ' + f'but the tests expected "{expected}" after the ' + 'suffix was removed.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_adjective_to_verb(self): + input_data = ['Look at the bright sky.', + 'His expression went dark.', + 'The bread got hard after sitting out.', + 'The butter got soft in the sun.', + 'Her eyes were light blue.', + 'The morning fog made everything damp with mist.', + 'He cut the fence pickets short by mistake.', + 'Charles made weak crying noises.', + 'The black oil got on the white dog.'] + index_data = [-2, -1, 3, 3, -2, -3, 5, 2, 1] + result_data = ['brighten', 'darken', 'harden', 'soften', + 'lighten', 'dampen', 'shorten', 'weaken', 'blacken'] + + for variant, (sentence, index, expected) in enumerate(zip(input_data, index_data, result_data), start=1): + with self.subTest(f'variation #{variant}', sentence=sentence, index=index, expected=expected): + actual_result = adjective_to_verb(sentence, index) + error_message = (f'Called adjective_to_verb("{sentence}", {index}). ' + f'The function returned "{actual_result}", but the tests ' + f'expected "{expected}" as the verb for ' + f'the word at index {index}.') + + self.assertEqual(actual_result, expected, msg=error_message) diff --git a/python/pig-latin/.exercism/config.json b/python/pig-latin/.exercism/config.json new file mode 100644 index 0000000..6dd8c46 --- /dev/null +++ b/python/pig-latin/.exercism/config.json @@ -0,0 +1,30 @@ +{ + "authors": [ + "behrtam" + ], + "contributors": [ + "akashsara", + "cmccandless", + "Dog", + "ikhadykin", + "N-Parsons", + "pheanex", + "Sukhj1nder", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "pig_latin.py" + ], + "test": [ + "pig_latin_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Implement a program that translates from English to Pig Latin.", + "source": "The Pig Latin exercise at Test First Teaching by Ultrasaurus", + "source_url": "https://github.com/ultrasaurus/test-first-teaching/blob/master/learn_ruby/pig_latin/" +} diff --git a/python/pig-latin/.exercism/metadata.json b/python/pig-latin/.exercism/metadata.json new file mode 100644 index 0000000..dd21b43 --- /dev/null +++ b/python/pig-latin/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"pig-latin","id":"3f746fd8371241dca8d222d21db49a7b","url":"https://exercism.org/tracks/python/exercises/pig-latin","handle":"DanielSiepmann","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/pig-latin/HELP.md b/python/pig-latin/HELP.md new file mode 100644 index 0000000..2972102 --- /dev/null +++ b/python/pig-latin/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit pig_latin.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/pig-latin/README.md b/python/pig-latin/README.md new file mode 100644 index 0000000..a041633 --- /dev/null +++ b/python/pig-latin/README.md @@ -0,0 +1,47 @@ +# Pig Latin + +Welcome to Pig Latin on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Implement a program that translates from English to Pig Latin. + +Pig Latin is a made-up children's language that's intended to be confusing. +It obeys a few simple rules (below), but when it's spoken quickly it's really difficult for non-children (and non-native speakers) to understand. + +- **Rule 1**: If a word begins with a vowel sound, add an "ay" sound to the end of the word. + Please note that "xr" and "yt" at the beginning of a word make vowel sounds (e.g. "xray" -> "xrayay", "yttria" -> "yttriaay"). +- **Rule 2**: If a word begins with a consonant sound, move it to the end of the word and then add an "ay" sound to the end of the word. + Consonant sounds can be made up of multiple consonants, such as the "ch" in "chair" or "st" in "stand" (e.g. "chair" -> "airchay"). +- **Rule 3**: If a word starts with a consonant sound followed by "qu", move it to the end of the word, and then add an "ay" sound to the end of the word (e.g. "square" -> "aresquay"). +- **Rule 4**: If a word contains a "y" after a consonant cluster or as the second letter in a two letter word it makes a vowel sound (e.g. "rhythm" -> "ythmrhay", "my" -> "ymay"). + +There are a few more rules for edge cases, and there are regional variants too. +Check the tests for all the details. + +Read more about [Pig Latin on Wikipedia][pig-latin]. + +[pig-latin]: https://en.wikipedia.org/wiki/Pig_latin + +## Source + +### Created by + +- @behrtam + +### Contributed to by + +- @akashsara +- @cmccandless +- @Dog +- @ikhadykin +- @N-Parsons +- @pheanex +- @Sukhj1nder +- @tqa236 +- @yawpitch + +### Based on + +The Pig Latin exercise at Test First Teaching by Ultrasaurus - https://github.com/ultrasaurus/test-first-teaching/blob/master/learn_ruby/pig_latin/ \ No newline at end of file diff --git a/python/pig-latin/pig_latin.py b/python/pig-latin/pig_latin.py new file mode 100644 index 0000000..dda3f07 --- /dev/null +++ b/python/pig-latin/pig_latin.py @@ -0,0 +1,2 @@ +def translate(text): + pass diff --git a/python/pig-latin/pig_latin_test.py b/python/pig-latin/pig_latin_test.py new file mode 100644 index 0000000..e5a441e --- /dev/null +++ b/python/pig-latin/pig_latin_test.py @@ -0,0 +1,77 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/pig-latin/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from pig_latin import ( + translate, +) + + +class PigLatinTest(unittest.TestCase): + def test_word_beginning_with_a(self): + self.assertEqual(translate("apple"), "appleay") + + def test_word_beginning_with_e(self): + self.assertEqual(translate("ear"), "earay") + + def test_word_beginning_with_i(self): + self.assertEqual(translate("igloo"), "iglooay") + + def test_word_beginning_with_o(self): + self.assertEqual(translate("object"), "objectay") + + def test_word_beginning_with_u(self): + self.assertEqual(translate("under"), "underay") + + def test_word_beginning_with_a_vowel_and_followed_by_a_qu(self): + self.assertEqual(translate("equal"), "equalay") + + def test_word_beginning_with_p(self): + self.assertEqual(translate("pig"), "igpay") + + def test_word_beginning_with_k(self): + self.assertEqual(translate("koala"), "oalakay") + + def test_word_beginning_with_x(self): + self.assertEqual(translate("xenon"), "enonxay") + + def test_word_beginning_with_q_without_a_following_u(self): + self.assertEqual(translate("qat"), "atqay") + + def test_word_beginning_with_ch(self): + self.assertEqual(translate("chair"), "airchay") + + def test_word_beginning_with_qu(self): + self.assertEqual(translate("queen"), "eenquay") + + def test_word_beginning_with_qu_and_a_preceding_consonant(self): + self.assertEqual(translate("square"), "aresquay") + + def test_word_beginning_with_th(self): + self.assertEqual(translate("therapy"), "erapythay") + + def test_word_beginning_with_thr(self): + self.assertEqual(translate("thrush"), "ushthray") + + def test_word_beginning_with_sch(self): + self.assertEqual(translate("school"), "oolschay") + + def test_word_beginning_with_yt(self): + self.assertEqual(translate("yttria"), "yttriaay") + + def test_word_beginning_with_xr(self): + self.assertEqual(translate("xray"), "xrayay") + + def test_y_is_treated_like_a_consonant_at_the_beginning_of_a_word(self): + self.assertEqual(translate("yellow"), "ellowyay") + + def test_y_is_treated_like_a_vowel_at_the_end_of_a_consonant_cluster(self): + self.assertEqual(translate("rhythm"), "ythmrhay") + + def test_y_as_second_letter_in_two_letter_word(self): + self.assertEqual(translate("my"), "ymay") + + def test_a_whole_phrase(self): + self.assertEqual(translate("quick fast run"), "ickquay astfay unray") diff --git a/python/raindrops/.exercism/config.json b/python/raindrops/.exercism/config.json new file mode 100644 index 0000000..70763b8 --- /dev/null +++ b/python/raindrops/.exercism/config.json @@ -0,0 +1,32 @@ +{ + "authors": [], + "contributors": [ + "behrtam", + "BethanyG", + "bsoyka", + "cmccandless", + "Dog", + "ikhadykin", + "kytrinyx", + "lowks", + "N-Parsons", + "pheanex", + "sjakobi", + "tqa236", + "yawpitch" + ], + "files": { + "solution": [ + "raindrops.py" + ], + "test": [ + "raindrops_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Convert a number into its corresponding raindrop sounds - Pling, Plang and Plong.", + "source": "A variation on FizzBuzz, a famous technical interview question that is intended to weed out potential candidates. That question is itself derived from Fizz Buzz, a popular children's game for teaching division.", + "source_url": "https://en.wikipedia.org/wiki/Fizz_buzz" +} diff --git a/python/raindrops/.exercism/metadata.json b/python/raindrops/.exercism/metadata.json new file mode 100644 index 0000000..fc0ae25 --- /dev/null +++ b/python/raindrops/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"raindrops","id":"00ec103661614e07b410af1f21c48a65","url":"https://exercism.org/tracks/python/exercises/raindrops","handle":"DanielSiepmann","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/raindrops/HELP.md b/python/raindrops/HELP.md new file mode 100644 index 0000000..8739752 --- /dev/null +++ b/python/raindrops/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit raindrops.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/raindrops/README.md b/python/raindrops/README.md new file mode 100644 index 0000000..e0b0ddd --- /dev/null +++ b/python/raindrops/README.md @@ -0,0 +1,75 @@ +# Raindrops + +Welcome to Raindrops on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +Raindrops is a slightly more complex version of the FizzBuzz challenge, a classic interview question. + +## Instructions + +Your task is to convert a number into its corresponding raindrop sounds. + +If a given number: + +- is divisible by 3, add "Pling" to the result. +- is divisible by 5, add "Plang" to the result. +- is divisible by 7, add "Plong" to the result. +- **is not** divisible by 3, 5, or 7, the result should be the number as a string. + +## Examples + +- 28 is divisible by 7, but not 3 or 5, so the result would be `"Plong"`. +- 30 is divisible by 3 and 5, but not 7, so the result would be `"PlingPlang"`. +- 34 is not divisible by 3, 5, or 7, so the result would be `"34"`. + +~~~~exercism/note +A common way to test if one number is evenly divisible by another is to compare the [remainder][remainder] or [modulus][modulo] to zero. +Most languages provide operators or functions for one (or both) of these. + +[remainder]: https://exercism.org/docs/programming/operators/remainder +[modulo]: https://en.wikipedia.org/wiki/Modulo_operation +~~~~ + +## How this Exercise is Structured in Python + +This exercise is best solved with Python's `%` ([modulo][modulo]) operator, which returns the remainder of positive integer division. +It has a method equivalent, `operator.mod()` in the [operator module][operator-mod]. + + +Python also offers additional 'remainder' methods in the [math module][math-module]. +[`math.fmod()`][fmod] behaves like `%`, but operates on floats. +[`math.remainder()`][remainder] implements a "step closest to zero" algorithm for the remainder of division. +While we encourage you to get familiar with these methods, neither of these will exactly match the result of `%`, and are not recommended for use with this exercise. + +The built-in function [`divmod()`][divmod] will also give a remainder than matches `%` if used with two positive integers, but returns a `tuple` that needs to be unpacked. + +[divmod]: https://docs.python.org/3/library/functions.html#divmod +[fmod]: https://docs.python.org/3/library/math.html#math.fmod +[math-module]: https://docs.python.org/3/library/math.html +[modulo]: https://www.programiz.com/python-programming/operators#arithmetic +[operator-mod]: https://docs.python.org/3/library/operator.html#operator.mod +[remainder]: https://docs.python.org/3/library/math.html#math.remainder + +## Source + +### Contributed to by + +- @behrtam +- @BethanyG +- @bsoyka +- @cmccandless +- @Dog +- @ikhadykin +- @kytrinyx +- @lowks +- @N-Parsons +- @pheanex +- @sjakobi +- @tqa236 +- @yawpitch + +### Based on + +A variation on FizzBuzz, a famous technical interview question that is intended to weed out potential candidates. That question is itself derived from Fizz Buzz, a popular children's game for teaching division. - https://en.wikipedia.org/wiki/Fizz_buzz \ No newline at end of file diff --git a/python/raindrops/raindrops.py b/python/raindrops/raindrops.py new file mode 100644 index 0000000..f38f3b6 --- /dev/null +++ b/python/raindrops/raindrops.py @@ -0,0 +1,2 @@ +def convert(number): + pass diff --git a/python/raindrops/raindrops_test.py b/python/raindrops/raindrops_test.py new file mode 100644 index 0000000..b07e70d --- /dev/null +++ b/python/raindrops/raindrops_test.py @@ -0,0 +1,67 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/raindrops/canonical-data.json +# File last updated on 2023-07-19 + +import unittest + +from raindrops import ( + convert, +) + + +class RaindropsTest(unittest.TestCase): + def test_the_sound_for_1_is_1(self): + self.assertEqual(convert(1), "1") + + def test_the_sound_for_3_is_pling(self): + self.assertEqual(convert(3), "Pling") + + def test_the_sound_for_5_is_plang(self): + self.assertEqual(convert(5), "Plang") + + def test_the_sound_for_7_is_plong(self): + self.assertEqual(convert(7), "Plong") + + def test_the_sound_for_6_is_pling_as_it_has_a_factor_3(self): + self.assertEqual(convert(6), "Pling") + + def test_2_to_the_power_3_does_not_make_a_raindrop_sound_as_3_is_the_exponent_not_the_base( + self, + ): + self.assertEqual(convert(8), "8") + + def test_the_sound_for_9_is_pling_as_it_has_a_factor_3(self): + self.assertEqual(convert(9), "Pling") + + def test_the_sound_for_10_is_plang_as_it_has_a_factor_5(self): + self.assertEqual(convert(10), "Plang") + + def test_the_sound_for_14_is_plong_as_it_has_a_factor_of_7(self): + self.assertEqual(convert(14), "Plong") + + def test_the_sound_for_15_is_pling_plang_as_it_has_factors_3_and_5(self): + self.assertEqual(convert(15), "PlingPlang") + + def test_the_sound_for_21_is_pling_plong_as_it_has_factors_3_and_7(self): + self.assertEqual(convert(21), "PlingPlong") + + def test_the_sound_for_25_is_plang_as_it_has_a_factor_5(self): + self.assertEqual(convert(25), "Plang") + + def test_the_sound_for_27_is_pling_as_it_has_a_factor_3(self): + self.assertEqual(convert(27), "Pling") + + def test_the_sound_for_35_is_plang_plong_as_it_has_factors_5_and_7(self): + self.assertEqual(convert(35), "PlangPlong") + + def test_the_sound_for_49_is_plong_as_it_has_a_factor_7(self): + self.assertEqual(convert(49), "Plong") + + def test_the_sound_for_52_is_52(self): + self.assertEqual(convert(52), "52") + + def test_the_sound_for_105_is_pling_plang_plong_as_it_has_factors_3_5_and_7(self): + self.assertEqual(convert(105), "PlingPlangPlong") + + def test_the_sound_for_3125_is_plang_as_it_has_a_factor_5(self): + self.assertEqual(convert(3125), "Plang")