Add new exercises for python

This commit is contained in:
Daniel Siepmann 2024-03-25 10:10:25 +01:00
parent 164a2443de
commit e6c7977320
Signed by: Daniel Siepmann
GPG key ID: 33D6629915560EF4
32 changed files with 2448 additions and 0 deletions

View file

@ -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."
}

View file

@ -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}

130
python/black-jack/HELP.md Normal file
View file

@ -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}
```
<br>
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.

View file

@ -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

395
python/black-jack/README.md Normal file
View file

@ -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.
`<apple> is <orange>` evaluates to `True` if _**and only if**_ `id(<apple>)` == `id(<orange>)`.
`<apple> is not <orange>` 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_.
`<fish> in <soup>` evaluates to `True` if `<fish>` is a member of `<soup>` (_if `<fish>` is a subset of or is contained within `<soup>`_), and evaluates `False` otherwise.
`<fish> not in <soup>` returns the negation, or _opposite of_ `<fish> in <soup>`.
For string and bytes types, `<name> in <fullname>` is `True` _**if and only if**_ `<name>` is a substring of `<fullname>`.
```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(<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(<card_one>, <card_two>)` 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(<card_one>, <card_two>)` 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(<card_one>, <card_two>)` 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(<card_one>, <card_two>)` 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(<card_one>, <card_two>)` 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

View file

@ -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

View file

@ -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)

View file

@ -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"
}

View file

@ -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}

130
python/bob/HELP.md Normal file
View file

@ -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}
```
<br>
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.

72
python/bob/README.md Normal file
View file

@ -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

2
python/bob/bob.py Normal file
View file

@ -0,0 +1,2 @@
def response(hey_bob):
pass

102
python/bob/bob_test.py Normal file
View file

@ -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."
)

View file

@ -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."
}

View file

@ -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}

View file

@ -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}
```
<br>
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.

View file

@ -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

View file

@ -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`, [`<str>.join(<iterable>)`][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])
<class 'str'>
>>> len(website[0])
1
>>> website[0] == website[0:1] == 'e'
True
```
Substrings can be selected via _slice notation_, using [`<str>[<start>:stop:<step>]`][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 [`<str>.split(<separator>)`][str-split], which will return a `list` of substrings.
The list can then be further indexed or split, if needed.
Using `<str>.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 `<str>.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 <str>`.
Indexes _with_ items can be iterated through in a loop via `for index, item in enumerate(<str>)`.
```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(<word>)` 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(<vocab_words>)` function that takes a `vocab_words` as a parameter in the following form:
`[<prefix>, <word_1>, <word_2> .... <word_n>]`, and returns a string with the prefix applied to each word that looks like:
`'<prefix> :: <prefix><word_1> :: <prefix><word_2> :: <prefix><word_n>'`.
```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(<word>)` 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(<sentence>, <index>)` 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

View file

@ -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

View file

@ -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)

View file

@ -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/"
}

View file

@ -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}

130
python/pig-latin/HELP.md Normal file
View file

@ -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}
```
<br>
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.

View file

@ -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/

View file

@ -0,0 +1,2 @@
def translate(text):
pass

View file

@ -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")

View file

@ -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"
}

View file

@ -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}

130
python/raindrops/HELP.md Normal file
View file

@ -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}
```
<br>
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.

View file

@ -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

View file

@ -0,0 +1,2 @@
def convert(number):
pass

View file

@ -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")