-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Write approaches for Yacht #3420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
f9473e6
write approaches for yacht
safwansamsudeen 782ceac
improve wording, structure, and code
safwansamsudeen b3ef407
update based on bethany's changes
safwansamsudeen 194f24d
Apply suggestions from code review
safwansamsudeen c6f5574
improve snippets, add spm approach
safwansamsudeen 0e634bd
Merge remote-tracking branch 'origin/main'
safwansamsudeen 6bc9914
Apply suggestions from code review
BethanyG File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| { | ||
| "introduction": { | ||
| "authors": ["safwansamsudeen"] | ||
| }, | ||
| "approaches": [ | ||
| { | ||
| "uuid": "3593cfe3-5cab-4141-b0a2-329148a66bb6", | ||
| "slug": "functions", | ||
| "title": "Functions", | ||
| "blurb": "Use functions", | ||
| "authors": ["safwansamsudeen"] | ||
| }, | ||
| { | ||
| "uuid": "eccd1e1e-6c88-4823-9b25-944eccaa92e7", | ||
| "slug": "if-structure", | ||
| "title": "If structure", | ||
| "blurb": "Use an if structure", | ||
| "authors": ["safwansamsudeen"] | ||
| } | ||
| ] | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| ## Approach: functions | ||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Each bit of functionality for each category can be encoded in a function, and the constant set to that function. | ||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| We use `lambda`s as _all_ the functions can be written in one line. | ||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| In `score`, we call the category (as it's now a function) passing in `dice`. | ||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```python | ||
| def digits(n): | ||
| return lambda dice: dice.count(n) * n | ||
|
|
||
| YACHT = lambda dice: 50 if dice.count(dice[0]) == len(dice) else 0 | ||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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 s: 4 * sorted(s)[1] if len(set(s)) < 3 and s.count(s[0]) in (1, 4, 5) 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 idiomatic way to solve the exercise, although some one-liners get a little long. | ||
| The [ternary operator][ternary-operator] is crucial in solving the exercise this way. | ||
| Instead of `lambda`s, functions could be created and the constants set to them. | ||
| This will remove the need for one-liners. If interested, read more on [lamdas][lambdas]. | ||
| ```python | ||
| def yacht(dice): | ||
| if dice.count(dice[0]) == len(dice): | ||
| return 50 | ||
| return 0 | ||
| YACHT = yacht | ||
| # and so on | ||
| # or even, though not recommended | ||
| def YACHT(dice): | ||
| if dice.count(dice[0]) == len(dice): | ||
| return 50 | ||
| return 0 | ||
| ``` | ||
|
|
||
| Instead of setting each constant in `ONES` through `SIXES` to a separate `lambda`, we create a function that returns a `lambda`, 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(d) == 20 and len(set(d)) == 5` (15 in `LITTLE_STRAIGHT`). | ||
| In `CHOICE`, `lambda x: sum(x)` is shortened to just `sum`. | ||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| The essence of the one-liners in `FULL_HOUSE` and `FOUR_OF_A_KIND` is in creating `set`s to remove the duplicates and checking their lengths. | ||
| `FOUR_OF_A_KIND` is commonly the hardest function to put in one line, and it's valid to declare it in a less complicated function: | ||
| ```python | ||
| FOUR_OF_A_KIND = four_of_a_kind | ||
| def four_of_a_kind(x): | ||
| four_times_elements = [dice for dice in set(x) if x.count(dice) >= 4] | ||
| return 4 * four_times_elements[0] if len(four_times_elements) > 0 else 0 | ||
| ``` | ||
| This approach can be done in one line using the [walrus operator][walrus] which exists in Python since 3.8 (done slightly differently to show the possible variations): | ||
| ```python | ||
| FOUR_OF_A_KIND = lambda dice: four_elem[0] * 4 if (four_elem := [i for i in dice if dice.count(i) >= 4]) else 0 | ||
| ``` | ||
|
|
||
|
|
||
| [closures]: https://www.programiz.com/python-programming/closure | ||
| [ternary-operator]: https://www.tutorialspoint.com/ternary-operator-in-python | ||
| [lambdas]: https://www.w3schools.com/python/python_lambda.asp | ||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| [walrus]: https://realpython.com/python-walrus-operator/ | ||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| YACHT = lambda x: 50 if x.count(x[0]) == len(x) else 0 | ||
safwansamsudeen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ONES = digits(1) | ||
| FULL_HOUSE = lambda x: sum(x) if len(set(x)) == 2 and x.count(x[0]) in [2, 3] else 0 | ||
safwansamsudeen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| LITTLE_STRAIGHT = lambda x: 30 if sorted(x) == [1, 2, 3, 4, 5] else 0 | ||
safwansamsudeen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def score(dice, category): | ||
| return category(dice) | ||
56 changes: 56 additions & 0 deletions
56
exercises/practice/yacht/.approaches/if-structure/content.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # 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. | ||
BethanyG marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| As one-liners aren't necessary here, we can spread out the code to make it look neater. | ||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ```python | ||
| YACHT = 'YACHT' | ||
| ONES = 'ONES' | ||
| TWOS = 'TWOS' | ||
| THREES = 'THREES' | ||
| FOURS = 'FOURS' | ||
| FIVES = 'FIVES' | ||
| SIXES = 'SIXES' | ||
| FULL_HOUSE = 'FULL_HOUSE' | ||
| FOUR_OF_A_KIND = 'FOUR_OF_A_KIND' | ||
| LITTLE_STRAIGHT = 'LITTLE_STRAIGHT' | ||
| BIG_STRAIGHT = 'BIG_STRAIGHT' | ||
| CHOICE = 'CHOICE' | ||
|
|
||
| def score(dice, category): | ||
| if category == 'ONES': | ||
| return dice.count(1) | ||
| elif category == 'TWOS': | ||
| return dice.count(2) * 2 | ||
| elif category == 'THREES': | ||
| return dice.count(3) * 3 | ||
| elif category == 'FOURS': | ||
| return dice.count(4) * 4 | ||
| elif category == 'FIVES': | ||
| return dice.count(5) * 5 | ||
| elif category == 'SIXES': | ||
| return dice.count(6) * 6 | ||
| elif category == 'FULL_HOUSE': | ||
| for i in dice: | ||
| for j in dice: | ||
| if dice.count(i) == 3 and dice.count(j) == 2: | ||
| return i * 3 + j * 2 | ||
| elif category == 'FOUR_OF_A_KIND': | ||
| for j in dice: | ||
| if dice.count(j) >= 4: | ||
| return j * 4 | ||
| elif category == 'LITTLE_STRAIGHT': | ||
| if dice.count(1) == 1 and dice.count(2) == 1 and dice.count(3) == 1 and dice.count(4) == 1 and dice.count(5) == 1: | ||
| return 30 | ||
| elif category == 'BIG_STRAIGHT': | ||
| if dice.count(6) == 1 and dice.count(2) == 1 and dice.count(3) == 1 and dice.count(4) == 1 and dice.count(5) == 1: | ||
| return 30 | ||
| elif category == 'YACHT': | ||
| if all(i == dice[0] for i 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 is not an ideal way to solve the exercise, as the provided constants are used as dummies, and the code is rather long and winded. It remains, however, valid, and does have its advantages, such as the lack of repetition in returning 0 that we had in the `lambda` approach. | ||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
8 changes: 8 additions & 0 deletions
8
exercises/practice/yacht/.approaches/if-structure/snippet.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| YACHT = 'YACHT' | ||
| CHOICE = 'CHOICE' | ||
| def score(dice, category): | ||
| if category == 'ONES': | ||
| ... | ||
| elif category == 'FULL_HOUSE': | ||
| ... | ||
| return 0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,87 @@ | ||||||
| # Introduction | ||||||
| Yacht in Python can be solved in many ways. The most intuitive approach is to use an `if` structure. More idiomatically, you can create functions and set their names to the constant names. | ||||||
BethanyG marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| ## General guidance | ||||||
| The main thing in this exercise is to map a category to a function or a standalone piece of code. While map generally reminds us of `dict`s, here the constants in the stub file are global. This indicates that the most idiomatic approach is not using a `dict`. Adhering to the principles of DRY too is important - don't repeat yourself if you can help it, especially in the `ONES` through `SIXES` categories. | ||||||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| ## Approach: functions | ||||||
| Each bit of functionality for each category can be encoded in a function, and the constant set to that function. We use `lambda`s as _all_ of the functions can be written in one line. In `score`, we call the category (as it's now a function) passing in `dice`. We use `lambda`s as _all_ of the functions can be written in one line. | ||||||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| ```python | ||||||
| def digits(n): | ||||||
| return lambda x: x.count(n) * n | ||||||
|
|
||||||
| YACHT = lambda x: 50 if x.count(x[0]) == len(x) else 0 | ||||||
| ONES = digits(1) | ||||||
| TWOS = digits(2) | ||||||
| THREES = digits(3) | ||||||
| FOURS = digits(4) | ||||||
| FIVES = digits(5) | ||||||
| SIXES = digits(6) | ||||||
| FULL_HOUSE = lambda x: sum(x) if len(set(x)) == 2 and x.count(x[0]) in [2, 3] else 0 | ||||||
| FOUR_OF_A_KIND = lambda s: 4 * sorted(s)[1] if len(set(s)) < 3 and s.count(s[0]) in (1, 4, 5) else 0 | ||||||
| LITTLE_STRAIGHT = lambda x: 30 if sorted(x) == [1, 2, 3, 4, 5] else 0 | ||||||
| BIG_STRAIGHT = lambda x: 30 if sorted(x) == [2, 3, 4, 5, 6] else 0 | ||||||
| CHOICE = sum | ||||||
|
|
||||||
| def score(dice, category): | ||||||
| return category(dice) | ||||||
| ``` | ||||||
safwansamsudeen marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| This is a very idiomatic way to solve the exercise, although some one-liners get a little long. | ||||||
safwansamsudeen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| The repetitive code is minimized using a seperate function `digits` that returns a function (closure). For more information on this approach, read [this document][approach-functions]. | ||||||
|
||||||
| The repetitive code is minimized using a seperate function `digits` that returns a function (closure). For more information on this approach, read [this document][approach-functions]. | |
| For more information on this approach, read [this document][approach-functions]. |
safwansamsudeen marked this conversation as resolved.
Show resolved
Hide resolved
safwansamsudeen marked this conversation as resolved.
Show resolved
Hide resolved
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.