mirror of
https://codeberg.org/andyscott/exercism.git
synced 2024-12-22 06:43:09 -05:00
Compare commits
2 commits
f6384f3c7a
...
9cfecd833c
Author | SHA1 | Date | |
---|---|---|---|
9cfecd833c | |||
9750e8d9ef |
14 changed files with 1339 additions and 0 deletions
27
python/black-jack/.exercism/config.json
Normal file
27
python/black-jack/.exercism/config.json
Normal 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."
|
||||||
|
}
|
1
python/black-jack/.exercism/metadata.json
Normal file
1
python/black-jack/.exercism/metadata.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"track":"python","exercise":"black-jack","id":"c39a445c45914cf69f9cd468976225b8","url":"https://exercism.org/tracks/python/exercises/black-jack","handle":"Chomp1295","is_requester":true,"auto_approve":false}
|
130
python/black-jack/HELP.md
Normal file
130
python/black-jack/HELP.md
Normal 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.
|
45
python/black-jack/HINTS.md
Normal file
45
python/black-jack/HINTS.md
Normal 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
395
python/black-jack/README.md
Normal 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 a player is dealt an ace (`A`) and a ten-card (10, `K`, `Q`, or `J`) as their first two cards, 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
|
110
python/black-jack/black_jack.py
Normal file
110
python/black-jack/black_jack.py
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
"""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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
res = 0
|
||||||
|
if card >= "J":
|
||||||
|
res = 10
|
||||||
|
elif card == "A":
|
||||||
|
res = 1
|
||||||
|
else:
|
||||||
|
res = int(card)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
card_one_val = value_of_card(card_one)
|
||||||
|
card_two_val = value_of_card(card_two)
|
||||||
|
|
||||||
|
if card_one_val == card_two_val:
|
||||||
|
return (card_one, card_two)
|
||||||
|
|
||||||
|
if card_one_val > card_two_val:
|
||||||
|
return card_one
|
||||||
|
|
||||||
|
return card_two
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if (value_of_card(card_one) + value_of_card(card_two) >= 11) or "A" in (
|
||||||
|
card_one,
|
||||||
|
card_two,
|
||||||
|
):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
return 11
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if card_one != "A" and card_two != "A":
|
||||||
|
return False
|
||||||
|
|
||||||
|
if card_one == "A":
|
||||||
|
return value_of_card(card_two) + 11 == 21
|
||||||
|
|
||||||
|
return value_of_card(card_one) + 11 == 21
|
||||||
|
|
||||||
|
|
||||||
|
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).
|
||||||
|
"""
|
||||||
|
|
||||||
|
return value_of_card(card_one) == value_of_card(card_two)
|
||||||
|
|
||||||
|
|
||||||
|
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).
|
||||||
|
"""
|
||||||
|
|
||||||
|
return 9 <= value_of_card(card_one) + value_of_card(card_two) <= 11
|
114
python/black-jack/black_jack_test.py
Normal file
114
python/black-jack/black_jack_test.py
Normal 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)
|
22
python/little-sisters-essay/.exercism/config.json
Normal file
22
python/little-sisters-essay/.exercism/config.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"authors": [
|
||||||
|
"kimolivia"
|
||||||
|
],
|
||||||
|
"contributors": [
|
||||||
|
"valentin-p",
|
||||||
|
"BethanyG"
|
||||||
|
],
|
||||||
|
"files": {
|
||||||
|
"solution": [
|
||||||
|
"string_methods.py"
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
"string_methods_test.py"
|
||||||
|
],
|
||||||
|
"exemplar": [
|
||||||
|
".meta/exemplar.py"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"icon": "anagrams",
|
||||||
|
"blurb": "Learn about string methods while improving your little sister's school essay."
|
||||||
|
}
|
1
python/little-sisters-essay/.exercism/metadata.json
Normal file
1
python/little-sisters-essay/.exercism/metadata.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"track":"python","exercise":"little-sisters-essay","id":"68b15f3f00a4425db54965e6136896c1","url":"https://exercism.org/tracks/python/exercises/little-sisters-essay","handle":"Chomp1295","is_requester":true,"auto_approve":false}
|
130
python/little-sisters-essay/HELP.md
Normal file
130
python/little-sisters-essay/HELP.md
Normal 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 string_methods.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.
|
29
python/little-sisters-essay/HINTS.md
Normal file
29
python/little-sisters-essay/HINTS.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Hints
|
||||||
|
|
||||||
|
## General
|
||||||
|
|
||||||
|
- [Python Documentation: String Methods][string-method-docs]
|
||||||
|
- [Python Documentation Tutorial: Text][tutorial-strings]
|
||||||
|
|
||||||
|
## 1. Capitalize the title of the paper
|
||||||
|
|
||||||
|
- You can use [string methods][title-method-docs] to capitalize the title properly.
|
||||||
|
|
||||||
|
## 2. Check if each sentence ends with a period
|
||||||
|
|
||||||
|
- You can use [string methods][endswith-method-docs] to check the ending of a string.
|
||||||
|
|
||||||
|
## 3. Clean up spacing
|
||||||
|
|
||||||
|
- You can use [string methods][strip-method-docs] to remove whitespace.
|
||||||
|
|
||||||
|
## 4. Replace words with a synonym
|
||||||
|
|
||||||
|
- You can use [string methods][replace-method-docs] to replace words.
|
||||||
|
|
||||||
|
[endswith-method-docs]: https://docs.python.org/3/library/stdtypes.html#str.endswith
|
||||||
|
[replace-method-docs]: https://docs.python.org/3/library/stdtypes.html#str.replace
|
||||||
|
[string-method-docs]: https://docs.python.org/3/library/stdtypes.html#string-methods
|
||||||
|
[strip-method-docs]: https://docs.python.org/3/library/stdtypes.html#str.strip
|
||||||
|
[title-method-docs]: https://docs.python.org/3/library/stdtypes.html#str.title
|
||||||
|
[tutorial-strings]: https://docs.python.org/3/tutorial/introduction.html#text
|
194
python/little-sisters-essay/README.md
Normal file
194
python/little-sisters-essay/README.md
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
# Little Sister's Essay
|
||||||
|
|
||||||
|
Welcome to Little Sister's Essay 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
|
||||||
|
|
||||||
|
The `str` class offers [many useful methods][str methods] for working with and composing strings.
|
||||||
|
These include searching, cleaning, splitting, transforming, translating, and many other techniques.
|
||||||
|
|
||||||
|
Strings are [immutable sequences][text sequence] of [Unicode code points][unicode code points] -- individual "characters" or code points (_strings of length 1_) can be referenced by `0-based index` number from the left, or `-1-based index` number from the right.
|
||||||
|
|
||||||
|
Strings can be iterated through using `for item in <str>` or `for index, item in enumerate(<str>)` syntax.
|
||||||
|
They can be concatenated using the `+` operator or via `<string>.join(<iterable>)` and implement all [common sequence operations][common sequence operations].
|
||||||
|
|
||||||
|
Strings are _immutable_, meaning the value of a `str` object in memory cannot change.
|
||||||
|
Functions or methods that operate on a `str` (_like the ones we are learning about here_) will return a new `instance` of that `str` object instead of modifying the original `str`.
|
||||||
|
|
||||||
|
Following is a small selection of Python string methods.
|
||||||
|
For a complete list, see the [str class][str methods] in the Python docs.
|
||||||
|
|
||||||
|
|
||||||
|
[`<str>.title()`][str-title] parses a string and capitalizes the first "character" of each "word" found.
|
||||||
|
In Python, this is very dependent on the [language codec][codecs] used and how the particular language represents words and characters.
|
||||||
|
There may also be [locale][locale] rules in place for a language or character set.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
man_in_hat_th = 'ผู้ชายใส่หมวก'
|
||||||
|
man_in_hat_ru = 'мужчина в шляпе'
|
||||||
|
man_in_hat_ko = '모자를 쓴 남자'
|
||||||
|
man_in_hat_en = 'the man in the hat.'
|
||||||
|
|
||||||
|
>>> man_in_hat_th.title()
|
||||||
|
'ผู้ชายใส่หมวก'
|
||||||
|
|
||||||
|
>>> man_in_hat_ru.title()
|
||||||
|
'Мужчина В Шляпе'
|
||||||
|
|
||||||
|
>>> man_in_hat_ko.title()
|
||||||
|
'모자를 쓴 남자'
|
||||||
|
|
||||||
|
>> man_in_hat_en.title()
|
||||||
|
'The Man In The Hat.'
|
||||||
|
```
|
||||||
|
|
||||||
|
[`<str>.endswith(<suffix>)`][str-endswith] returns `True` if the string ends with `<suffix>`, `False` otherwise.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> 'My heart breaks. 💔'.endswith('💔')
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> 'cheerfulness'.endswith('ness')
|
||||||
|
True
|
||||||
|
|
||||||
|
# Punctuation is part of the string, so needs to be included in any endswith match.
|
||||||
|
>>> 'Do you want to 💃?'.endswith('💃')
|
||||||
|
False
|
||||||
|
|
||||||
|
>> 'The quick brown fox jumped over the lazy dog.'.endswith('dog')
|
||||||
|
False
|
||||||
|
```
|
||||||
|
|
||||||
|
[`<str>.strip(<chars>)`][str-strip] returns a copy of the `str` with leading and trailing `<chars>` removed.
|
||||||
|
The code points specified in `<chars>` are not a prefix or suffix - **all combinations** of the code points will be removed starting from **both ends** of the string.
|
||||||
|
If nothing is specified for `<chars>`, all combinations of whitespace code points will be removed.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
# This will remove "https://", because it can be formed from "/stph:".
|
||||||
|
>>> 'https://unicode.org/emoji/'.strip('/stph:')
|
||||||
|
'unicode.org/emoji'
|
||||||
|
|
||||||
|
# Removal of all whitespace from both ends of the str.
|
||||||
|
>>> ' 🐪🐪🐪🌟🐪🐪🐪 '.strip()
|
||||||
|
'🐪🐪🐪🌟🐪🐪🐪'
|
||||||
|
|
||||||
|
>>> justification = 'оправдание'
|
||||||
|
>>> justification.strip('еина')
|
||||||
|
'оправд'
|
||||||
|
|
||||||
|
# Prefix and suffix in one step.
|
||||||
|
>>> 'unaddressed'.strip('dnue')
|
||||||
|
'address'
|
||||||
|
|
||||||
|
>>> ' unaddressed '.strip('dnue ')
|
||||||
|
'address'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
[`<str>.replace(<substring>, <replacement substring>)`][str-replace] returns a copy of the string with all occurrences of `<substring>` replaced with `<replacement substring>`.
|
||||||
|
|
||||||
|
The quote used below is from [The Hunting of the Snark][The Hunting of the Snark] by [Lewis Carroll][Lewis Carroll]
|
||||||
|
|
||||||
|
```python
|
||||||
|
# The Hunting of the Snark, by Lewis Carroll
|
||||||
|
>>> quote = '''
|
||||||
|
"Just the place for a Snark!" the Bellman cried,
|
||||||
|
As he landed his crew with care;
|
||||||
|
Supporting each man on the top of the tide
|
||||||
|
By a finger entwined in his hair.
|
||||||
|
|
||||||
|
"Just the place for a Snark! I have said it twice:
|
||||||
|
That alone should encourage the crew.
|
||||||
|
Just the place for a Snark! I have said it thrice:
|
||||||
|
What I tell you three times is true."
|
||||||
|
'''
|
||||||
|
|
||||||
|
>>> quote.replace('Snark', '🐲')
|
||||||
|
...
|
||||||
|
'\n"Just the place for a 🐲!" the Bellman cried,\n As he landed his crew with care;\nSupporting each man on the top of the tide\n By a finger entwined in his hair.\n\n"Just the place for a 🐲! I have said it twice:\n That alone should encourage the crew.\nJust the place for a 🐲! I have said it thrice:\n What I tell you three times is true."\n'
|
||||||
|
|
||||||
|
>>> 'bookkeeper'.replace('kk', 'k k')
|
||||||
|
'book keeper'
|
||||||
|
```
|
||||||
|
|
||||||
|
[Lewis Carroll]: https://www.poetryfoundation.org/poets/lewis-carroll
|
||||||
|
[The Hunting of the Snark]: https://www.poetryfoundation.org/poems/43909/the-hunting-of-the-snark
|
||||||
|
[codecs]: https://docs.python.org/3/library/codecs.html
|
||||||
|
[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str
|
||||||
|
[locale]: https://docs.python.org/3/library/locale.html#module-locale
|
||||||
|
[str methods]: https://docs.python.org/3/library/stdtypes.html#string-methods
|
||||||
|
[str-endswith]: https://docs.python.org/3/library/stdtypes.html#str.endswith
|
||||||
|
[str-replace]: https://docs.python.org/3/library/stdtypes.html#str.replace
|
||||||
|
[str-strip]: https://docs.python.org/3/library/stdtypes.html#str.strip
|
||||||
|
[str-title]: https://docs.python.org/3/library/stdtypes.html#str.title
|
||||||
|
[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
|
||||||
|
|
||||||
|
In this exercise you are helping your younger sister edit her paper for school. The teacher is looking for correct punctuation, grammar, and excellent word choice.
|
||||||
|
|
||||||
|
You have four tasks to clean up and modify strings.
|
||||||
|
|
||||||
|
## 1. Capitalize the title of the paper
|
||||||
|
|
||||||
|
Any good paper needs a properly formatted title.
|
||||||
|
Implement the function `capitalize_title(<title>)` which takes a title `str` as a parameter and capitalizes the first letter of each word.
|
||||||
|
This function should return a `str` in title case.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> capitalize_title("my hobbies")
|
||||||
|
"My Hobbies"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Check if each sentence ends with a period
|
||||||
|
|
||||||
|
You want to make sure that the punctuation in the paper is perfect.
|
||||||
|
Implement the function `check_sentence_ending()` that takes `sentence` as a parameter. This function should return a `bool`.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> check_sentence_ending("I like to hike, bake, and read.")
|
||||||
|
True
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Clean up spacing
|
||||||
|
|
||||||
|
To make the paper look professional, unnecessary spacing needs to be removed.
|
||||||
|
Implement the function `clean_up_spacing()` that takes `sentence` as a parameter.
|
||||||
|
The function should remove extra whitespace at both the beginning and the end of the sentence, returning a new, updated sentence `str`.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> clean_up_spacing(" I like to go on hikes with my dog. ")
|
||||||
|
"I like to go on hikes with my dog."
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Replace words with a synonym
|
||||||
|
|
||||||
|
To make the paper _even better_, you can replace some of the adjectives with their synonyms.
|
||||||
|
Write the function `replace_word_choice()` that takes `sentence`, `old_word`, and `new_word` as parameters.
|
||||||
|
This function should replace all instances of the `old_word` with the `new_word`, and return a new `str` with the updated sentence.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> replace_word_choice("I bake good cakes.", "good", "amazing")
|
||||||
|
"I bake amazing cakes."
|
||||||
|
```
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
### Created by
|
||||||
|
|
||||||
|
- @kimolivia
|
||||||
|
|
||||||
|
### Contributed to by
|
||||||
|
|
||||||
|
- @valentin-p
|
||||||
|
- @BethanyG
|
43
python/little-sisters-essay/string_methods.py
Normal file
43
python/little-sisters-essay/string_methods.py
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
"""Functions to help edit essay homework using string manipulation."""
|
||||||
|
|
||||||
|
|
||||||
|
def capitalize_title(title):
|
||||||
|
"""Convert the first letter of each word in the title to uppercase if needed.
|
||||||
|
|
||||||
|
:param title: str - title string that needs title casing.
|
||||||
|
:return: str - title string in title case (first letters capitalized).
|
||||||
|
"""
|
||||||
|
|
||||||
|
return title.title()
|
||||||
|
|
||||||
|
|
||||||
|
def check_sentence_ending(sentence):
|
||||||
|
"""Check the ending of the sentence to verify that a period is present.
|
||||||
|
|
||||||
|
:param sentence: str - a sentence to check.
|
||||||
|
:return: bool - return True if punctuated correctly with period, False otherwise.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return sentence.endswith(".")
|
||||||
|
|
||||||
|
|
||||||
|
def clean_up_spacing(sentence):
|
||||||
|
"""Verify that there isn't any whitespace at the start and end of the sentence.
|
||||||
|
|
||||||
|
:param sentence: str - a sentence to clean of leading and trailing space characters.
|
||||||
|
:return: str - a sentence that has been cleaned of leading and trailing space characters.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return sentence.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def replace_word_choice(sentence, old_word, new_word):
|
||||||
|
"""Replace a word in the provided sentence with a new one.
|
||||||
|
|
||||||
|
:param sentence: str - a sentence to replace words in.
|
||||||
|
:param old_word: str - word to replace.
|
||||||
|
:param new_word: str - replacement word.
|
||||||
|
:return: str - input sentence with new words in place of old words.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return sentence.replace(old_word, new_word)
|
98
python/little-sisters-essay/string_methods_test.py
Normal file
98
python/little-sisters-essay/string_methods_test.py
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
import unittest
|
||||||
|
import pytest
|
||||||
|
from string_methods import (capitalize_title,
|
||||||
|
check_sentence_ending,
|
||||||
|
clean_up_spacing,
|
||||||
|
replace_word_choice)
|
||||||
|
|
||||||
|
|
||||||
|
class LittleSistersEssayTest(unittest.TestCase):
|
||||||
|
|
||||||
|
@pytest.mark.task(taskno=1)
|
||||||
|
def test_capitalize_word(self):
|
||||||
|
|
||||||
|
actual_result = capitalize_title("canopy")
|
||||||
|
expected = "Canopy"
|
||||||
|
error_message = (f'Called capitalize_title("canopy"). '
|
||||||
|
f'The function returned "{actual_result}", '
|
||||||
|
f'but the tests expected "{expected}" for the title.')
|
||||||
|
|
||||||
|
self.assertEqual(actual_result, expected, msg=error_message)
|
||||||
|
|
||||||
|
@pytest.mark.task(taskno=1)
|
||||||
|
def test_capitalize_title(self):
|
||||||
|
|
||||||
|
actual_result = capitalize_title("fish are cold blooded")
|
||||||
|
expected = "Fish Are Cold Blooded"
|
||||||
|
error_message = (f'Called capitalize_title("fish are cold blooded"). '
|
||||||
|
f'The function returned "{actual_result}", '
|
||||||
|
f'but the tests expected "{expected}" for the title.')
|
||||||
|
|
||||||
|
self.assertEqual(actual_result, expected, msg=error_message)
|
||||||
|
|
||||||
|
@pytest.mark.task(taskno=2)
|
||||||
|
def test_sentence_ending(self):
|
||||||
|
|
||||||
|
actual_result = check_sentence_ending("Snails can sleep for 3 years.")
|
||||||
|
expected = True
|
||||||
|
error_message = (f'Called check_sentence_ending("Snails can sleep for 3 years."). '
|
||||||
|
f'The function returned {actual_result}, '
|
||||||
|
f'but the tests expected {expected} for a period ending.')
|
||||||
|
|
||||||
|
self.assertEqual(actual_result, expected, msg=error_message)
|
||||||
|
|
||||||
|
@pytest.mark.task(taskno=2)
|
||||||
|
def test_sentence_ending_without_period(self):
|
||||||
|
|
||||||
|
actual_result = check_sentence_ending("Fittonia are nice")
|
||||||
|
expected = False
|
||||||
|
error_message = (f'Called check_sentence_ending("Fittonia are nice"). '
|
||||||
|
f'The function returned {actual_result}, '
|
||||||
|
f'but the tests expected {expected} for a period ending.')
|
||||||
|
|
||||||
|
self.assertEqual(actual_result, expected, msg=error_message)
|
||||||
|
|
||||||
|
@pytest.mark.task(taskno=3)
|
||||||
|
def test_remove_extra_spaces_only_start(self):
|
||||||
|
|
||||||
|
actual_result = clean_up_spacing(" A rolling stone gathers no moss")
|
||||||
|
expected = "A rolling stone gathers no moss"
|
||||||
|
error_message = (f'Called clean_up_spacing(" A rolling stone gathers no moss"). '
|
||||||
|
f'The function returned "{actual_result}", '
|
||||||
|
f'but the tests expected "{expected}" as a cleaned string.')
|
||||||
|
|
||||||
|
self.assertEqual(actual_result, expected, msg=error_message)
|
||||||
|
|
||||||
|
@pytest.mark.task(taskno=3)
|
||||||
|
def test_remove_extra_spaces(self):
|
||||||
|
|
||||||
|
actual_result = clean_up_spacing(" Elephants can't jump. ")
|
||||||
|
expected = "Elephants can't jump."
|
||||||
|
error_message = ("Called clean_up_spacing(\" Elephants can't jump. \")"
|
||||||
|
f'The function returned "{actual_result}", '
|
||||||
|
f'but the tests expected "{expected}" as a cleaned string.')
|
||||||
|
|
||||||
|
self.assertEqual(actual_result, expected, msg=error_message)
|
||||||
|
|
||||||
|
@pytest.mark.task(taskno=4)
|
||||||
|
def test_replace_word_choice(self):
|
||||||
|
|
||||||
|
actual_result = replace_word_choice("Animals are cool.", "cool", "awesome")
|
||||||
|
expected = "Animals are awesome."
|
||||||
|
error_message = ('Called replace_word_choice("Animals are cool.", "cool", "awesome"). '
|
||||||
|
f'The function returned "{actual_result}", '
|
||||||
|
f'but the tests expected "{expected}" after the word replacement.')
|
||||||
|
|
||||||
|
self.assertEqual(actual_result, expected, msg=error_message)
|
||||||
|
|
||||||
|
@pytest.mark.task(taskno=4)
|
||||||
|
def test_replace_word_not_exist(self):
|
||||||
|
|
||||||
|
actual_result = replace_word_choice("Animals are cool.", "small", "tiny")
|
||||||
|
expected = "Animals are cool."
|
||||||
|
error_message = ('Called replace_word_choice("Animals are cool.", "small", "tiny"). '
|
||||||
|
f'The function returned "{actual_result}", '
|
||||||
|
f'but the tests expected "{expected}", because the word '
|
||||||
|
'to be replaced is not in the sentence.')
|
||||||
|
|
||||||
|
self.assertEqual(actual_result, expected, msg=error_message)
|
Loading…
Reference in a new issue