Repository: exercism/python
Pull request #2844 (2022-01-06 01:14:54)

[Black Jack]: Comparisons Concept and Concept Exercise Finalization
Added/Changed/Edited files:

- [x]   config.json
- [x]   exercises/concept/black-jack/.meta/config.json
----
- [x]   concepts/comparisons/introduction.md
- [x]   concepts/comparisons/about.md
____
- [x]   exercises/concept/black-jack/.docs/introduction.md
- [x]   exercises/concept/black-jack/.docs/instructions.md
- [x]   exercises/concept/black-jack/.docs/hints.md
____
- [x]  exercises/concept/black-jack/.meta/exemplar.py
- [x]  exercises/concept/black-jack/black_jack.py
- [x]   exercises/concept/black-jack/black_jack_test.py

github-actions[bot]: Hi & Welcome! 👋🏽&nbsp;👋

**Thank you** for contributing to `exercism/python` 💛&nbsp;💙 -- we really appreciate it! 🌟 🌈


<br>

This is an automated [🤖&nbsp;🤖 &nbsp;] comment for the  **`maintainers`** of this repository, notifying them of your contribution.  🎉
Someone will review/reply to your changes shortly. (_usually within **72 hours**._)
You can safely ignore the **`maintainers`**  section below.

<br>
<details open>
  <summary>⚠️ &nbsp;<b>Please be aware</b>&nbsp;⚠️ </summary>

  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_This repo does not generally accept [Pull Requests](https://github.com/exercism/docs/blob/main/community/good-member/pull-requests.md) unless they follow our [contributing guidelines](https://github.com/exercism/python/blob/main/CONTRIBUTING.md) and are:_

  &nbsp;&nbsp;&nbsp;&nbsp; 1️⃣ &nbsp;&nbsp;&nbsp; Small, contained fixes for typos/grammar/punctuation/code syntax on [one] exercise,
  &nbsp;&nbsp;&nbsp;&nbsp; 2️⃣ &nbsp;&nbsp;&nbsp;&nbsp;Medium changes that have been agreed/discussed via a filed issue,
  &nbsp;&nbsp;&nbsp;&nbsp; 3️⃣ &nbsp;&nbsp;&nbsp;&nbsp;Contributions from our [help wanted][help-wanted] issue list,
  &nbsp;&nbsp;&nbsp;&nbsp; 4️⃣ &nbsp;&nbsp;&nbsp;&nbsp;Larger (_previously agreed-upon_) contributions from recent & regular (_within the last 6 months_) contributors.

  &nbsp;&nbsp;&nbsp;&nbsp;Pull Requests not in these categories **will be closed**.  😞

</details>
<br>


---

#### **`💙  It looks like you are changing/adding files in a Concept Exercise! 💙 `**

<br>
<details>
  <summary>‼️&nbsp;&nbsp;<b><em>Did You...</em></b></summary>
<br>
<table>
<td>
<br>

 - [ ]  &nbsp;Update & rebase your branch with any (recent) upstream changes.
 - [ ]  &nbsp;Spell and grammar check all prose changes.
 - [ ]  &nbsp;Run [Prettier](https://prettier.io/) on all markdown and JSON files.
     - (_Optionally_) run [yapf](https://github.com/google/yapf) ([_yapf config_](https://github.com/exercism/python/blob/main/.style.yapf)) to help format your code.
 - [ ]  &nbsp;Run [flake8](http://flake8.pycqa.org/) with [_flake8 config_](https://github.com/exercism/python/blob/main/.flake8) to check general code style standards.
 - [ ] &nbsp; Run [pylint](https://pylint.pycqa.org/en/v2.11.1/user_guide/index.html) with [_pylint config_](https://github.com/exercism/python/blob/main/pylintrc) to check extended code style standards.
 - [ ]  &nbsp;Use pytest or the [python-track-test-runner](https://github.com/exercism/python-test-runner) to test any changed `example.py`/`exemplar.py`files
 &nbsp;against their associated test files.
 - [ ]  &nbsp;Similarly, use [pytest](https://docs.pytest.org/en/6.2.x/contents.html) or the [python-track-test-runner](https://github.com/exercism/python-test-runner) to test any changed _**test**_ files.
     - Check that tests **fail** properly, as well as succeed.
     &nbsp;(_**e.g.**, make some tests fail on purpose to "test the tests" & failure messages_).
 - [ ]  &nbsp;Double-check all files for proper EOL.
 - [ ]  &nbsp;[Regenerate](https://github.com/exercism/python/blob/main/CONTRIBUTING.md#generating-practice-exercise-documents) exercise documents when you modified or created a `hints.md` file for a practice exercise.
 - [ ]  &nbsp;[Regenerate the test file](https://github.com/exercism/python/blob/main/CONTRIBUTING.md#auto-generated-test-files-and-test-templates) if you modified or created a `JinJa2` template file for a practice exercise.
     -  Run the generated test file result against its `example.py`.
 - [ ]  &nbsp;Run [`configlet-lint`](https://github.com/exercism/configlet#configlet-lint) if the track [config.json](https://github.com/exercism/docs/blob/main/building/tracks/config-json.md), or any other exercise `config.json` has been modified.

<br>
</td>
</table>
<br>
</details>

<details>
<summary>✅️&nbsp;&nbsp;<b><em>Have You Checked:</em></b></summary>
<br>
<table>
<td>

.
_**Are there any additional changes you need to make?**_
Please make sure all associated files are present and consistent with your changes!

[Concept Exercise Anatomy](https://github.com/exercism/docs/blob/main/building/tracks/concept-exercises.md)

- [ ] `.docs/hints.md`
- [ ] `.docs/instructions.md`
- [ ] `.docs/introduction.md`
- [ ] `.meta/config.json`
- [ ] `.meta/design.md`
- [ ] `.meta/exemplar.py` (_exemplar solution_)
- [ ] `<exercise-slug>_test.py` (_test file_)
- [ ] `<exercise-slug>.py` (_stub file_)
- [ ] `concepts/../introduction.md`
- [ ] `concepts/../about.md`
- [ ] `concepts/../links.json`
- [ ] `concepts/../.meta/config.json`

</td>
</table>
<br>
</details>



<h2>🛠️ &nbsp;&nbsp; Maintainers &nbsp;&nbsp;</h2>
<h3> Please take note 📒  of the following sections/review items 👀   ✨ </h3>
<br>
<br>
<details>
<summary> 🌈  &nbsp;Acknowledgements and Reputation</summary>
<br>
<table>
<td>

- ❓ Does this PR need to receive a label with a [`reputation modifier`](https://github.com/exercism/docs/blob/main/using/product/reputation.md#creating-a-pull-request)?
     -  `medium` is awarded by default.
- ❓ Does this contributor need to be added to the **exercise** [`authors` or `contributors`](https://github.com/exercism/docs/blob/main/building/tracks/practice-exercises.md#file-metaconfigjson)?
- ❓ Does this contributor need to be added to the **concept** [`authors` or `contributors`](https://github.com/exercism/docs/blob/main/building/tracks/concepts.md#file-metaconfigjson)?
- ❓ Is there an associated issue or issues that should be linked to this PR?

</td>
</table>
</details>
<details>
<summary>💫 &nbsp;General Code Quality</summary>
<ul>
<table>
<td>
  <h4>Verify:</h4>

  -  [ ]  &nbsp;The branch was updated & rebased with any (recent) upstream changes.
  -  [ ]  &nbsp;All prose was checked for spelling and grammar.
  -  [ ]  &nbsp;Files are formatted via [yapf](https://github.com/google/yapf) ([_yapf config_](https://github.com/exercism/python/blob/main/.style.yapf)) & conform to our [coding standards](https://github.com/exercism/python/blob/main/CONTRIBUTING.md#coding-standards)
  -  [ ]  &nbsp;Files pass [flake8](http://flake8.pycqa.org/) with [_flake8 config_](https://github.com/exercism/python/blob/main/.flake8) & [pylint](https://pylint.pycqa.org/en/v2.11.1/user_guide/index.html) with [_pylint config_](https://github.com/exercism/python/blob/main/pylintrc).
  -  [ ]  &nbsp;Changed `example.py`/`exemplar.py` files still pass their associated **test files**.
  -  [ ]  &nbsp;Changed _**test files**_ still work with associated `example.py`/`exemplar.py` files.
      - Check that tests **fail** properly, as well as succeed.
             (_**e.g.**, make some tests fail on purpose to "test the tests" & failure messages_).
  -  [ ]  &nbsp;All files have proper EOL.
  -  [ ]  &nbsp;If a `JinJa2` template was modified/created, was the test file [regenerated](https://github.com/exercism/python/blob/main/CONTRIBUTING.md#auto-generated-test-files-and-test-templates)?
      - Does the regenerated test file successfully test the exercises `example.py` file?
  -  [ ]  &nbsp;The branch passes all CI checks & [`configlet-lint`](https://github.com/exercism/configlet#configlet-lint).

<br>
</td>
</table>
</ul>
<br>
</details>
<details>
<summary>🌿 &nbsp;Changes to Concept Exercises</summary>
<br>

  -   ❓ Are all required files still up-to-date & configured correctly for this change?_
  -   ❓ Does `<exercise>/.meta/design.md` need to be updated with new implementation/design decisions
  -   ❓ Do these changes require follow-on/supporting changes to related **concept** documents?

<ul>
<details>
<summary><em><b> ✨ &nbsp;Where applicable, check the following&nbsp;✨  </b></em></summary>
<br>
<ul>
<table>
<td>

(_as a reminder: [Concept Exercise Anatomy](https://github.com/exercism/docs/blob/main/building/tracks/concept-exercises.md)_)
  - [ ] Exercise `introduction.md`
    - [ ]  Do all code examples compile, run, and return the shown output?
    - [ ]  Are all the code examples formatted per the Python docs?
  - [ ]  Exercise `instructions.md`
  - [ ]  Exercise  `hints.md`
  - [ ]   Check that exercise `design.md` was fulfilled or edited appropriately
  - [ ]   Exercise `exemplar.py`
    - [ ]  Only uses syntax previously introduced or explained.
    - [ ]  Is correct and appropriate for the exercise and story.
  - [ ]   Exercise `<exercise_name>.py` (stub)
    - [ ]  Includes appropriate docstrings and function names.
    - [ ]  Includes `pass` for each function
    - [ ]  Includes an EOL at the end
  - [ ]   Exercise  `<exercise_name>_test.py`
    - [ ]   Tests cover all (reasonable) inputs and scenarios
    - [ ]   At least one test for each task in the exercise
    - [ ]   If using subtests or fixtures they're [formatted correctly](https://github.com/exercism/python/blob/main/CONTRIBUTING.md#Test-File_style) for the runner
    - [ ]   Classnames are `<ExerciseName>Test`
    - [ ]   Test functions are `test_<test_name>`
  - [ ]   Exercise `config.json` --> **valid UUID4**
  - [ ]   Corresponding concept `introduction.md`
  - [ ]   Corresponding concept `about.md`
  - [ ]   Concept  `config.json`
  - [ ]   All Markdown Files :  Prettier linting (_for all markdown docs_)
  - [ ]   All Code files: PyLint linting (**_except for test files_**)
  - [ ]   All files with text:  Spell check & grammar review.

</td>
</table>
</ul>
</details>
</ul>
</details>

<details>
<summary>🚀&nbsp;  Changes to Practice Exercises</summary>
<br>
<ul>
<table>
<td>

_Is the exercise is in line with [Practice Exercise Anatomy](https://github.com/exercism/docs/blob/main/building/tracks/practice-exercises.md)?_
- [ ] `.docs/instructions.md`(**required**)
   - Was this file updated and regenerated properly?
- [ ] `.docs/introduction.md`(_optional_)
- [ ] `.docs/introduction.append.md`(_optional_)
- [ ] `.docs/instructions.append.md` (_optional_)
   - Are any additional instructions needed/provided?
   &nbsp;(_e.g. error handling or information on classes_)
- [ ] `.docs/hints.md`(_optional_)
   - Was this file regenerated properly?
- [ ] `.meta/config.json` (**required**)
- [ ] `.meta/example.py` (**required**)
   - Does this pass all the current tests as written/generated?
- [ ] `.meta/design.md` (_optional_)
- [ ] `.meta/template.j2` (_template for generating tests from canonical data_)
  - Was a test file properly regenerated from this template?
- [ ] `.meta/tests.toml`
   -  Are there additional test cases to include or exclude?
   -  Are there any Python-specific test cases needed for this exercise?
- [ ] `<exercise-slug>_test.py`
   - Does this file need to be regenerated?
   - Does this file correctly test the `example.py` file?
   - Does this file correctly report test failures and messages?
- [ ] `<exercise-slug>.py` (**required**)
   - Does this stub have enough information to get
   &nbsp;the student started coding a valid solution?

</td>
</table>
</ul>
</details>
  <details>
    <summary>🐣 &nbsp;Brand-New Concept Exercises</summary>
<br>
<ul>
<table>
<td>

_Is the exercise is in line with [Concept Exercise Anatomy](https://github.com/exercism/docs/blob/main/building/tracks/concept-exercises.md)?_
  - [ ] Exercise `introduction.md`
    - [ ]  Do all code examples compile, run, and return the shown output?
    - [ ]  Are all the code examples formatted per the Python docs?
  - [ ]  Exercise `instructions.md`
  - [ ]  Exercise  `hints.md`
  - [ ]   Check that exercise `design.md` was fulfilled or edited appropriately
  - [ ]   Exercise `exemplar.py`
    - [ ]  Only uses syntax previously introduced or explained.
    - [ ]  Is correct and appropriate for the exercise and story.
  - [ ]   Exercise `<exercise_name>.py` (stub)
    - [ ]  Includes appropriate docstrings and function names.
    - [ ]  Includes `pass` for each function
    - [ ]  Includes an EOL at the end
  - [ ]   Exercise  `<exercise_name>_test.py`
    - [ ]   Tests cover all (reasonable) inputs and scenarios
    - [ ]   At least one test for each task in the exercise
    - [ ]   If using subtests or fixtures they're formatted correctly for the runner
    - [ ]   Classnames are `<ExerciseName>Test`
    - [ ]   Test functions are `test_<test_name>`
  - [ ]   Exercise `config.json` --> valid UUID4
  - [ ]   Corresponding concept `introduction.md`
  - [ ]   Corresponding concept `about.md`
  - [ ]   Concept  `config.json`
  - [ ]   All Markdown Files :  Prettier linting (_for all markdown docs_)
  - [ ]   All Code files: Flake8 & PyLint linting
  - [ ]   All Code Examples:  proper formatting and fencing.  Verify they run in the REPL
  - [ ]   All files with text:  Spell check & grammar review.

<br>
</td>
</table>
</ul>
</details>
<br>
<h3>Our &nbsp; 💖  &nbsp; for all your review efforts! 🌟 🦄</h3>


<!-- pr-commenter-metadata: any-file-changed,change-concept-exercise -->
BethanyG: Alrighty.  Ran everything through priettier, and cleaned up the `<apples>` and `<oranges>` 😉   I also removed the excess lines in the module docstrings.  Let me know if there's anything I've missed.  😄   Thanks for reviewing this!
BethanyG: @kotp - are there additional changes needed here for approval?  Let me know - thanks!

Patch:
diff --git a/concepts/comparisons/about.md b/concepts/comparisons/about.md
index 3c43a38e..568b6603 100644
--- a/concepts/comparisons/about.md
+++ b/concepts/comparisons/about.md
@@ -1,199 +1,277 @@
-# About
-
-A [comparison operator][comparisons] in Python (_also called a Python relational operator_), looks at the values of two operands and returns `True` or `False` based on whether the `comparison` condition is met.
-The most common comparison operators are `"<"`, `">"`, `"=="`, `">="`, `"<="`, and `"!="`.
-They all have the same priority (which is higher than that of the Boolean operations).
-
-```python
->>> 7 > 5
-True
->>> 99 < 100
-True
->>> 4 < 4
-False
->>> 4 <= 4
-True
->>> 1 >= 1
-True
->>> 5 == 5
-True
->>> 6 != 6  # not equal to
-False
->>> 5 != 6
-True
->>> not 3 == 3  # interpreted as not(3 == 3)
-False
-```
-
-## Comparison Chaining
-
-Comparisons can be chained arbitrarily, e.g., `x < y <= z` is equivalent to `x < y` `and` `y <= z`, except that `y` is evaluated only once (but in both cases `z` is _not_ evaluated at all when `x < y` is found to be `False`).
-This is also called `short-circuit` evaluation which means the execution is stopped if the truth value of the expression has already been determined.
-Note that the evaluation of expression takes place from left to right.
-In python, short circuiting is supported by various boolean operators, functions and, in this case, comparison chaining.
-
-Also unlike `C`, expressions like `a < b < c` have the interpretation that is conventional in mathematics.
-
-```python
->>> x = 2
->>> y = 5
->>> z = 10
->>> x < y < z
-True
->>> x < y > z
-False
->>> x > y < z
-False
-```
-
-## Comparison between different data types
-
-Since everything in Python is an `object`, things can get interesting when objects of different types are compared.
-For example, the `str` value of a number is considered completely different from the `integer` or `floating-point` value.
-Python makes this distinction because strings are text, while `integers` and `floats` are numeric types.
-
-However, an `integer` **can** be considered equal to a `float`, as they are both numeric types that Python can implicitly convert to compare.
-
-For other numeric types, comparison operators are defined where they "make sense", but throw a `TypeError` if the underlying objects cannot be 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
->>> 17 == '17'
-False
->>> 17 == 17.0
-True
->>> 17.0 == 0017.000
-True
->>> complex(1, 2) == complex(1.0, 2.00)
-True
-```
-
-
-## Value Comparison
-
-The operators `<`, `>`, `==`, `>=`, `<=`, and `!=` compare the _values_ of two different objects.
-The objects do not need to have the same type.
-Remember that in Python every object has a `value` in addition to `type` and `identity`.
-
-### Following are comparison behaviour of most `built-ins` types.
-
-Numbers of built-in _numeric_ types such as `int`, `hex`, `ocal`, `binary`, `float`, `complex` and of the standard library types `fractions.Fraction` and `decimal.Decimal` can be compared within and across their types.
-
-Any ordered comparison of a number to a `NaN` (_not a number_) value is `False`.
-A counter-intuitive implication is that `NaN` never compares equal to `NaN`.
-
-```python
->>> x = float('NaN')
->>> x
-nan
->>> 3 < x
-False
->>> x < 3
-False
->>> x == x
-False
-```
-
-Strings (`str`) are compared _lexicographically_ using their individual numerical Unicode code points (_the result of passing each code point in the `str` to the built-in function `ord()`_).
-`str` and `binary` sequences cannot be directly compared.
-
-```python
->>> 'santa' < 'claus'
-False
->>> 'Santa' < 'claus'
-True
->>> ord('s')
-115
->>> ord('S')
-83
->>> ord('c')
-99
->>> # let's try Chinese words
->>> '你好' < '再见'  # hello < goodbye
-True
->>> # check ord() of first letters
->>> ord('你'), ord('再')
-(20320, 20877)
->>>
->>>
->>> # let's try Korean words
->>> '예쁜' < '아름다운'  # pretty < beautiful
-False
->>> ord('예'), ord('아')
-(50696, 50500)
-```
-
-Collections like `list`, `set`, `tuple` and `dict` can also be compared -- provided they are of the same `type`, have the same length, and each _**pair**_ of corresponding elements within the collection are comparable.
-
-```python
->>> [1, 2] == [1, 2]
-True
->>> (1, 2) == [1, 2]
-False
->>> [1, 2] < [1, 2, 3]
-True
->>> # comparison of dicts
->>> {'name': 'John', 'age': 19} == {'name': 'John', 'age': 18}
-False
->>> {'name': 'John', 'age': 19} == {'name': 'John', 'age': 19}
-True
-```
-
-## Identity comparisons
-
-The operators `is` and `is not` test for an object's _identity_.
-An object's identity is determined using the `id()` function.
-
-`apple is orange` is `True` if and only if `apple` and `orange` are the same object.
-`apple is not orange` yields the inverse truth value.
-
-```python
->>> my_fav_numbers = [1, 2, 3]
->>> your_fav_numbers = my_fav_numbers
->>> my_fav_numbers == your_fav_numbers
-True
->>> id(my_fav_numbers)
-4462635008
->>> id(your_fav_numbers)
-4462635008
->>> my_fav_numbers is not your_fav_numbers
-False
-```
-
-## Membership test operations
-
-The operators `in` and `not in` test for _membership_.
-`fish in soup` evaluates to `True` if `fish` is a member of `soup`, and evaluates `False` otherwise.
-`fish not in soup` returns the negation, or _opposite of_ `fish in soup`.
-
-For the string and bytes types, `name` in `fullname` is `True` if and only if `name` is a substring of `fullname`.
-
-```python
-lucky_numbers = {11, 22, 33}
->>> 22 in lucky_numbers
-True
->>> 44 in lucky_numbers
-False
->>>
->>> employee = {
-    'name': 'John Doe',
-    'id': 67826,
-    'age': 33,
-    'title': 'ceo'
-    }
->>> 'age' in employee
-True
->>> 33 in employee
-False
->>> 'lastname' not in employee
-True
->>>
->>> name = 'Super Batman'
->>> 'Bat' in name
-True
->>> 'Batwoman' in name
-False
-```
-
-[comparisons]: https://docs.python.org/3/library/stdtypes.html?highlight=comparisons#comparisons
-[arithmetic conversions]: https://docs.python.org/3/reference/expressions.html?highlight=number%20conversion#arithmetic-conversions
+# About
+
+A [comparison operator][comparisons] in Python (_also called a Python relational operator_), looks at the _values_ of two [operands][operand] and returns a boolean `True` or `False` if the `comparison` condition is or is not met.
+
+The table below shows the most common Python 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.
+For (much) more detail, 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 ([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`.
+If you are curious as to why `Nan` was defined this way in Python, this [Stack Overflow Post on NaN][so nan post] around the setting of the international standard is an interesting read.
+
+```python
+>>> x = float('NaN')
+
+>>> 3 < x
+False
+
+>>> x < 3
+False
+
+# NaN never compares equal to NaN
+>>> x == x
+False
+```
+
+## Comparing Strings
+
+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.
+Unlike in Python 2.x, 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)
+```
+
+## Comparing Container Data Types
+
+Container data types (_`lists`, `tuples`, `sets`, `dicts`, etc._) also compare [_lexicographically_][lexographic order] - they are equal if both containers have the same data **and** the same data types (_in the case of `lists` and `tuples`, they must also have the same **ordering**_), unequal otherwise.
+
+```python
+>>> [1, 2] == [1, 2]
+True
+
+# But if the data is not in the same order, they are not equal.
+>>> [2, 1] == [1, 2]
+False
+
+# The same holds true for tuples
+>>> (3,4,5) == (5,4,3)
+False
+
+# Length is also compared
+>>> [1, 2] < [1, 2, 3]
+True
+
+# Comparing dicts
+>>> {'name': 'John', 'age': 19} == {'name': 'John', 'age': 18}
+False
+
+>>> {'name': 'John', 'age': 19} == {'name': 'John', 'age': 19}
+True
+```
+
+## Comparison Chaining
+
+Comparison operators can be chained _arbitrarily_.
+Note that the evaluation of an expression takes place from `left` to `right`.
+For 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
+```
+
+## Identity comparisons
+
+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
+>>> 
+# A list of favorite numbers.
+>>> 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
+```
+
+# Customizing comparison behavior
+
+Comparison behavior for objects can be customized through the implementation of `rich comparison methods`.
+For more information, see [Python Tutorial: classes][classes], [Python Classes and Magic Methods (Dan Bader)][magic methods], and [Special method names][dunder methods].
+
+[PEP8 programming recommendations]: https://pep8.org/#programming-recommendations
+[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
+[classes]: https://docs.python.org/3/tutorial/classes.html#classes
+[comparisons]: https://docs.python.org/3/library/stdtypes.html?highlight=comparisons#comparisons
+[complex numbers]: https://docs.python.org/3/library/functions.html#complex
+[decimal numbers]: https://docs.python.org/3/library/decimal.html
+[dunder methods]: https://docs.python.org/3/reference/datamodel.html#special-method-names
+[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
+[magic methods]: https://dbader.org/blog/python-dunder-methods
+[object identity]: https://docs.python.org/3/reference/datamodel.html
+[octal]: https://docs.python.org/3/library/functions.html?#oct
+[operand]: https://www.computerhope.com/jargon/o/operand.htm
+[ord]: https://docs.python.org/3/library/functions.html#ord
+[rational numbers]: https://docs.python.org/3/library/fractions.html
+[rich comparisons]: https://docs.python.org/3/reference/datamodel.html#object.__lt__
+[so nan post]: https://stackoverflow.com/questions/1565164/what-is-the-rationale-for-all-comparisons-returning-false-for-ieee754-nan-values
+[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
diff --git a/concepts/comparisons/introduction.md b/concepts/comparisons/introduction.md
index 27a105c1..e597063c 100644
--- a/concepts/comparisons/introduction.md
+++ b/concepts/comparisons/introduction.md
@@ -1,23 +1,57 @@
-# Introduction
-
-A [comparison operator][comparisons] in Python (_also called a Python relational operator_), looks at the values of two operands and returns `True` or `False` based on whether the `comparison` condition is met.
-The most common comparison operators are `"<"`, `">"`, `"=="`, `">="`, `"<="`, and `"!="`.
-They all have the same priority (which is higher than that of the Boolean operations)
-
-## Comparison Chaining
-
-Comparisons can be chained arbitrarily, e.g., `x < y <= z` is equivalent to `x < y` `and` `y <= z`, except that `y` is evaluated only once (but in both cases `z` is _not_ evaluated at all when `x < y` is found to be `False`).
-This is also called `short-circuit` evaluation which means the execution is stopped if the truth value of the expression has already been determined.
-Note that the evaluation of expression takes place from left to right.
-In python, short circuiting is supported by various boolean operators, functions and, in this case, comparison chaining.
-
-## Comparison of different data types
-
-Since everything in Python is an `object`, things can get interesting when objects of different types are compared.
-For example, the `str` value of a number is considered completely different from the `integer` or `floating-point` value.
-However, an `integer` **can** be considered equal to a `float`, as they are both numeric types that Python can implicitly convert to compare.
-For other numeric types, comparison operators are defined where they "make sense", but throw a `TypeError` if the underlying objects cannot be converted for comparison.
-For more information on the rules that python uses for numeric conversion, see [arithmetic conversions][arithmetic conversions] in the Python documentation.
-
-[comparisons]: https://docs.python.org/3/library/stdtypes.html?
-[arithmetic conversions]: https://docs.python.org/3/reference/expressions.html?highlight=number%20conversion#arithmetic-conversions
+# Introduction
+
+A [comparison operator][comparisons] in Python (_also called a Python relational operator_), looks at the _values_ of two [operands][operand] and returns a boolean `True` or `False` if the `comparison` condition is or is not met.
+
+The table below shows the most common Python 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 methods that customize the default `object` comparison behavior.
+
+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 ([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.
+
+## 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.
+
+## 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>`.
+
+[boolean operations]: https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not
+[comparisons]: https://docs.python.org/3/library/stdtypes.html?highlight=comparisons#comparisons
+[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
+[object identity]: https://docs.python.org/3/reference/datamodel.html
+[octal]: https://docs.python.org/3/library/functions.html?#oct
+[operand]: https://www.computerhope.com/jargon/o/operand.htm
+[rational numbers]: https://docs.python.org/3/library/fractions.html
diff --git a/config.json b/config.json
index 134bd35f..ea1e3819 100644
--- a/config.json
+++ b/config.json
@@ -71,8 +71,8 @@
         "name": "Black Jack",
         "uuid": "e1a6075e-0c5e-48cd-8c50-69140961a06a",
         "concepts": ["comparisons"],
-        "prerequisites": ["basics"],
-        "status": "wip"
+        "prerequisites": ["basics", "bools", "conditionals"],
+        "status": "beta"
       },
       {
         "slug": "pretty-leaflet",
diff --git a/exercises/concept/black-jack/.docs/hints.md b/exercises/concept/black-jack/.docs/hints.md
index f91a51a1..55a1d026 100644
--- a/exercises/concept/black-jack/.docs/hints.md
+++ b/exercises/concept/black-jack/.docs/hints.md
@@ -4,30 +4,42 @@
 
 ## 1. Calculate the value of a card
 
-- You can use the equality comparison operator `==` to determine specific cards, e.g. `card == 'J'`.
-- You can use the [`int` constructor][int constructor] to get an integer number from an integer literal, e.g. `int(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. Calculate the value of an ace
+## 2. Determine which card has a higher value
 
-- You can use the order comparison operator `>` to decide the appropriate course of action, e.g. `hand_value + 11 > 21`.
+- 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. Determine Blackjack
+## 3. Calculate the value of an ace
 
-- You can use the [`if`/`elif`/`else` syntax][if syntax] to handle different combinations of cards.
+- 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.
 
-## 4. Splitting pairs
+## 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.
 
-## 5. Doubling down
+## 6. Doubling down
 
-- You can chain comparison operators, e.g. `9 <= hand_value <= 11`.
-- You can use the [conditional expression][conditional expression] (sometimes called a "ternary operator")
-to shorten simple `if`/`else` statements, e.g. `1 if card == 'A' else value_of_card(card)`.
+- 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`.
 
-[python comparisons tutorial]: https://docs.python.org/3/reference/expressions.html#comparisons
-[python comparisons examples]: https://www.tutorialspoint.com/python/comparison_operators_example.htm
-[int constructor]: https://docs.python.org/3/library/functions.html#int
-[if syntax]: https://docs.python.org/3/tutorial/controlflow.html#if-statements
 [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
diff --git a/exercises/concept/black-jack/.docs/instructions.md b/exercises/concept/black-jack/.docs/instructions.md
index 774b35fd..ebefc59b 100644
--- a/exercises/concept/black-jack/.docs/instructions.md
+++ b/exercises/concept/black-jack/.docs/instructions.md
@@ -3,89 +3,128 @@
 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 cards.
-A [standard 52-card deck][standard_deck] is assumed.
+**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.
-Face cards (_J_, _Q_, _K_) are worth 10 points and any other card is worth its pip (numerical) value.
+In Blackjack, it is up to each individual player if an ace is worth 1 or 11 points (_more on that later_).
+Face cards (`J`, `Q`, `K`) are scored at 10 points and any other card is worth its "pip" (_numerical_) value.
 
-Define the `value_of_card` function with a parameter `card`.
-The value of _J_, _Q_ or _K_ is 10.
-Otherwise, return the numerical value of a card.
-An ace can take on multiple values so let's ignore _A_ for the time being.
+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, give an existing hand.
 
 ```python
 >>> value_of_card('K')
 10
+
 >>> value_of_card('4')
 4
+
+>>> value_of_card('A')
+1
 ```
 
-## 2. Calculate the value of an ace
+## 2. Determine which card has a higher value
 
-As mentioned before, an ace can be worth _either_ 1 or 11 points.
-At the same time, players are trying to get as close to 21 as possible, without going _over_ 21.
+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:
 
-Define the `value_of_ace(<hand_value>)` function with a parameter `hand_value`,
-which is the total hand value before getting an ace card.
-You now have to decide if the upcoming ace card will be scored as a 1 or 11.
-The value of the hand with the ace needs to be as high as possible _without_ going over 21.
+```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
->>> value_of_ace(19)
+>>> 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.
+
+```python
+>>> value_of_ace('6', `K`)
 1
->>> value_of_ace(7)
+
+>>> value_of_ace('7', '3')
 11
 ```
 
-## 3. Determine Blackjack
+## 4. Determine a "Natural" or "Blackjack" Hand
 
-If the first two cards are an ace and a ten-card, giving a count of 21 in two cards, it is known as blackjack.
+If the first two cards a player is dealt are an ace (`A`) and a ten-card (10, `K`, `Q` or `J`), giving a score of 21 in two cards, the hand is considered a `natural` or `blackjack`.
 
 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.
+Determine if the two-card hand is a `blackjack`, and return the boolean `True` if it is, `False` otherwise.
 
-**Note** : This calculation can be done in many ways.
- If possible, check if there is an ace and a ten-card in the hand.
+**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
 ```
 
-## 4. Splitting pairs
+## 5. Splitting pairs
 
-If the 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.
+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
 ```
 
-## 5. Doubling down
+## 6. Doubling down
 
-When the original two cards dealt total 9, 10, or 11 points
-a player can place an additional bet equal to the original bet.
+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".
+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://en.wikipedia.org/wiki/Blackjack
+[blackjack]: https://bicyclecards.com/how-to-play/blackjack/
 [standard_deck]: https://en.wikipedia.org/wiki/Standard_52-card_deck
diff --git a/exercises/concept/black-jack/.docs/introduction.md b/exercises/concept/black-jack/.docs/introduction.md
index eed9111f..b79091f4 100644
--- a/exercises/concept/black-jack/.docs/introduction.md
+++ b/exercises/concept/black-jack/.docs/introduction.md
@@ -1,185 +1,235 @@
 ## Comparisons
 
-There are some different kinds of comparison operators in Python
+Python supports the following basic comparison operators:
 
-| Operator | Operation                | Description                                              |
-| -------- | ------------------------ | -------------------------------------------------------- |
-| `>`      | Greater than             | `a > b` is `True` if `a` is greater than `b`             |
-| `<`      | Less than                | `a < b` is `True` if `a` is less than `b`                |
-| `==`     | Equal to                 | `a == b` is `True` if `a` is equals to `b`               |
-| `>=`     | Greater than or equal to | `a >= b` is `True` if `a > b` or `a == b` is `True`      |
-| `<=`     | Less than or equal to    | `a <= b` is `True` if `a < b` or `a == b` is `True`      |
-| `!=`     | Not equal to             | `a != b` is `True` if `a = b` is `False`                 |
-| `is`     | Identity                 | `a is b` is `True` if `a` and `b` is same object         |
-| `is not` | Identity                 | `a is not b` is `True` if `a` and `b` is not same object |
-| `in`     | Containment test         | `a in b` is `True` if `a` is member of `b`               |
-| `not in` | Containment test         | `a not in b` is `True` if `a` is not a member of `b`     |
+| 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`  |
 
-## Greater than
+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_).
 
-Operator `>` tests if the first operand's value is greater than the second one's.
+## Comparison between different data types
 
-```python
->>> 3 > 1
-True
->>> 2.99 > 3
-False
->>> 1 > 1
-False
->>> 0 > 1
-False
-```
+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.
 
-## Less than
+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.
 
-Operator `<` tests if the first operand's value is less than the second one's.
+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
->>> 3 < 1
+>>> import fractions
+
+# A string cannot be converted to an int.
+>>> 17 == '17'
 False
->>> 2.99 < 3
+
+# An int can be converted to float for comparison.
+>>> 17 == 17.0
 True
->>> 1 < 1
-False
->>> 0 < 1
+
+# 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
-```
 
-## Equal to
+# An int can be converted to a complex number with a 0 imaginary part.
+>>> 17 == complex(17)
+True
 
-Operator `==` tests if the first operand's value is equal to the second one's
+# The fraction 2/5 can be converted to the float 0.4
+>>> 0.4 == 2/5
+True
 
-```python
->>> 3 == 1
-False
->>> 2.99 == 3
-False
->>> 1 == 1
+>>> complex(2/5, 1/2) == complex(0.4, 0.5)
 True
->>> 0 == 1
-False
 ```
 
-## Greater than or equal to
-
-Operator `>=` tests if the first operand's value is equal to or greater than the second one's.
+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
->>> 3 >= 1
-True
->>> 2.99 >= 3
+>>> x = float('NaN')
+
+>>> 3 < x
 False
->>> 1 >= 1
-True
->>> 0 >= 1
+
+>>> x < 3
+False
+
+# NaN never compares equal to NaN
+>>> x == x
 False
 ```
 
-## Less than or equal to
+## Comparing Strings
 
-Operator `<=` tests if the first operand's value is equal to or less than the second one's.
+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.
+Unlike in Python 2.x, in Python 3.x, `str` and `bytes` cannot be directly coerced/compared.
 
 ```python
->>> 3 <= 1
+>>> 'Python' > 'Rust'
 False
->>> 2.99 <= 3
-True
->>> 1 <= 1
+
+>>> 'Python' > 'JavaScript'
 True
->>> 0 <= 1
+
+# Examples with Mandarin.
+# hello < goodbye
+>>> '你好' < '再见'
 True
-```
 
-## Not equal to
+# ord() of first characters
+>>> ord('你'), ord('再')
+(20320, 20877)
 
-Operator `!=` tests if the first operand's value is not equal to the second one's
+# ord() of second characters
+>>> ord('好'), ord('见')
+(22909, 35265)
 
-```python
->>> 3 != 1
-True
->>> 2.99 != 3
-True
->>> 1 != 1
+# And with Korean words.
+# Pretty < beautiful.
+>>> '예쁜' < '아름다운'
 False
->>> 0 != 1
-True
+
+>>> ord('예'), ord('아')
+(50696, 50500)
 ```
 
-## Identity test
+## 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`.
 
-Operator `is` tests if the first and second operand is the same object.
+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
-# comparing non-object type `is` will raise warning
->>> 1 is 1
-<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
+>>> x = 2
+>>> y = 5
+>>> z = 10
+
+>>> x < y < z
 True
->>> 1 is 2
-<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
+
+>>> x < y > z
 False
->>> x = int(4)
->>> y = x
->>> x is y
-True
->>> y = int(5)
->>> x is y
+
+>>> x > y < z
 False
 ```
 
-Operator `is not` tests if the first and second operand is not the same object.
+## 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
->>> 1 is not 1
-<stdin>:1: SyntaxWarning: "is not" with a literal. Did you mean "!="?
-False
->>> 1 is not 2
-<stdin>:1: SyntaxWarning: "is not" with a literal. Did you mean "!="?
+>>> my_fav_numbers = [1, 2, 3]
+
+>>> your_fav_numbers = my_fav_numbers
+
+>>> my_fav_numbers is your_fav_numbers
 True
->>> x = int(4)
->>> y = x
->>> x is not y
+
+# 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
->>> y = int(5)
->>> x is not y
+
+>>> my_fav_numbers is not None
 True
+
+>>> my_fav_numbers is NotImplemented
+False
 ```
 
-## Containment test
+## Membership comparisons
 
-Operator `in` tests if the first operand is a member of the second operand.
+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
->>> x = [1, 2, 3, 4, 5]
->>> 1 in x
-True
->>> 2 in x
+>>> 
+# A set of lucky numbers.
+>>> lucky_numbers = {11, 22, 33}
+>>> 22 in lucky_numbers
 True
->>> 3 in x
-True
->>> 4 in x
-True
->>> 5 in x
-True
->>> 6 in x
+
+>>> 44 in lucky_numbers
 False
-```
 
-Operator `not in` tests if the first operand is not a member of the second operand.
+# A dictionary of employee information.
+>>> employee = {'name': 'John Doe', 'id': 67826, 'age': 33, 'title': 'ceo'}
 
-```python
->>> x = [1, 2, 3, 4, 5]
->>> 1 not in x
-False
->>> 2 not in x
-False
->>> 3 not in x
-False
->>> 4 not in x
-False
->>> 5 not in x
+# Checking for the membership of certain keys.
+>>> 'age' in employee
+True
+
+>>> 33 in employee
 False
->>> 6 not in x
+
+>>> 'lastname' not in employee
 True
+
+# Checking for substring membership
+>>> name = 'Super Batman'
+>>> 'Bat' in name
+True
+
+>>> 'Batwoman' in name
+False
 ```
 
-[python3-docs]: https://docs.python.org/3/library/operator.html
\ No newline at end of file
+[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
diff --git a/exercises/concept/black-jack/.meta/config.json b/exercises/concept/black-jack/.meta/config.json
index c120dafa..76e4fc7b 100644
--- a/exercises/concept/black-jack/.meta/config.json
+++ b/exercises/concept/black-jack/.meta/config.json
@@ -1,8 +1,8 @@
 {
   "blurb": "Learn about comparisons by implementing some Black Jack judging rules.",
-  "authors": ["Ticktakto", "Yabby1997", "limm-jk", "OMEGA-Y", "wnstj2007", "pranasziaukas"],
+  "authors": ["Ticktakto", "Yabby1997", "limm-jk", "OMEGA-Y", "wnstj2007", "pranasziaukas", "bethanyG"],
   "icon": "poker",
-  "contributors": ["bethanyg"],
+  "contributors": [],
   "files": {
     "solution": ["black_jack.py"],
     "test": ["black_jack_test.py"],
diff --git a/exercises/concept/black-jack/.meta/exemplar.py b/exercises/concept/black-jack/.meta/exemplar.py
index 89d26bc1..98ceca15 100644
--- a/exercises/concept/black-jack/.meta/exemplar.py
+++ b/exercises/concept/black-jack/.meta/exemplar.py
@@ -1,68 +1,92 @@
+"""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 (J, Q, K = 10, numerical value otherwise).
+    :return: int - value of a given card (J, Q, K = 10, 'A' = 1) numerical value otherwise.
     """
 
-    if card in ('J', 'Q', 'K'):
+    if card in('JQK'):
         value = 10
+
+    elif card == 'A':
+        value = 1
+
     else:
         value = int(card)
+
     return value
 
-def value_of_ace(hand_value):
+
+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.  J, Q, K = 10, 'A' = 1, all others are numerical value.
+    :return: higher value card - str. Tuple of both cards if they are of equal value.
     """
 
-    :param hand_value: int - current hand value.
+    card_one_value = value_of_card(card_one)
+    card_two_value = value_of_card(card_two)
+
+    if card_one_value == card_two_value:
+        result = card_one, card_two
+
+    elif card_one_value > card_two_value:
+        result = card_one
+
+    else:
+        result = card_two
+
+    return result
+
+
+def value_of_ace(card_one, card_two):
+    """Calculate the most advantageous value for the ace card.
+
+    :param card_one, card_two: str - card (J, Q, K == 10, numerical value otherwise)
     :return: int - value of the upcoming ace card (either 1 or 11).
     """
 
-    if hand_value + 11 > 21:
-        value = 1
+    if 11 + (value_of_card(card_one) + value_of_card(card_two)) > 21:
+        ace_value = 1
+
     else:
-        value = 11
-    return value
+        ace_value = 11
+
+    return ace_value
+
 
 def is_blackjack(card_one, card_two):
-    """
+    """Determine if the hand is a 'natural' or 'blackjack'.
 
-    :param card_one: str - first card in hand.
-    :param card_two: str - second card in hand.
+    :param card_one, card_two: str - cards dealt.  J, Q, K = 10, 'A' = 11, all others are numerical value.
     :return: bool - if the hand is a blackjack (two cards worth 21).
     """
 
-    if card_one == 'A' and card_two != 'A':
-        blackjack = value_of_card(card_two) == 10
-    elif card_one != 'A' and card_two == 'A':
-        blackjack = value_of_card(card_one) == 10
-    else:
-        blackjack = False
-    return blackjack
+    return (card_one == 'A' or card_two == 'A') and (value_of_card(card_one) == 10 or value_of_card(card_two) == 10)
+
 
 def can_split_pairs(card_one, card_two):
-    """
+    """Determine if a player can split their hand into two hands.
 
-    :param card_one: str - first card in hand.
-    :param card_two: str - second card in hand.
+    :param card_one, card_two: str - cards in hand.
     :return: bool - if the hand can be split into two pairs (i.e. cards are of the same value).
     """
 
-    if card_one == 'A' or card_two == 'A':
-        split_pairs = card_one == card_two
-    else:
-        split_pairs = value_of_card(card_one) == value_of_card(card_two)
-    return split_pairs
+    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: str - first card in hand.
-    :param card_two: str - second card in hand.
+    :param card_one, card_two: str - first and second cards in hand.
     :return: bool - if the hand can be doubled down (i.e. totals 9, 10 or 11 points).
     """
 
-    card_one_value = 1 if card_one == 'A' else value_of_card(card_one)
-    card_two_value = 1 if card_two == 'A' else value_of_card(card_two)
-    hand_value = card_one_value + card_two_value
-    return 9 <= hand_value <= 11
+    return 8 < value_of_card(card_one) + value_of_card(card_two) < 12
diff --git a/exercises/concept/black-jack/black_jack.py b/exercises/concept/black-jack/black_jack.py
index 7343184f..5965c3f8 100644
--- a/exercises/concept/black-jack/black_jack.py
+++ b/exercises/concept/black-jack/black_jack.py
@@ -1,17 +1,33 @@
+"""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 (J, Q, K = 10, numerical value otherwise).
+    :return: int - value of a given card (J, Q, K = 10, 'A' = 1) numerical value otherwise.
     """
 
     pass
 
+def higher_card(card_one, card_two):
+    """Determine which card has a higher value in the hand.
 
-def value_of_ace(hand_value):
+    :param card_one, card_two: str - cards dealt.  J, Q, K = 10, 'A' = 1, all others are numerical value.
+    :return: higher value card - str. Tuple of both cards if they are of equal value.
     """
 
-    :param hand_value: int - current hand 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 (J, Q, K == 10, numerical value otherwise)
     :return: int - value of the upcoming ace card (either 1 or 11).
     """
 
@@ -19,10 +35,9 @@ def value_of_ace(hand_value):
 
 
 def is_blackjack(card_one, card_two):
-    """
+    """Determine if the hand is a 'natural' or 'blackjack'.
 
-    :param card_one: str - first card in hand.
-    :param card_two: str - second card in hand.
+    :param card_one, card_two: str - cards dealt.  J, Q, K = 10, 'A' = 11, all others are numerical value.
     :return: bool - if the hand is a blackjack (two cards worth 21).
     """
 
@@ -30,10 +45,9 @@ def is_blackjack(card_one, card_two):
 
 
 def can_split_pairs(card_one, card_two):
-    """
+    """Determine if a player can split their hand into two hands.
 
-    :param card_one: str - first card in hand.
-    :param card_two: str - second card in hand.
+    :param card_one, card_two: str - cards in hand.
     :return: bool - if the hand can be split into two pairs (i.e. cards are of the same value).
     """
 
@@ -41,10 +55,9 @@ def can_split_pairs(card_one, card_two):
 
 
 def can_double_down(card_one, card_two):
-    """
+    """Determine if a blackjack player can place a double down bet.
 
-    :param card_one: str - first card in hand.
-    :param card_two: str - second card in hand.
+    :param card_one, card_two: str - first and second cards in hand.
     :return: bool - if the hand can be doubled down (i.e. totals 9, 10 or 11 points).
     """
 
diff --git a/instructions.md b/instructions.md
deleted file mode 100644
index 01ce2e1f..00000000
--- a/instructions.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# Instructions
-
-The [ISBN-10 verification process](https://en.wikipedia.org/wiki/International_Standard_Book_Number) is used to validate book identification
-numbers. These normally contain dashes and look like: `3-598-21508-8`
-
-## ISBN
-
-The ISBN-10 format is 9 digits (0 to 9) plus one check character (either a digit or an X only). In the case the check character is an X, this represents the value '10'. These may be communicated with or without hyphens, and can be checked for their validity by the following formula:
-
-```text
-(x1 * 10 + x2 * 9 + x3 * 8 + x4 * 7 + x5 * 6 + x6 * 5 + x7 * 4 + x8 * 3 + x9 * 2 + x10 * 1) mod 11 == 0
-```
-
-If the result is 0, then it is a valid ISBN-10, otherwise it is invalid.
-
-## Example
-
-Let's take the ISBN-10 `3-598-21508-8`. We plug it in to the formula, and get:
-
-```text
-(3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 == 0
-```
-
-Since the result is 0, this proves that our ISBN is valid.
-
-## Task
-
-Given a string the program should check if the provided string is a valid ISBN-10.
-Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN.
-
-The program should be able to verify ISBN-10 both with and without separating dashes.
-
-## Caveats
-
-Converting from strings to numbers can be tricky in certain languages.
-Now, it's even trickier since the check digit of an ISBN-10 may be 'X' (representing '10'). For instance `3-598-21507-X` is a valid ISBN-10.
-
-## Bonus tasks
-
-* Generate a valid ISBN-13 from the input ISBN-10 (and maybe verify it again with a derived verifier).
-
-* Generate valid ISBN, maybe even from a given starting ISBN.


Test patch:
diff --git a/exercises/concept/black-jack/black_jack_test.py b/exercises/concept/black-jack/black_jack_test.py
index bfef90bf..bb6cc908 100644
--- a/exercises/concept/black-jack/black_jack_test.py
+++ b/exercises/concept/black-jack/black_jack_test.py
@@ -1,12 +1,14 @@
 import unittest
 import pytest
+
 from black_jack import (
-    value_of_card,
-    value_of_ace,
-    is_blackjack,
-    can_split_pairs,
-    can_double_down
-)
+                        value_of_card,
+                        higher_card,
+                        value_of_ace,
+                        is_blackjack,
+                        can_split_pairs,
+                        can_double_down
+                        )
 
 
 class BlackJackTest(unittest.TestCase):
@@ -14,96 +16,84 @@ class BlackJackTest(unittest.TestCase):
     @pytest.mark.task(taskno=1)
     def test_value_of_card(self):
         data = [
-            ('2', 2),
-            ('5', 5),
-            ('8', 8),
-            ('10', 10),
-            ('J', 10),
-            ('Q', 10),
-            ('K', 10),
-        ]
+                ('2', 2), ('5', 5), ('8', 8),
+                ('A', 1), ('10', 10), ('J', 10),
+                ('Q', 10), ('K', 10)]
 
         for variant, (card, value) in enumerate(data, 1):
             with self.subTest(f'variation #{variant}', input=card, output=value):
-                self.assertEqual(
-                    value,
-                    value_of_card(card),
-                    msg=f'Expected {value} as the value of {card}.'
-                )
+                error_msg = f'Expected {value} as the value of {card}.'
+
+                self.assertEqual(value_of_card(card), value, msg=error_msg)
 
     @pytest.mark.task(taskno=2)
-    def test_value_of_ace(self):
+    def test_higher_card(self):
         data = [
-            (2, 11),
-            (5, 11),
-            (7, 11),
-            (9, 11),
-            (10, 11),
-            (11, 1),
-            (12, 1),
-            (15, 1),
-            (19, 1),
-            (20, 1),
-        ]
-
-        for variant, (hand_value, ace_value) in enumerate(data, 1):
-            with self.subTest(f'variation #{variant}', input=hand_value, output=ace_value):
-                self.assertEqual(
-                    ace_value,
-                    value_of_ace(hand_value),
-                    msg=f'Expected {ace_value} as the value of ace when the hand is worth {hand_value}.'
-                )
+                ('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, result) in enumerate(data, 1):
+            with self.subTest(f'variation #{variant}', card_one=card_one, card_two=card_two, output=result):
+                error_msg = f'Expected {result} as the higher value of the cards {card_one, card_two}.'
+
+                self.assertEqual(higher_card(card_one, card_two), result, msg=error_msg)
 
     @pytest.mark.task(taskno=3)
+    def test_value_of_ace(self):
+        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)]
+
+        for variant, (card_one, card_two, ace_value) in enumerate(data, 1):
+            with self.subTest(f'variation #{variant}', card_one=card_one, card_two=card_two, ace_value=ace_value):
+                error_msg = f'Expected {ace_value} as the value of an ace card when the hand has {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):
         data = [
-            (('A', 'K'), True),
-            (('10', 'A'), True),
-            (('10', '9'), False),
-            (('A', 'A'), False),
-        ]
+                (('A', 'K'), True), (('10', 'A'), True),
+                (('10', '9'), False), (('A', 'A'), False)]
 
         for variant, (hand, blackjack) in enumerate(data, 1):
             with self.subTest(f'variation #{variant}', input=hand, output=blackjack):
-                self.assertEqual(
-                    blackjack,
-                    is_blackjack(*hand),
-                    msg=f'Hand {hand} {"is" if blackjack else "is not"} a blackjack.'
-                )
+                error_msg=f'Hand {hand} {"is" if blackjack else "is not"} a blackjack.'
 
-    @pytest.mark.task(taskno=4)
+                self.assertEqual( is_blackjack(*hand), blackjack, msg=error_msg)
+
+
+    @pytest.mark.task(taskno=5)
     def test_can_split_pairs(self):
         data = [
-            (('Q', 'K'), True),
-            (('6', '6'), True),
-            (('A', 'A'), True),
-            (('10', 'A'), False),
-            (('10', '9'), False),
-        ]
+                (('Q', 'K'), True), (('6', '6'), True), (('A', 'A'), True),
+                (('10', 'A'), False), (('10', '9'), False)]
 
         for variant, (hand, split_pairs) in enumerate(data, 1):
             with self.subTest(f'variation #{variant}', input=hand, output=split_pairs):
-                self.assertEqual(
-                    split_pairs,
-                    can_split_pairs(*hand),
-                    msg=f'Hand {hand} {"can" if split_pairs else "cannot"} be split into pairs.'
-                )
+                error_msg=f'Hand {hand} {"can" if split_pairs else "cannot"} be split into pairs.'
 
-    @pytest.mark.task(taskno=5)
+                self.assertEqual(can_split_pairs(*hand), split_pairs, msg=error_msg)
+
+
+    @pytest.mark.task(taskno=6)
     def test_can_double_down(self):
         data = [
-            (('A', '9'), True),
-            (('K', 'A'), True),
-            (('4', '5'), True),
-            (('A', 'A'), False),
-            (('10', '2'), False),
-            (('10', '9'), False),
-        ]
+                (('A', '9'), True), (('K', 'A'), True), (('4', '5'), True),
+                (('A', 'A'), False), (('10', '2'), False), (('10', '9'), False)]
 
         for variant, (hand, double_down) in enumerate(data, 1):
             with self.subTest(f'variation #{variant}', input=hand, output=double_down):
-                self.assertEqual(
-                    double_down,
-                    can_double_down(*hand),
-                    msg=f'Hand {hand} {"can" if double_down else "cannot"} be doubled down.'
-                )
+                error_msg = f'Hand {hand} {"can" if double_down else "cannot"} be doubled down.'
+
+                self.assertEqual(can_double_down(*hand), double_down, msg=error_msg)