Repository: exercism/python
Pull request #3420 (2023-05-09 06:50:15)

Write approaches for Yacht
As per the blog post on Freeing our Maintainers, the community contributions pause has an exception for writing approaches. This is for Yacht.

Let me know your suggestions. This is my first time, so my apologies if there are any errors in the format.


Patch:
diff --git a/concepts/generators/.meta/config.json b/concepts/generators/.meta/config.json
index 2204a700..6c29169d 100644
--- a/concepts/generators/.meta/config.json
+++ b/concepts/generators/.meta/config.json
@@ -1,5 +1,5 @@
 {
-  "blurb": "Learn about generators by assigning seats to passengers.",
+  "blurb": "Generator are functions that returns a lazy iterator, lazy iterator is an iterator like: list, tuple, etc. But doesn't need store its content in memory",
   "authors": ["J08K"],
   "contributors": []
 }
diff --git a/concepts/generators/about.md b/concepts/generators/about.md
index f1b97291..9a26ab55 100644
--- a/concepts/generators/about.md
+++ b/concepts/generators/about.md
@@ -4,65 +4,63 @@
 
 Generators are constructed much like other looping or recursive functions, but require a [`yield` expression](#the-yield-expression), which we will explore in depth a bit later.
 
-
 An example is a function that returns the _squares_ from a given list of numbers.  
-As currently written, all input must be processed before any values can be returned:  
-
+As currently written, all input must be processed before any values can be returned:
 
 ```python
 >>> def squares(list_of_numbers):
->>>     squares = []
->>>     for number in list_of_numbers:
->>>         squares.append(number ** 2)
->>>     return squares
+...     squares = []
+...     for number in list_of_numbers:
+...         squares.append(number ** 2)
+...     return squares
 ```
 
 You can convert that function into a generator like this:
 
 ```python
-def squares(list_of_numbers):
-    for number in list_of_number:
-        yield number ** 2
+>>> def squares_generator(list_of_numbers):
+...     for number in list_of_numbers:
+...         yield number ** 2
 ```
 
 The rationale behind this is that you use a generator when you do not need all the values _at once_.
 
 This saves memory and processing power, since only the value you are _currently working on_ is calculated.
 
-
 ## Using a generator
 
-Generators may be used in place of most `iterables` in Python. This includes  _functions_ or _objects_ that require an `iterable`/`iterator` as an argument.
+Generators may be used in place of most `iterables` in Python. This includes _functions_ or _objects_ that require an `iterable`/`iterator` as an argument.
 
-To use the `squares()` generator:
+To use the `squares_generator()` generator:
 
 ```python
->>> squared_numbers = squares([1, 2, 3, 4])
+>>> squared_numbers = squares_generator([1, 2, 3, 4])
 
 >>> for square in squared_numbers:
->>>     print(square)
+...     print(square)
+...
 1
 4
 9
 16
 ```
 
-Values within a generator can also be produced/accessed via the `next()` function. 
+Values within a generator can also be produced/accessed via the `next()` function.
 `next()` calls the `__next__()` method of a generator object, "advancing" or evaluating the generator code up to its `yield` expression, which then "yields" or returns the value.
 
 ```python
-square_generator = squares([1, 2])
+>>> squared_numbers = squares_generator([1, 2])
 
->>> next(square_generator)
+>>> next(squared_numbers)
 1
->>> next(square_generator)
+>>> next(squared_numbers)
 4
 ```
 
 When a `generator` is fully consumed and has no more values to return, it throws a `StopIteration` error.
 
 ```python
->>> next(square_generator)
+>>> next(squared_numbers)
 Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
 StopIteration
@@ -72,12 +70,12 @@ StopIteration
 
 Generators are a special sub-set of _iterators_.
 `Iterators` are the mechanism/protocol that enables looping over _iterables_.
-Generators and and the iterators returned by common Python (`iterables`)[https://wiki.python.org/moin/Iterator] act very similarly, but there are some important differences to note:
-
+Generators and the iterators returned by common Python [`iterables`][iterables] act very similarly, but there are some important differences to note:
 
 - Generators are _one-way_; there is no "backing up" to a previous value.
 
 - Iterating over generators consume the returned values; no resetting.
+
 - Generators (_being lazily evaluated_) are not sortable and can not be reversed.
 
 - Generators do _not_ have `indexes`, so you can't reference a previous or future value using addition or subtraction.
@@ -88,7 +86,7 @@ Generators and and the iterators returned by common Python (`iterables`)[https:/
 
 ## The yield expression
 
-The [yield expression](https://docs.python.org/3.8/reference/expressions.html#yield-expressions) is very similar to the `return` expression.
+The [yield expression][yield expression] is very similar to the `return` expression.
 
 _Unlike_ the `return` expression, `yield` gives up values to the caller at a _specific point_, suspending evaluation/return of any additional values until they are requested.
 
@@ -96,14 +94,16 @@ When `yield` is evaluated, it pauses the execution of the enclosing function and
 
 The function then _stays in scope_, and when `__next__()` is called, execution resumes until `yield` is encountered again.
 
-Note: _Using `yield` expressions is prohibited outside of functions._
+```exercism/note
+Using `yield` expressions is prohibited outside of functions.
+```
 
 ```python
 >>> def infinite_sequence():
->>>     current_number = 0
->>>     while True:
->>>         yield current_number
->>>         current_number += 1
+...     current_number = 0
+...     while True:
+...         yield current_number
+...         current_number += 1
 
 >>> lets_try = infinite_sequence()
 >>> lets_try.__next__()
@@ -123,10 +123,13 @@ Generators are also very helpful when a process or calculation is _complex_, _ex
 
 ```python
 >>> def infinite_sequence():
->>>     current_number = 0
->>>     while True:
->>>         yield current_number
->>>         current_number += 1
+...     current_number = 0
+...     while True:
+...         yield current_number
+...         current_number += 1
 ```
 
 Now whenever `__next__()` is called on the `infinite_sequence` object, it will return the _previous number_ + 1.
+
+[iterables]: https://wiki.python.org/moin/Iterator
+[yield expression]: https://docs.python.org/3.11/reference/expressions.html#yield-expressions
diff --git a/concepts/generators/introduction.md b/concepts/generators/introduction.md
index 2c148371..82a686d1 100644
--- a/concepts/generators/introduction.md
+++ b/concepts/generators/introduction.md
@@ -1,5 +1,7 @@
 # Introduction
 
-A generator in Python is a _callable function_ that returns a [lazy iterator](https://en.wikipedia.org/wiki/Lazy_evaluation).
+A generator in Python is a _callable function_ that returns a [lazy iterator][lazy iterator].
 
 _Lazy iterators_ are similar to `lists`, and other `iterators`, but with one key difference: They do not store their `values` in memory, but _generate_ their values when needed.
+
+[lazy iterator]: https://en.wikipedia.org/wiki/Lazy_evaluation
diff --git a/concepts/generators/links.json b/concepts/generators/links.json
index b8ae2f7b..972bbe7a 100644
--- a/concepts/generators/links.json
+++ b/concepts/generators/links.json
@@ -1,10 +1,14 @@
 [
   {
-    "url": "https://docs.python.org/3.8/reference/expressions.html#yield-expressions",
-    "description": "Official Python 3.8 docs for the yield expression."
+    "url": "https://docs.python.org/3.10/reference/expressions.html#yield-expressions",
+    "description": "Official Python 3.10 docs for the yield expression."
   },
   {
     "url": "https://en.wikipedia.org/wiki/Lazy_evaluation",
     "description": "Wikipedia page about lazy evaluation"
+  },
+  {
+    "url": "https://realpython.com/introduction-to-python-generators/",
+    "description": "Real python, introduction to generators and yield"
   }
 ]
diff --git a/config.json b/config.json
index 1d118f79..038123f6 100644
--- a/config.json
+++ b/config.json
@@ -184,7 +184,7 @@
         "name": "Plane Tickets",
         "uuid": "3ba3fc89-3e1b-48a5-aff0-5aeaba8c8810",
         "concepts": ["generators"],
-        "prerequisites": ["conditionals", "dicts", "lists", "loops"],
+        "prerequisites": ["conditionals", "dicts", "lists", "loops", "classes"],
         "status": "wip"
       },
       {
@@ -1247,14 +1247,6 @@
         ],
         "difficulty": 3
       },
-      {
-        "slug": "diffie-hellman",
-        "name": "Diffie-Hellman",
-        "uuid": "92e2d5f8-7d8a-4e81-a55c-52fa6be80c74",
-        "practices": ["numbers"],
-        "prerequisites": ["basics", "bools", "numbers"],
-        "difficulty": 3
-      },
       {
         "slug": "connect",
         "name": "Connect",
@@ -2201,6 +2193,15 @@
         "difficulty": 3,
         "status": "deprecated"
       },
+      {
+        "slug": "diffie-hellman",
+        "name": "Diffie-Hellman",
+        "uuid": "92e2d5f8-7d8a-4e81-a55c-52fa6be80c74",
+        "practices": [],
+        "prerequisites": [],
+        "difficulty": 3,
+        "status": "deprecated"
+      },
       {
         "slug": "trinary",
         "name": "Trinary",
diff --git a/exercises/concept/plane-tickets/.docs/hints.md b/exercises/concept/plane-tickets/.docs/hints.md
index 72d814b2..11508ee3 100644
--- a/exercises/concept/plane-tickets/.docs/hints.md
+++ b/exercises/concept/plane-tickets/.docs/hints.md
@@ -1,11 +1,24 @@
 # Hints
 
-## 1. Generate an amount of seats
+## 1. Generate seat letters
+
+- The returned value should be of _type_ `generator`.
+- You can have a sequence of letters from `A` to `D` and cycle through them.
+- And use `yield` to return the next letter.
+
+## 2. Generate an amount of seats
 
 - The returned value should be of _type_ `generator`.
 - Row `13` should be skipped, so go from `12` to `14`.
 - Keep in mind that the returned values should be ordered from low to high. `1A, 1B, 2A, ...`
+- It might be good to reuse or call other functions you have already completed here.
 
-## 2. Assign seats to passengers
+## 3. Assign seats to passengers
 
 - Make sure your seat numbers do not have any space in them.
+- It might be good to reuse or call other functions you have already completed here.
+
+## 4. Ticket codes
+
+- You can use `len()` to get the length of a string.
+- You can use `"<string>" * <int>` to repeat a string.
diff --git a/exercises/concept/plane-tickets/.docs/instructions.md b/exercises/concept/plane-tickets/.docs/instructions.md
index 290aad2e..b22a84f2 100644
--- a/exercises/concept/plane-tickets/.docs/instructions.md
+++ b/exercises/concept/plane-tickets/.docs/instructions.md
@@ -2,32 +2,51 @@
 
 Conda airlines is the programming-world's biggest airline, with over 10.000 flights a day!
 
-They are currently assigning all seats to passengers by hand, this will need to automated.
+They are currently assigning all seats to passengers by hand, this will need to be automated.
 
-They have asked _you_ to create software to automate the assigning of seats to passengers. They require your software to be memory efficient and performant.
+They have asked _you_ to create software to automate the assigning of seats to passengers.
+They require your software to be memory efficient and performant.
 
-Conda's airplanes have up to _4 seats_ in each row, and each airplane has many rows.
+## 1. Generate seat letters
 
-While the rows are defined using numbers, seats in each row are defined using letters from the alphabet, with `seat A` being the first _seat_ in the row.
+Conda wants to generate seat letters for their airplanes.
+An airplane is made of rows of seats.
+Each row has _4 seats_.
+The rows seats has the same naming: `A`, `B`, `C`, `D`.
+Meaning the first seat in the row is `A`, the second seat in the row is `B`, and so on.
+After reaching `D` it should start again with `A`.
 
-You can use this table as a guide:
+Implement a function `generate_seat_letters()` that accepts an `int` that holds how many seat letters to be generated.
+The function should then return an _iterable_ of seat letters.
 
-| x             | 1         | 2     |
-| :----:        | :----:    | :----:|
-| Row           | 5         | 21    |
-| Seat letter   | A         | D     |
-| Result        | 5A        | 21D   |
+```python
+>>> letters = generate_seat_letters(4)
+>>> next(letters)
+"A"
+>>> next(letters)
+"B"
+```
 
-## 1. Generate an amount of seats
+## 2. Generate an amount of seats
 
-Implement the `generate_seats()` function that returns an _iterable_ of seats given the following variable:
+Conda wants a system that can generate an amount of seats for their airplanes.
+Each airplane has _4 seats_ in each row.
+The rows are defined using numbers, starting from `1` and going up.
+The seats should be ordered, like: `1A`, `1B`, `1C`, `1D`, `2A`, `2B`, `2C`, `2D`, `3A`, `3B`, `3C`, `3D`, ...
 
-`amount`: The amount of seats to be generated.
+Here is an example:
+
+|      x      |  1  |  2  |
+| :---------: | :-: | :-: |
+|     Row     |  5  | 21  |
+| Seat letter |  A  |  D  |
+|   Result    | 5A  | 21D |
 
 Many airlines do not have _row_ number 13 on their flights, due to superstition amongst passengers.
 Conda Airlines also follows this convention, so make sure you _don't_ generate seats for _row_ number 13.
 
-_Note: The returned seats should be ordered, like: 1A 1B 1C._
+Implement a function `generate_seats()` that accepts an `int` that holds how many seats to be generated.
+The function should then return an _iterable_ of seats given.
 
 ```python
 >>> seats = generate_seats(10)
@@ -37,29 +56,32 @@ _Note: The returned seats should be ordered, like: 1A 1B 1C._
 "1B"
 ```
 
-## 2. Assign seats to passengers
+## 3. Assign seats to passengers
 
-Implement the `assign_seats()` function that returns a _dictionary_ of `passenger` as _key_, and `seat_number` as _value_. Given is the following _list_:
+Now that you have a function that generates seats, you can use it to assign seats to passengers.
 
-`passengers`: A list containing passenger names.
+Implement a function `assign_seats()` that accepts a `list` of passenger names.
+The function should then return a _dictionary_ of `passenger` as _key_, and `seat_number` as _value_.
 
 ```python
->>> passengers = ['Jerimiah', 'Eric', 'Bethaney', 'Byte', 'SqueekyBoots', 'Bob']
+>>> passengers = ['Jerimiah', 'Eric', 'Bethany', 'Byte', 'SqueekyBoots', 'Bob']
 
 >>> assign_seats(passengers)
-{'Jerimiah': '1A', 'Eric': '1B', 'Bethaney': '1C', 'Byte': '1D', 'SqueekyBoots': '2A', 'Bob': '2B'}
+{'Jerimiah': '1A', 'Eric': '1B', 'Bethany': '1C', 'Byte': '1D', 'SqueekyBoots': '2A', 'Bob': '2B'}
 ```
 
-## 3. Ticket codes
-
-Each ticket has a _12_ character long string code for identification.
+## 4. Ticket codes
 
-This code begins with the `assigned_seat` followed by the `flight_id`. The rest of the code is appended by `0s`.
+Conda Airlines would like to have a unique code for each ticket.
+Since they are a big airline, they have a lot of flights.
+Meaning that there are multiple flights with the same seat number.
+They want you to create a system that creates a unique ticket that is _12_ characters long string code for identification.
 
-Implement a `generator` that yields a `ticket_number` given the following arguments:
+This code begins with the `assigned_seat` followed by the `flight_id`.
+The rest of the code is appended by `0s`.
 
-`seat_numbers`: A _list_ of *seat_numbers*.
-`flight_id`: A string containing the flight identification.
+Implement a function `generate_codes()` that accepts a `list` of `seat_numbers` and a `string` with the flight number.
+The function should then return a `generator` that yields a `ticket_number`.
 
 ```python
 >>> seat_numbers = ['1A', '17D']
diff --git a/exercises/concept/plane-tickets/.docs/introduction.md b/exercises/concept/plane-tickets/.docs/introduction.md
index 1b557b44..5ab9d6d2 100644
--- a/exercises/concept/plane-tickets/.docs/introduction.md
+++ b/exercises/concept/plane-tickets/.docs/introduction.md
@@ -1,5 +1,135 @@
-# Introduction
+# About
 
-A generator in Python is a _callable function_ that returns a [lazy iterator](https://en.wikipedia.org/wiki/Lazy_evaluation).
+## Constructing a generator
 
-_Lazy iterators_ are similar to iterables such as `lists`, and other types of `iterators` in Python -- but with one key difference: `generators` do not store their `values` in memory, but _generate_ their values as needed or when called.
+Generators are constructed much like other looping or recursive functions, but require a [`yield` expression](#the-yield-expression), which we will explore in depth a bit later.
+
+An example is a function that returns the _squares_ from a given list of numbers.  
+As currently written, all input must be processed before any values can be returned:
+
+```python
+>>> def squares(list_of_numbers):
+...     squares = []
+...     for number in list_of_numbers:
+...         squares.append(number ** 2)
+...     return squares
+```
+
+You can convert that function into a generator like this:
+
+```python
+>>> def squares_generator(list_of_numbers):
+...     for number in list_of_numbers:
+...         yield number ** 2
+```
+
+The rationale behind this is that you use a generator when you do not need all the values _at once_.
+
+This saves memory and processing power, since only the value you are _currently working on_ is calculated.
+
+## Using a generator
+
+Generators may be used in place of most `iterables` in Python. This includes _functions_ or _objects_ that require an `iterable`/`iterator` as an argument.
+
+To use the `squares_generator()` generator:
+
+```python
+>>> squared_numbers = squares_generator([1, 2, 3, 4])
+
+>>> for square in squared_numbers:
+...     print(square)
+...
+1
+4
+9
+16
+```
+
+Values within a generator can also be produced/accessed via the `next()` function.
+`next()` calls the `__next__()` method of a generator object, "advancing" or evaluating the generator code up to its `yield` expression, which then "yields" or returns the value.
+
+```python
+>>> squared_numbers = squares_generator([1, 2])
+
+>>> next(squared_numbers)
+1
+>>> next(squared_numbers)
+4
+```
+
+When a `generator` is fully consumed and has no more values to return, it throws a `StopIteration` error.
+
+```python
+>>> next(squared_numbers)
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+StopIteration
+```
+
+### Difference between iterables and generators
+
+Generators are a special sub-set of _iterators_.
+`Iterators` are the mechanism/protocol that enables looping over _iterables_.
+Generators and the iterators returned by common Python [`iterables`][iterables] act very similarly, but there are some important differences to note:
+
+- Generators are _one-way_; there is no "backing up" to a previous value.
+
+- Iterating over generators consume the returned values; no resetting.
+
+- Generators (_being lazily evaluated_) are not sortable and can not be reversed.
+
+- Generators do _not_ have `indexes`, so you can't reference a previous or future value using addition or subtraction.
+
+- Generators cannot be used with the `len()` function.
+
+- Generators can be _finite_ or _infinite_, be careful when collecting all values from an _infinite_ generator.
+
+## The yield expression
+
+The [yield expression][yield expression] is very similar to the `return` expression.
+
+_Unlike_ the `return` expression, `yield` gives up values to the caller at a _specific point_, suspending evaluation/return of any additional values until they are requested.
+
+When `yield` is evaluated, it pauses the execution of the enclosing function and returns any values of the function _at that point in time_.
+
+The function then _stays in scope_, and when `__next__()` is called, execution resumes until `yield` is encountered again.
+
+```exercism/note
+Using `yield` expressions is prohibited outside of functions.
+```
+
+```python
+>>> def infinite_sequence():
+...     current_number = 0
+...     while True:
+...         yield current_number
+...         current_number += 1
+
+>>> lets_try = infinite_sequence()
+>>> lets_try.__next__()
+0
+>>> lets_try.__next__()
+1
+```
+
+## Why generators?
+
+Generators are useful in a lot of applications.
+
+When working with a large collection, you might not want to put all of its values into `memory`.
+A generator can be used to work on larger data piece-by-piece, saving memory and improving performance.
+
+Generators are also very helpful when a process or calculation is _complex_, _expensive_, or _infinite_:
+
+```python
+>>> def infinite_sequence():
+...     current_number = 0
+...     while True:
+...         yield current_number
+...         current_number += 1
+```
+
+Now whenever `__next__()` is called on the `infinite_sequence` object, it will return the _previous number_ + 1.
+
+[iterables]: https://wiki.python.org/moin/Iterator
+[yield expression]: https://docs.python.org/3.11/reference/expressions.html#yield-expressions
diff --git a/exercises/concept/plane-tickets/.meta/config.json b/exercises/concept/plane-tickets/.meta/config.json
index 016ff0ce..26981888 100644
--- a/exercises/concept/plane-tickets/.meta/config.json
+++ b/exercises/concept/plane-tickets/.meta/config.json
@@ -16,6 +16,6 @@
       ".meta/exemplar.py"
     ]
   },
-  "icon": "poker",
+  "icon": "new-passport",
   "blurb": "Learn about generators by assigning seats to passengers."
 }
diff --git a/exercises/concept/plane-tickets/.meta/design.md b/exercises/concept/plane-tickets/.meta/design.md
index 58542aab..96a4cc3c 100644
--- a/exercises/concept/plane-tickets/.meta/design.md
+++ b/exercises/concept/plane-tickets/.meta/design.md
@@ -2,16 +2,15 @@ This issue describes how to implement the `generators` concept exercise for the
 
 ## Goal
 
-The goal of this exercise is to teach the syntax and use of `generators` in Python. 
+The goal of this exercise is to teach the syntax and use of `generators` in Python.
 
 ## Learning objectives
 
--  Understand what generators are and how/when to use them
--  Understand how generators relate to `loops` and `iterators`
--  Understand how to use the `yield` keyword
--  Understand the `__next__()` method
--  Create a generator
-
+- Understand what generators are and how/when to use them
+- Understand how generators relate to `loops` and `iterators`
+- Understand how to use the `yield` keyword
+- Understand the `__next__()` method
+- Create a generator
 
 ## Out of scope
 
@@ -22,32 +21,29 @@ The goal of this exercise is to teach the syntax and use of `generators` in Pyth
 - `yield from`
 - `generators` used as coroutines
 
-
 ## Concepts covered
 
--  `generators`
--  `yield`
--   `__next__()`
--  `iterators`
-
+- `generators`
+- `yield`
+- `__next__()`
+- `iterators`
 
 ## Prerequisites
 
--  `conditionals`
--  `dicts`
--  `functions`
--  `higher-order-functions`
--  `lists`
--  `loops`
--  `iteration`
--  `iterators`
--  `sequences`
-
-
+- `conditionals`
+- `dicts`
+- `functions`
+- `higher-order-functions`
+- `lists`
+- `loops`
+- `iteration`
+- `iterators`
+- `sequences`
+- `classes`
 
 ## Resources to refer to
 
--  [Generators (Python official docs)](https://docs.python.org/3/howto/functional.html#generators)
+- [Generators (Python official docs)](https://docs.python.org/3/howto/functional.html#generators)
 - [generator (Python official docs glossary)](https://docs.python.org/3/glossary.html#term-generator)
 - [The yield statement (Python official docs)](https://docs.python.org/3/reference/simple_stmts.html#the-yield-statement)
 - [Yield expressions (Python official docs)](https://docs.python.org/3/reference/expressions.html#yieldexpr)
@@ -57,21 +53,20 @@ The goal of this exercise is to teach the syntax and use of `generators` in Pyth
 
 ### Hints
 
--  Referring to one or more of the resources linked above, or analogous resources from a trusted source.
-- `Generators` section of the Python Docs Functional How to tutorial:  [Generators](https://docs.python.org/3/howto/functional.html#generators)
-
+- Referring to one or more of the resources linked above, or analogous resources from a trusted source.
+- `Generators` section of the Python Docs Functional How to tutorial: [Generators](https://docs.python.org/3/howto/functional.html#generators)
 
-## Concept Description 
+## Concept Description
 
-(_a variant of this can be used for the `v3/languages/python/concepts/<concept>/about.md` doc and this exercises  `introduction.md` doc._)
+(_a variant of this can be used for the `v3/languages/python/concepts/<concept>/about.md` doc and this exercises `introduction.md` doc._)
 
 _**Concept Description Needs to Be Filled In Here/Written**_
 
 _Some "extras" that we might want to include as notes in the concept description, or as links in `links.json`:_
 
--  Additional `Generator-iterator methods`, such as `generator.send()` and `generator.throw()`
+- Additional `Generator-iterator methods`, such as `generator.send()` and `generator.throw()`
 - `generator expressions`
--  Asynchronous generator functions
+- Asynchronous generator functions
 - `generators` used as coroutines
 
 ## Implementing
@@ -80,10 +75,8 @@ The general Python track concept exercise implantation guide can be found [here]
 
 Tests should be written using `unittest.TestCase` and the test file named `generators_test.py`.
 
-Code in the `.meta/example.py` file should **only use syntax & concepts introduced in this exercise or one of its prerequisites.** Please do not use comprehensions, generator expressions, or other syntax not previously covered.  Please also follow [PEP8](https://www.python.org/dev/peps/pep-0008/) guidelines.
+Code in the `.meta/example.py` file should **only use syntax & concepts introduced in this exercise or one of its prerequisites.** Please do not use comprehensions, generator expressions, or other syntax not previously covered. Please also follow [PEP8](https://www.python.org/dev/peps/pep-0008/) guidelines.
 
 ## Help
 
 If you have any questions while implementing the exercise, please post the questions as comments in this issue, or contact one of the maintainers on our Slack channel.
-
-
diff --git a/exercises/concept/plane-tickets/.meta/exemplar.py b/exercises/concept/plane-tickets/.meta/exemplar.py
index fa8927d7..9a3d7024 100644
--- a/exercises/concept/plane-tickets/.meta/exemplar.py
+++ b/exercises/concept/plane-tickets/.meta/exemplar.py
@@ -1,15 +1,32 @@
-"""Plane Tickets Exercise"""
+"""Functions to automate Conda airlines ticketing system."""
 
 import math
 
 SEATS_IN_ROW = ['A', 'B', 'C', 'D']
 
-def generate_seats(amount):
 
+def generate_seat_letters(amount):
+    """Generate a series of seat letters for airline boarding.
+
+    :param amount: int - amount of seat letters to be generated.
+    :return: generator - generator that yields seat letters.
+
+    Seat letters are generated from A to D.
+    After D it should start again with A.
+
+    Example: A, B, C, D
+
+    """
+
+    for seat in range(amount):
+        yield SEATS_IN_ROW[seat % 4]
+
+
+def generate_seats(amount):
     """Generate a series of seat numbers for airline boarding.
 
-    :param amount: Amount of seats to be generated. (int)
-    :return: Generator that generates seat numbers. (generator)
+    :param amount: int - Amount of seats to be generated.
+    :return: generator - generator that yields seat numbers.
 
     There should be no row 13
 
@@ -21,19 +38,17 @@ def generate_seats(amount):
     """
 
     amount = amount + 4 if amount >= 13 else amount
-
+    letters = generate_seat_letters(amount)
     for seat in range(amount):
         row_number = math.ceil((seat+1) / 4)
         if row_number != 13:
-            seat_letter = SEATS_IN_ROW[seat % 4]
-            yield f'{str(row_number)}{seat_letter}'
+            yield f'{str(row_number)}{next(letters)}'
 
 def assign_seats(passengers):
+    """Assign seats to passengers.
 
-    """Assign seats to passenger.
-
-    :param passengers: A list of strings containing names of passengers. (list[str])
-    :return: A dictionary type object containing the names of the passengers as keys and seat numbers as values.
+    :param passengers: list[str] - A list of strings containing names of passengers.
+    :return: dict - with the names of the passengers as keys and seat numbers as values.
 
     Example output: {"Foo": "1A", "Bar": "1B"}
 
@@ -46,12 +61,11 @@ def assign_seats(passengers):
     return output
 
 def generate_codes(seat_numbers, flight_id):
-
     """Generate codes for a ticket.
 
-    :param seat_numbers: A list of seat numbers. (list[str])
-    :param flight_id: A string containing the flight identification. (str)
-    :return: Generator that generates 12 character long strings. (generator[str])
+    :param seat_numbers: list[str] - list of seat numbers.
+    :param flight_id: str - string containing the flight identification.
+    :return: generator - generator that yields 12 character long strings.
 
     """
 
diff --git a/exercises/concept/plane-tickets/plane_tickets.py b/exercises/concept/plane-tickets/plane_tickets.py
index 44d68553..4399791b 100644
--- a/exercises/concept/plane-tickets/plane_tickets.py
+++ b/exercises/concept/plane-tickets/plane_tickets.py
@@ -1,11 +1,26 @@
-"""Plane Tickets Exercise"""
+"""Functions to automate Conda airlines ticketing system."""
 
-def generate_seats(amount):
+def generate_seat_letters(amount):
+    """ Generate a series of seat letters for airline boarding.
+
+    :param amount: int - amount of seat letters to be generated.
+    :return: generator - generator that yields seat letters.
+
+    Seat letters are generated from A to D.
+    After D it should start again with A.
+
+    Example: A, B, C, D
+
+    """
 
+    pass
+
+
+def generate_seats(amount):
     """ Generate a series of seat numbers for airline boarding.
 
-    :param amount: Amount of seats to be generated. (int)
-    :return: Generator that yields seat numbers.
+    :param amount: int - Amount of seats to be generated.
+    :return: generator - generator that yields seat numbers.
 
     There should be no row 13
 
@@ -19,11 +34,10 @@ def generate_seats(amount):
     pass
 
 def assign_seats(passengers):
-
     """ Assign seats to passengers.
 
-    :param passengers: A list of strings containing names of passengers. (list[str])
-    :return: A dictionary type object containing the names of the passengers as keys and seat numbers as values.
+    :param passengers: list[str] - A list of strings containing names of passengers.
+    :return: dict - with the names of the passengers as keys and seat numbers as values.
 
     Example output: {"Foo": "1A", "Bar": "1B"}
 
@@ -32,11 +46,10 @@ def assign_seats(passengers):
     pass
 
 def generate_codes(seat_numbers, flight_id):
-
     """Generate codes for a ticket.
 
-    :param seat_numbers: A list of seat numbers. (list[str])
-    :param flight_id: A string containing the flight identification. (str)
-    :return: Generator that generates 12 character long strings. (generator[str])
+    :param seat_numbers: list[str] - list of seat numbers.
+    :param flight_id: str - string containing the flight identification.
+    :return: generator - generator that yields 12 character long strings.
 
     """
diff --git a/exercises/practice/binary/.meta/config.json b/exercises/practice/binary/.meta/config.json
index 7170a4ab..b9f5b075 100644
--- a/exercises/practice/binary/.meta/config.json
+++ b/exercises/practice/binary/.meta/config.json
@@ -26,5 +26,5 @@
     ]
   },
   "source": "All of Computer Science",
-  "source_url": "http://www.wolframalpha.com/input/?i=binary&a=*C.binary-_*MathWorld-"
+  "source_url": "https://www.wolframalpha.com/examples/mathematics/numbers/base-conversions"
 }
diff --git a/exercises/practice/etl/.meta/config.json b/exercises/practice/etl/.meta/config.json
index 4d99e631..32aab8ba 100644
--- a/exercises/practice/etl/.meta/config.json
+++ b/exercises/practice/etl/.meta/config.json
@@ -27,7 +27,7 @@
       ".meta/example.py"
     ]
   },
-  "blurb": "We are going to do the `Transform` step of an Extract-Transform-Load.",
-  "source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.",
+  "blurb": "Change the data format for scoring a game to more easily add other languages.",
+  "source": "Based on an exercise by the JumpstartLab team for students at The Turing School of Software and Design.",
   "source_url": "https://turing.edu"
 }
diff --git a/exercises/practice/hexadecimal/.meta/config.json b/exercises/practice/hexadecimal/.meta/config.json
index 352ca16d..b61e1a2c 100644
--- a/exercises/practice/hexadecimal/.meta/config.json
+++ b/exercises/practice/hexadecimal/.meta/config.json
@@ -26,5 +26,5 @@
     ]
   },
   "source": "All of Computer Science",
-  "source_url": "http://www.wolframalpha.com/examples/NumberBases.html"
+  "source_url": "https://www.wolframalpha.com/examples/mathematics/numbers/base-conversions"
 }
diff --git a/exercises/practice/list-ops/.meta/config.json b/exercises/practice/list-ops/.meta/config.json
index efc025a3..cdb33138 100644
--- a/exercises/practice/list-ops/.meta/config.json
+++ b/exercises/practice/list-ops/.meta/config.json
@@ -8,6 +8,7 @@
     "Dog",
     "dvermd",
     "gabriel376",
+    "IsaacG",
     "N-Parsons",
     "pheanex",
     "rootulp",
diff --git a/exercises/practice/list-ops/.meta/example.py b/exercises/practice/list-ops/.meta/example.py
index ee43248f..75f45033 100644
--- a/exercises/practice/list-ops/.meta/example.py
+++ b/exercises/practice/list-ops/.meta/example.py
@@ -29,7 +29,7 @@ def foldr(function, list, initial):
     if len(list) == 0:
         return initial
     else:
-        return function(list[0], foldr(function, list[1:], initial))
+        return function(foldr(function, list[1:], initial), list[0])
 
 
 def reverse(list):
diff --git a/exercises/practice/list-ops/.meta/template.j2 b/exercises/practice/list-ops/.meta/template.j2
index c346d3c2..cc28280f 100644
--- a/exercises/practice/list-ops/.meta/template.j2
+++ b/exercises/practice/list-ops/.meta/template.j2
@@ -2,7 +2,6 @@
 {% macro lambdify(function) -%}
     {% set function = function.replace("(", "", 1).replace(")", "", 1).replace(" ->", ":") %}
     {% set function = function.replace("modulo", "%") %}
-    {% set function = function.replace("/", "//") %}
     lambda {{function}}
 {%- endmacro %}
 
diff --git a/exercises/practice/nucleotide-count/.meta/config.json b/exercises/practice/nucleotide-count/.meta/config.json
index 4e91bb7e..e0c108f7 100644
--- a/exercises/practice/nucleotide-count/.meta/config.json
+++ b/exercises/practice/nucleotide-count/.meta/config.json
@@ -28,5 +28,5 @@
     ]
   },
   "source": "The Calculating DNA Nucleotides_problem at Rosalind",
-  "source_url": "http://rosalind.info/problems/dna/"
+  "source_url": "https://rosalind.info/problems/dna/"
 }
diff --git a/exercises/practice/octal/.meta/config.json b/exercises/practice/octal/.meta/config.json
index e39e3fb6..4fe6c11b 100644
--- a/exercises/practice/octal/.meta/config.json
+++ b/exercises/practice/octal/.meta/config.json
@@ -26,5 +26,5 @@
     ]
   },
   "source": "All of Computer Science",
-  "source_url": "http://www.wolframalpha.com/input/?i=base+8"
+  "source_url": "https://www.wolframalpha.com/examples/mathematics/numbers/base-conversions"
 }
diff --git a/exercises/practice/point-mutations/.meta/config.json b/exercises/practice/point-mutations/.meta/config.json
index 2d8d765c..b02f3706 100644
--- a/exercises/practice/point-mutations/.meta/config.json
+++ b/exercises/practice/point-mutations/.meta/config.json
@@ -26,5 +26,5 @@
     ]
   },
   "source": "The Calculating Point Mutations problem at Rosalind",
-  "source_url": "http://rosalind.info/problems/hamm/"
+  "source_url": "https://rosalind.info/problems/hamm/"
 }
diff --git a/exercises/practice/trinary/.meta/config.json b/exercises/practice/trinary/.meta/config.json
index 104b505a..da59ec6c 100644
--- a/exercises/practice/trinary/.meta/config.json
+++ b/exercises/practice/trinary/.meta/config.json
@@ -26,5 +26,5 @@
     ]
   },
   "source": "All of Computer Science",
-  "source_url": "http://www.wolframalpha.com/input/?i=binary&a=*C.binary-_*MathWorld-"
+  "source_url": "https://www.wolframalpha.com/examples/mathematics/numbers/base-conversions"
 }
diff --git a/exercises/practice/yacht/.approaches/config.json b/exercises/practice/yacht/.approaches/config.json
new file mode 100644
index 00000000..86d37075
--- /dev/null
+++ b/exercises/practice/yacht/.approaches/config.json
@@ -0,0 +1,28 @@
+{
+  "introduction": {
+    "authors": ["safwansamsudeen"]
+  },
+  "approaches": [
+    {
+      "uuid": "3593cfe3-5cab-4141-b0a2-329148a66bb6",
+      "slug": "functions",
+      "title": "Lambdas with Functions",
+      "blurb": "Use lambdas with functions",
+      "authors": ["safwansamsudeen"]
+    },
+    {
+      "uuid": "eccd1e1e-6c88-4823-9b25-944eccaa92e7",
+      "slug": "if-structure",
+      "title": "If structure",
+      "blurb": "Use an if structure",
+      "authors": ["safwansamsudeen"]
+    },
+    {
+      "uuid": "72079791-e51f-4825-ad94-3b7516c631cc",
+      "slug": "structural-pattern-matching",
+      "title": "Structural Pattern Matching",
+      "blurb": "Use structural pattern matching",
+      "authors": ["safwansamsudeen"]
+    }
+  ]
+}
diff --git a/exercises/practice/yacht/.approaches/functions/content.md b/exercises/practice/yacht/.approaches/functions/content.md
new file mode 100644
index 00000000..2c6bfe52
--- /dev/null
+++ b/exercises/practice/yacht/.approaches/functions/content.md
@@ -0,0 +1,72 @@
+## Approach: Using Lambdas with Functions
+Each bit of functionality for each category can be encoded in an anonymous function (otherwise known as a [`lambda` expression][lambda] or lambda form), and the constant name set to that function.
+
+In `score`, we call the category (as it now points to a function) passing in `dice` as an argument.
+
+```python
+def digits(num):
+    return lambda dice: dice.count(num) * num
+
+YACHT = lambda dice: 50 if len(set(dice)) ==  1 else 0
+ONES = digits(1)
+TWOS = digits(2)
+THREES = digits(3)
+FOURS = digits(4)
+FIVES = digits(5)
+SIXES = digits(6)
+FULL_HOUSE = lambda dice: sum(dice) if len(set(dice)) == 2 and dice.count(dice[0]) in [2, 3] else 0
+FOUR_OF_A_KIND = lambda dice: 4 * dice[1] if dice[0] == dice[3] or dice[1] == dice[4] else 0
+LITTLE_STRAIGHT = lambda dice: 30 if sorted(dice) == [1, 2, 3, 4, 5] else 0
+BIG_STRAIGHT = lambda dice: 30 if sorted(dice) == [2, 3, 4, 5, 6] else 0
+CHOICE = sum
+
+def score(dice, category):
+    return category(dice)
+``` 
+
+
+Instead of setting each constant in `ONES` through `SIXES` to a separate function, we create a function `digits` that returns a function, using [closures][closures] transparently.
+
+For `LITTLE_STRAIGHT` and `BIG_STRAIGHT`, we first sort the dice and then check it against the hard-coded value. 
+Another way to solve this would be to check if `sum(dice) == 20 and len(set(dice)) == 5` (15 in `LITTLE_STRAIGHT`).
+In `CHOICE`, `lambda number : sum(number)` is shortened to just `sum`.
+
+In `FULL_HOUSE`, we create a `set` to remove the duplicates and check the set's length along with the individual counts. 
+For `FOUR_OF_A_KIND`, we check if the first and the fourth element are the same or the second and the last element are the same - if so, there are (at least) four of the same number in the array. 
+
+This solution is a succinct way to solve the exercise, although some of the one-liners can get a little long and hard to read. 
+Additionally, [PEP8][pep8] does not recommend assigning constant or variable names to `lambda` expressions, so it is a better practice to use `def`:
+```python
+def digits(num):
+    return lambda dice: dice.count(num) * num
+
+def YACHT(dice): return 50 if len(set(dice)) ==  1 else 0
+ONES = digits(1)
+TWOS = digits(2)
+THREES = digits(3)
+FOURS = digits(4)
+FIVES = digits(5)
+SIXES = digits(6)
+def FULL_HOUSE(dice): return sum(dice) if len(set(dice)) == 2 and dice.count(dice[0]) in [2, 3] else 0
+def FOUR_OF_A_KIND(dice): return 4 * sorted(dice)[1] if len(set(dice)) < 3 and dice.count(dice[0]) in (1, 4, 5) else 0
+def LITTLE_STRAIGHT(dice): return 30 if sorted(dice) == [1, 2, 3, 4, 5] else 0
+def BIG_STRAIGHT(dice): return 30 if sorted(dice) == [2, 3, 4, 5, 6] else 0
+CHOICE = sum
+
+def score(dice, category):
+    return category(dice)
+```
+
+As you can see from the examples, the [ternary operator][ternary-operator] (_or ternary form_) is crucial in solving the exercise using one liners.  
+As functions are being used, it might be a better strategy to spread the code over multiple lines to improve readability.
+```python
+def YACHT(dice):
+    if dice.count(dice[0]) == len(dice):
+        return 50
+    return 0
+```
+
+[closures]: https://www.programiz.com/python-programming/closure
+[ternary-operator]: https://www.tutorialspoint.com/ternary-operator-in-python
+[lambda]: https://docs.python.org/3/howto/functional.html?highlight=lambda#small-functions-and-the-lambda-expression    
+[pep8]: https://peps.python.org/pep-0008/
\ No newline at end of file
diff --git a/exercises/practice/yacht/.approaches/functions/snippet.txt b/exercises/practice/yacht/.approaches/functions/snippet.txt
new file mode 100644
index 00000000..34d270ad
--- /dev/null
+++ b/exercises/practice/yacht/.approaches/functions/snippet.txt
@@ -0,0 +1,8 @@
+def digits(num):
+    return lambda dice: dice.count(num) * num
+YACHT = lambda x: 50 if x.count(x[0]) == len(x) else 0
+ONES = digits(1)
+FULL_HOUSE = lambda x: sum(x) if len(set(x)) == 2 and x.count(x[0]) in [2, 3] else 0
+LITTLE_STRAIGHT = lambda x: 30 if sorted(x) == [1, 2, 3, 4, 5] else 0
+def score(dice, category):
+    return category(dice)
\ No newline at end of file
diff --git a/exercises/practice/yacht/.approaches/if-structure/content.md b/exercises/practice/yacht/.approaches/if-structure/content.md
new file mode 100644
index 00000000..581f31d1
--- /dev/null
+++ b/exercises/practice/yacht/.approaches/if-structure/content.md
@@ -0,0 +1,50 @@
+# If structure
+
+The constants here can be set to random, null, or numeric values, and an `if` structure inside the `score` function can determine the code to be executed. 
+ 
+As one-liners aren't necessary here, we can spread out the code to make it look neater:
+```python
+ONES = 1
+TWOS = 2
+THREES = 3
+FOURS = 4
+FIVES = 5
+SIXES = 6
+FULL_HOUSE = 'FULL_HOUSE'
+FOUR_OF_A_KIND = 'FOUR_OF_A_KIND'
+LITTLE_STRAIGHT = 'LITTLE_STRAIGHT'
+BIG_STRAIGHT = 'BIG_STRAIGHT'
+CHOICE = 'CHOICE'
+YACHT = 'YACHT'
+
+def score(dice, category):
+    if category in (1,2,3,4,5,6):
+         return dice.count(category) * category
+    elif category == 'FULL_HOUSE':
+        if len(set(dice)) == 2 and dice.count(dice[0]) in [2, 3]:
+            return sum(dice) or 0
+    elif category == 'FOUR_OF_A_KIND':
+        if dice[0] == dice[3] or dice[1] == dice[4]:
+            return dice[1] * 4 or 0
+    elif category == 'LITTLE_STRAIGHT':
+        if sorted(dice) == [1, 2, 3, 4, 5]: 
+            return 30 or 0
+    elif category == 'BIG_STRAIGHT':
+        if sorted(dice) == [2, 3, 4, 5, 6]:
+            return 30 or 0
+    elif category == 'YACHT':
+        if all(num == dice[0] for num in dice):
+            return 50
+    elif category == 'CHOICE':
+        return sum(dice)
+    return 0
+```
+Note that the code inside the `if` statements themselves can differ, but the key idea here is to use `if` and `elif` to branch out the code, and return `0` at the end if nothing else has been returned. 
+The `if` condition itself can be different, with people commonly checking if `category == ONES` as opposed to `category == 'ONES'` (or whatever the dummy value is).
+
+This may not be an ideal way to solve the exercise, as the code is rather long and convoluted.
+However, it is a valid (_and fast_) solution.
+Using [structural pattern matching][structural pattern matching], introduced in Python 3.10, could shorten and clarify the code in this situation.
+Pulling some logic out of the `score` function and into additional "helper" functions could also help.
+
+[structural pattern matching]: https://peps.python.org/pep-0636/
\ No newline at end of file
diff --git a/exercises/practice/yacht/.approaches/if-structure/snippet.txt b/exercises/practice/yacht/.approaches/if-structure/snippet.txt
new file mode 100644
index 00000000..fb590cc1
--- /dev/null
+++ b/exercises/practice/yacht/.approaches/if-structure/snippet.txt
@@ -0,0 +1,8 @@
+ONES = 1
+YACHT = 'YACHT'
+def score(dice, category):
+    if category == 'ONES':
+        ...
+    elif category == 'FULL_HOUSE':
+        ...
+    return 0
\ No newline at end of file
diff --git a/exercises/practice/yacht/.approaches/introduction.md b/exercises/practice/yacht/.approaches/introduction.md
new file mode 100644
index 00000000..97177606
--- /dev/null
+++ b/exercises/practice/yacht/.approaches/introduction.md
@@ -0,0 +1,77 @@
+# Introduction
+Yacht in Python can be solved in many ways. The most intuitive approach is to use an `if` structure. 
+Alternatively, you can create functions and set their names to the constant names.
+
+## General guidance
+The main thing in this exercise is to map a category (_here defined as constants in the stub file_) to a function or a standalone piece of code. 
+While mapping generally reminds us of dictionaries, here the constants are global.
+This indicates that the most idiomatic approach is not using a `dict`.
+Adhering to the principles of DRY is important - don't repeat yourself if you can help it, especially in the `ONES` through `SIXES` categories!
+
+## Approach: functions
+Each bit of functionality for each category can be encoded in a function, and the constant name set to that function. 
+This can be done by assigning the constant name to a `lambda` or creating a one-line function using the constant as a function name. 
+```python
+```python
+def digits(num):
+    return lambda dice: dice.count(num) * num
+YACHT = lambda dice: 50 if dice.count(dice[0]) == len(dice) else 0
+ONES = digits(1)
+TWOS = digits(2)
+THREES = digits(3)
+FOURS = digits(4)
+FIVES = digits(5)
+SIXES = digits(6)
+FULL_HOUSE = lambda dice: sum(dice) if len(set(dice)) == 2 and dice.count(dice[0]) in [2, 3] else 0
+FOUR_OF_A_KIND = lambda dice: 4 * dice[1] if dice[0] == dice[3] or dice[1] == dice[4] else 0
+LITTLE_STRAIGHT = lambda dice: 30 if sorted(dice) == [1, 2, 3, 4, 5] else 0
+BIG_STRAIGHT = lambda dice: 30 if sorted(dice) == [2, 3, 4, 5, 6] else 0
+CHOICE = sum
+def score(dice, category):
+    return category(dice)
+```
+This is a very succinct way to solve the exercise, although some one-liners get a little long. 
+For more information on this approach, read [this document][approach-functions].
+
+## Approach: if structure
+The constants can be set to random, null, or numeric values, and an `if` structure inside `score` determines the code to be executed. 
+As one-liners aren't necessary here, we can spread out the code to make it look neater:
+```python
+ONES = 1
+TWOS = 2
+THREES = 3
+FOURS = 4
+FIVES = 5
+SIXES = 6
+FULL_HOUSE = 'FULL_HOUSE'
+FOUR_OF_A_KIND = 'FOUR_OF_A_KIND'
+LITTLE_STRAIGHT = 'LITTLE_STRAIGHT'
+BIG_STRAIGHT = 'BIG_STRAIGHT'
+CHOICE = 'CHOICE'
+YACHT = 'YACHT'
+def score(dice, category):
+    if category in (1,2,3,4,5,6):
+         return dice.count(category) * category
+    elif category == 'FULL_HOUSE':
+        if len(set(dice)) == 2 and dice.count(dice[0]) in [2, 3]:
+            return sum(dice) or 0
+    elif category == 'FOUR_OF_A_KIND':
+        if dice[0] == dice[3] or dice[1] == dice[4]:
+            return dice[1] * 4 or 0
+    elif category == 'LITTLE_STRAIGHT':
+        if sorted(dice) == [1, 2, 3, 4, 5]: 
+            return 30 or 0
+    elif category == 'BIG_STRAIGHT':
+        if sorted(dice) == [2, 3, 4, 5, 6]:
+            return 30 or 0
+    elif category == 'YACHT':
+        if all(num == dice[0] for num in dice):
+            return 50
+    elif category == 'CHOICE':
+        return sum(dice)
+    return 0
+```
+Read more on this approach [here][approach-if-structure].
+
+[approach-functions]: https://exercism.org/tracks/python/exercises/yacht/approaches/functions
+[approach-if-structure]: https://exercism.org/tracks/python/exercises/yacht/approaches/if-structure
diff --git a/exercises/practice/yacht/.approaches/structural-pattern-matching/content.md b/exercises/practice/yacht/.approaches/structural-pattern-matching/content.md
new file mode 100644
index 00000000..b49bb634
--- /dev/null
+++ b/exercises/practice/yacht/.approaches/structural-pattern-matching/content.md
@@ -0,0 +1,55 @@
+# Structural Pattern Matching
+
+Another very interesting approach is to use [structural pattern matching][structural pattern matching]. 
+Existing in Python since 3.10, this feature allows for neater code than traditional if structures.
+ 
+By and large, we reuse the code from the [if structure approach][approach-if-structure]. 
+We set the constants to random values and check for them in the `match` structure. 
+`category` is the "subject", and in every other line, we check it against a "pattern". 
+```python
+ONES = 1
+TWOS = 2
+THREES = 3
+FOURS = 4
+FIVES = 5
+SIXES = 6
+FULL_HOUSE = 'FULL_HOUSE'
+FOUR_OF_A_KIND = 'FOUR_OF_A_KIND'
+LITTLE_STRAIGHT = 'LITTLE_STRAIGHT'
+BIG_STRAIGHT = 'BIG_STRAIGHT'
+CHOICE = 'CHOICE'
+YACHT = 'YACHT'
+
+def score(dice, category):
+    match category:
+        case 1 | 2 | 3 | 4 | 5 | 6:
+            return dice.count(category) * category
+        case 'FULL_HOUSE' if len(set(dice)) == 2 and dice.count(dice[0]) in [2, 3]:
+            return sum(dice)
+        case 'FOUR_OF_A_KIND' if dice[0] == dice[3] or dice[1] == dice[4]:
+            return dice[1] * 4
+        case 'LITTLE_STRAIGHT' if sorted(dice) == [1, 2, 3, 4, 5]:
+            return 30
+        case 'BIG_STRAIGHT' if sorted(dice) == [2, 3, 4, 5, 6]:
+            return 30 
+        case 'YACHT' if all(num == dice[0] for num in dice):
+            return 50
+        case 'CHOICE':
+            return sum(dice)
+        case _:
+            return 0
+```
+For the first pattern, we utilize "or patterns", using the `|` operator. 
+This checks whether the subject is any of the provided patterns.
+
+In the next five patterns, we check an additional condition along with the pattern matching. 
+Finally, we use the wildcard operator `_` to match anything. 
+As the compiler checks the patterns (`case`s) in order, `return 0` will be executed if none of the other patterns match. 
+
+Note that the conditions might differ, but the patterns must have hard coded values - that is, you can't say `case ONES ...` instead of `case 1 ...`. 
+This will capture the category and lead to unexpected behavior. 
+
+This code is much clenaer than the corresponding `if` structure code.
+
+[structural pattern matching]: https://peps.python.org/pep-0636/
+[approach-if-structure]: https://exercism.org/tracks/python/exercises/yacht/approaches/if-structure
\ No newline at end of file
diff --git a/exercises/practice/yacht/.approaches/structural-pattern-matching/snippet.txt b/exercises/practice/yacht/.approaches/structural-pattern-matching/snippet.txt
new file mode 100644
index 00000000..4ed99824
--- /dev/null
+++ b/exercises/practice/yacht/.approaches/structural-pattern-matching/snippet.txt
@@ -0,0 +1,8 @@
+ONES = 1
+YACHT = 'YACHT'
+def score(dice, category):
+    match category:
+        case 1 | 2 | 3 | 4 | 5 | 6:
+            return dice.count(category) * category
+        case _:
+            return 0
\ No newline at end of file


Test patch:
diff --git a/exercises/concept/plane-tickets/plane_tickets_test.py b/exercises/concept/plane-tickets/plane_tickets_test.py
index f4255c43..1372e5cd 100644
--- a/exercises/concept/plane-tickets/plane_tickets_test.py
+++ b/exercises/concept/plane-tickets/plane_tickets_test.py
@@ -3,6 +3,7 @@ import unittest
 import pytest
 
 from plane_tickets import (
+    generate_seat_letters,
     generate_seats,
     assign_seats,
     generate_codes
@@ -10,16 +11,31 @@ from plane_tickets import (
 
 class PlaneTicketsTest(unittest.TestCase):
 
-
     @pytest.mark.task(taskno=1)
     def test_task1_is_generator(self):  # * Tests if [Task 1] actually returns a generator.
         input_var = 5
         output_type = Generator
         error_message = f"Expected: {str(output_type)} type, but got a different type."
-        self.assertIsInstance(generate_seats(input_var), output_type, msg=error_message)
+        self.assertIsInstance(generate_seat_letters(input_var), output_type, msg=error_message)
 
     @pytest.mark.task(taskno=1)
     def test_task1_output(self):
+        input_vars = [1, 2, 3, 4, 5]
+        output = [["A"], ["A", "B"], ["A", "B", "C"], ["A", "B", "C", "D"], ["A", "B", "C", "D", "A"]]
+        for variant, (input_var, output) in enumerate(zip(input_vars, output), start=1):
+            error_message = f"Expected: {output}, but something went wrong while generating {input_var} seat(s)."
+            with self.subTest(f"variation #{variant}", input_data=input_var, output_data=output):
+                self.assertEqual(list(generate_seat_letters(input_var)), output, msg=error_message)
+
+    @pytest.mark.task(taskno=2)
+    def test_task2_is_generator(self):  # * Tests if [Task 2] actually returns a generator.
+        input_var = 5
+        output_type = Generator
+        error_message = f"Expected: {str(output_type)} type, but got a different type."
+        self.assertIsInstance(generate_seats(input_var), output_type, msg=error_message)
+
+    @pytest.mark.task(taskno=2)
+    def test_task2_output(self):
         input_vars = [1, 2, 3, 4, 5]
         output = [["1A"], ["1A", "1B"], ["1A", "1B", "1C"], ["1A", "1B", "1C", "1D"], ["1A", "1B", "1C", "1D", "2A"]]
         for variant, (input_var, output) in enumerate(zip(input_vars, output), start=1):
@@ -27,8 +43,8 @@ class PlaneTicketsTest(unittest.TestCase):
             with self.subTest(f"variation #{variant}", input_data=input_var, output_data=output):
                 self.assertEqual(list(generate_seats(input_var)), output, msg=error_message)
 
-    @pytest.mark.task(taskno=1)
-    def test_task1_skips_row_13(self):
+    @pytest.mark.task(taskno=2)
+    def test_task3_skips_row_13(self):
         input_vars = [14 * 4]
         output = [["1A", "1B", "1C", "1D", "2A", "2B", "2C", "2D",
                    "3A", "3B", "3C", "3D", "4A", "4B", "4C", "4D",
@@ -42,8 +58,8 @@ class PlaneTicketsTest(unittest.TestCase):
             with self.subTest(f"variation #{variant}", input_data=input_var, output_data=output):
                 self.assertEqual(list(generate_seats(input_var)), output, msg=error_message)
 
-    @pytest.mark.task(taskno=2)
-    def test_task2(self):
+    @pytest.mark.task(taskno=3)
+    def test_task3(self):
         input_vars = [["Passenger1", "Passenger2", "Passenger3", "Passenger4", "Passenger5"], 
                       ["TicketNo=5644", "TicketNo=2273", "TicketNo=493", "TicketNo=5411", "TicketNo=824"]]
         output = [{"Passenger1": "1A", "Passenger2": "1B", "Passenger3": "1C", "Passenger4": "1D", "Passenger5": "2A"}, 
@@ -53,15 +69,15 @@ class PlaneTicketsTest(unittest.TestCase):
             with self.subTest(f"variation #{variant}", input_data=input_var, output_data=output):
                 self.assertEqual(assign_seats(input_var), output, msg=error_message)
 
-    @pytest.mark.task(taskno=3)
-    def test_task3_is_generator(self):
+    @pytest.mark.task(taskno=4)
+    def test_task4_is_generator(self):
         input_var = ("11B", "HA80085")
         output_type = Generator
         error_message = f"Expected: {str(output_type)} type, but got a different type."
         self.assertIsInstance(generate_codes(input_var[0], input_var[1]), output_type, msg=error_message)
 
-    @pytest.mark.task(taskno=3)
-    def test_task3(self):
+    @pytest.mark.task(taskno=4)
+    def test_task4(self):
         input_vars = [(["12A", "38B", "69C", "102B"],"KL1022"),
                       (["22C", "88B", "33A", "44B"], "DL1002")]
         output = [['12AKL1022000', '38BKL1022000', '69CKL1022000', '102BKL102200'],
diff --git a/exercises/practice/list-ops/.meta/additional_tests.json b/exercises/practice/list-ops/.meta/additional_tests.json
index 7eb1d65c..39c0a8bf 100644
--- a/exercises/practice/list-ops/.meta/additional_tests.json
+++ b/exercises/practice/list-ops/.meta/additional_tests.json
@@ -6,7 +6,7 @@
       "input": {
         "list": ["e", "x", "e", "r", "c", "i", "s", "m"],
         "initial": "!",
-        "function": "(x, y) -> x + y"
+        "function": "(acc, el) -> el + acc"
       },
       "expected": "exercism!"
     },
@@ -19,4 +19,4 @@
       "expected": [1, "cat", 4.0, "xyz"]
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/exercises/practice/list-ops/.meta/tests.toml b/exercises/practice/list-ops/.meta/tests.toml
index 7fe3c8d1..08b1edc0 100644
--- a/exercises/practice/list-ops/.meta/tests.toml
+++ b/exercises/practice/list-ops/.meta/tests.toml
@@ -71,7 +71,6 @@ reimplements = "e56df3eb-9405-416a-b13a-aabb4c3b5194"
 [d7fcad99-e88e-40e1-a539-4c519681f390]
 description = "folds (reduces) the given list from the left with a function -> direction dependent function applied to non-empty list"
 reimplements = "d2cf5644-aee1-4dfc-9b88-06896676fe27"
-include = false
 
 [aeb576b9-118e-4a57-a451-db49fac20fdc]
 description = "folds (reduces) the given list from the right with a function -> empty list"
@@ -96,7 +95,6 @@ reimplements = "c4b64e58-313e-4c47-9c68-7764964efb8e"
 [8066003b-f2ff-437e-9103-66e6df474844]
 description = "folds (reduces) the given list from the right with a function -> direction dependent function applied to non-empty list"
 reimplements = "be396a53-c074-4db3-8dd6-f7ed003cce7c"
-include = false
 
 [94231515-050e-4841-943d-d4488ab4ee30]
 description = "reverse the elements of the list -> empty list"
diff --git a/exercises/practice/list-ops/list_ops_test.py b/exercises/practice/list-ops/list_ops_test.py
index cff6156d..a2a30129 100644
--- a/exercises/practice/list-ops/list_ops_test.py
+++ b/exercises/practice/list-ops/list_ops_test.py
@@ -63,12 +63,18 @@ class ListOpsTest(unittest.TestCase):
     def test_foldl_direction_independent_function_applied_to_non_empty_list(self):
         self.assertEqual(foldl(lambda acc, el: el + acc, [1, 2, 3, 4], 5), 15)
 
+    def test_foldl_direction_dependent_function_applied_to_non_empty_list(self):
+        self.assertEqual(foldl(lambda acc, el: el / acc, [1, 2, 3, 4], 24), 64)
+
     def test_foldr_empty_list(self):
         self.assertEqual(foldr(lambda acc, el: el * acc, [], 2), 2)
 
     def test_foldr_direction_independent_function_applied_to_non_empty_list(self):
         self.assertEqual(foldr(lambda acc, el: el + acc, [1, 2, 3, 4], 5), 15)
 
+    def test_foldr_direction_dependent_function_applied_to_non_empty_list(self):
+        self.assertEqual(foldr(lambda acc, el: el / acc, [1, 2, 3, 4], 24), 9)
+
     def test_reverse_empty_list(self):
         self.assertEqual(reverse([]), [])
 
@@ -84,7 +90,9 @@ class ListOpsTest(unittest.TestCase):
 
     def test_foldr_foldr_add_string(self):
         self.assertEqual(
-            foldr(lambda x, y: x + y, ["e", "x", "e", "r", "c", "i", "s", "m"], "!"),
+            foldr(
+                lambda acc, el: el + acc, ["e", "x", "e", "r", "c", "i", "s", "m"], "!"
+            ),
             "exercism!",
         )