From d4c332c74dd96da9449efb13c7139b995aec8ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Gajo?= <50725287+64J0@users.noreply.github.com> Date: Tue, 28 Feb 2023 13:18:05 -0300 Subject: [PATCH 001/162] chore: rename is-pangram function to pangramp (#274) --- exercises/practice/pangram/.meta/example.el | 2 +- exercises/practice/pangram/pangram-test.el | 22 ++++++++++----------- exercises/practice/pangram/pangram.el | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/exercises/practice/pangram/.meta/example.el b/exercises/practice/pangram/.meta/example.el index adc020fd..7771374d 100644 --- a/exercises/practice/pangram/.meta/example.el +++ b/exercises/practice/pangram/.meta/example.el @@ -5,7 +5,7 @@ ;;; Code: (require 'cl-lib) -(defun is-pangram (phrase) +(defun pangramp (phrase) "Determine if a given phrase is a pangram." (let ((alphabet "abcdefghijklmnopqrstuvwxyz")) (cl-every diff --git a/exercises/practice/pangram/pangram-test.el b/exercises/practice/pangram/pangram-test.el index a6de6642..ef03a905 100644 --- a/exercises/practice/pangram/pangram-test.el +++ b/exercises/practice/pangram/pangram-test.el @@ -6,37 +6,37 @@ ;;; Code: (load-file "pangram.el") -(declare-function is-pangram "pangram.el" (phrase)) +(declare-function pangramp "pangram.el" (phrase)) (ert-deftest sentence-empty () - (should (equal nil (is-pangram "")))) + (should (equal nil (pangramp "")))) (ert-deftest recognizes-a-perfect-lower-case-pangram () - (should (equal t (is-pangram "abcdefghijklmnopqrstuvwxyz")))) + (should (equal t (pangramp "abcdefghijklmnopqrstuvwxyz")))) (ert-deftest pangram-with-only-lower-case () - (should (equal t (is-pangram "the quick brown fox jumps over the lazy dog")))) + (should (equal t (pangramp "the quick brown fox jumps over the lazy dog")))) (ert-deftest missing-character-x () - (should (equal nil (is-pangram "a quick movement of the enemy will jeopardize five gunboats")))) + (should (equal nil (pangramp "a quick movement of the enemy will jeopardize five gunboats")))) (ert-deftest missing-another-character-eg-h () - (should (equal nil (is-pangram "five boxing wizards jump quickly at it")))) + (should (equal nil (pangramp "five boxing wizards jump quickly at it")))) (ert-deftest pangram-with-underscores () - (should (equal t (is-pangram "the_quick_brown_fox_jumps_over_the_lazy_dog")))) + (should (equal t (pangramp "the_quick_brown_fox_jumps_over_the_lazy_dog")))) (ert-deftest pangram-with-numbers () - (should (equal t (is-pangram "the 1 quick brown fox jumps over the 2 lazy dogs")))) + (should (equal t (pangramp "the 1 quick brown fox jumps over the 2 lazy dogs")))) (ert-deftest missing-letters-replaced-by-numbers () - (should (equal nil (is-pangram "7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog")))) + (should (equal nil (pangramp "7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog")))) (ert-deftest pangram-with-mixed-case-and-punctuation () - (should (equal t (is-pangram "\"Five quacking Zephyrs jolt my wax bed.\"")))) + (should (equal t (pangramp "\"Five quacking Zephyrs jolt my wax bed.\"")))) (ert-deftest a-m-and-A-M-are-26-different-characters-but-not-a-pangram () - (should (equal nil (is-pangram "abcdefghijklm ABCDEFGHIJKLM")))) + (should (equal nil (pangramp "abcdefghijklm ABCDEFGHIJKLM")))) (provide 'pangram-test) ;;; pagram-test.el ends here diff --git a/exercises/practice/pangram/pangram.el b/exercises/practice/pangram/pangram.el index c7dd7a90..3ee08adb 100644 --- a/exercises/practice/pangram/pangram.el +++ b/exercises/practice/pangram/pangram.el @@ -2,7 +2,7 @@ ;;; Commentary: -(defun is-pangram (phrase) +(defun pangramp (phrase) ;;; Code: ) From 660c83e996756ebb8a049b11ba061ed7e9aaa87e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Gajo?= <50725287+64J0@users.noreply.github.com> Date: Fri, 10 Mar 2023 13:51:52 -0300 Subject: [PATCH 002/162] Add hints to the nucleotide-count exercise (#276) --- exercises/practice/nucleotide-count/.docs/hints.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 exercises/practice/nucleotide-count/.docs/hints.md diff --git a/exercises/practice/nucleotide-count/.docs/hints.md b/exercises/practice/nucleotide-count/.docs/hints.md new file mode 100644 index 00000000..332002fc --- /dev/null +++ b/exercises/practice/nucleotide-count/.docs/hints.md @@ -0,0 +1,11 @@ +# Hints + +## General + +- The expected result is an `Association List` data structure (also called `alist`), not an string, or something else. You can find more information about it in this [link](https://www.gnu.org/software/emacs/manual/html_node/elisp/Association-Lists.html). So, for the correct example, the right output would be: + + ```text + "GATTACA" -> '((?A . 3) (?C . 1) (?G . 1) (?T . 2)) + ``` + +- The `?A` is the Emacs Lisp way to represent a character. You can find more information in the documentation: [link](https://www.gnu.org/software/emacs/manual/html_node/elisp/Basic-Char-Syntax.html). From 36dec57bd5e39ff2550e1a7ddcc079db4a7eb212 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Fri, 10 Mar 2023 17:52:50 +0100 Subject: [PATCH 003/162] Sync gigasecond docs with problem-specifications (#277) The gigasecond exercise has been overhauled as part of a project to make practice exercises more consistent and friendly. For more context, please see the discussion in the forum, as well as the pull request that updated the exercise in the problem-specifications repository: - https://forum.exercism.org/t/new-project-making-practice-exercises-more-consistent-and-human-across-exercism/3943 - https://github.com/exercism/problem-specifications/pull/2206 --- .../practice/gigasecond/.docs/instructions.md | 7 ++++-- .../practice/gigasecond/.docs/introduction.md | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 exercises/practice/gigasecond/.docs/introduction.md diff --git a/exercises/practice/gigasecond/.docs/instructions.md b/exercises/practice/gigasecond/.docs/instructions.md index 41a057c4..1e20f002 100644 --- a/exercises/practice/gigasecond/.docs/instructions.md +++ b/exercises/practice/gigasecond/.docs/instructions.md @@ -1,5 +1,8 @@ # Instructions -Given a moment, determine the moment that would be after a gigasecond has passed. +Your task is to determine the date and time one gigasecond after a certain date. -A gigasecond is 10^9 (1,000,000,000) seconds. +A gigasecond is one thousand million seconds. +That is a one with nine zeros after it. + +If you were born on _January 24th, 2015 at 22:00 (10:00:00pm)_, then you would be a gigasecond old on _October 2nd, 2046 at 23:46:40 (11:46:40pm)_. diff --git a/exercises/practice/gigasecond/.docs/introduction.md b/exercises/practice/gigasecond/.docs/introduction.md new file mode 100644 index 00000000..74afaa99 --- /dev/null +++ b/exercises/practice/gigasecond/.docs/introduction.md @@ -0,0 +1,24 @@ +# Introduction + +The way we measure time is kind of messy. +We have 60 seconds in a minute, and 60 minutes in an hour. +This comes from ancient Babylon, where they used 60 as the basis for their number system. +We have 24 hours in a day, 7 days in a week, and how many days in a month? +Well, for days in a month it depends not only on which month it is, but also on what type of calendar is used in the country you live in. + +What if, instead, we only use seconds to express time intervals? +Then we can use metric system prefixes for writing large numbers of seconds in more easily comprehensible quantities. + +- A food recipe might explain that you need to let the brownies cook in the oven for two kiloseconds (that's two thousand seconds). +- Perhaps you and your family would travel to somewhere exotic for two megaseconds (that's two million seconds). +- And if you and your spouse were married for _a thousand million_ seconds, you would celebrate your one gigasecond anniversary. + +```exercism/note +If we ever colonize Mars or some other planet, measuring time is going to get even messier. +If someone says "year" do they mean a year on Earth or a year on Mars? + +The idea for this exercise came from the science fiction novel ["A Deepness in the Sky"][vinge-novel] by author Vernor Vinge. +In it the author uses the metric system as the basis for time measurements. + +[vinge-novel]: https://www.tor.com/2017/08/03/science-fiction-with-something-for-everyone-a-deepness-in-the-sky-by-vernor-vinge/ +``` From 6c0140fd7ef9dc4634521421155f0751b0f0a6bf Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Fri, 10 Mar 2023 17:53:09 +0100 Subject: [PATCH 004/162] Sync bob docs with problem-specifications (#278) The bob exercise has been overhauled as part of a project to make practice exercises more consistent and friendly. For more context, please see the discussion in the forum, as well as the pull request that updated the exercise in the problem-specifications repository: - https://forum.exercism.org/t/new-project-making-practice-exercises-more-consistent-and-human-across-exercism/3943 - https://github.com/exercism/problem-specifications/pull/2205 --- exercises/practice/bob/.docs/instructions.md | 27 +++++++++++--------- exercises/practice/bob/.docs/introduction.md | 10 ++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) create mode 100644 exercises/practice/bob/.docs/introduction.md diff --git a/exercises/practice/bob/.docs/instructions.md b/exercises/practice/bob/.docs/instructions.md index 7888c9b7..bb702f7b 100644 --- a/exercises/practice/bob/.docs/instructions.md +++ b/exercises/practice/bob/.docs/instructions.md @@ -1,16 +1,19 @@ # Instructions -Bob is a lackadaisical teenager. -In conversation, his responses are very limited. +Your task is to determine what Bob will reply to someone when they say something to him or ask him a question. -Bob answers 'Sure.' if you ask him a question, such as "How are you?". +Bob only ever answers one of five things: -He answers 'Whoa, chill out!' if you YELL AT HIM (in all capitals). - -He answers 'Calm down, I know what I'm doing!' if you yell a question at him. - -He says 'Fine. Be that way!' if you address him without actually saying anything. - -He answers 'Whatever.' to anything else. - -Bob's conversational partner is a purist when it comes to written communication and always follows normal rules regarding sentence punctuation in English. +- **"Sure."** + This is his response if you ask him a question, such as "How are you?" + The convention used for questions is that it ends with a question mark. +- **"Whoa, chill out!"** + This is his answer if you YELL AT HIM. + The convention used for yelling is ALL CAPITAL LETTERS. +- **"Calm down, I know what I'm doing!"** + This is what he says if you yell a question at him. +- **"Fine. Be that way!"** + This is how he responds to silence. + The convention used for silence is nothing, or various combinations of whitespace characters. +- **"Whatever."** + This is what he answers to anything else. diff --git a/exercises/practice/bob/.docs/introduction.md b/exercises/practice/bob/.docs/introduction.md new file mode 100644 index 00000000..ea4a8077 --- /dev/null +++ b/exercises/practice/bob/.docs/introduction.md @@ -0,0 +1,10 @@ +# Introduction + +Bob is a [lackadaisical][] teenager. +He likes to think that he's very cool. +And he definitely doesn't get excited about things. +That wouldn't be cool. + +When people talk to him, his responses are pretty limited. + +[lackadaisical]: https://www.collinsdictionary.com/dictionary/english/lackadaisical From 7b3575317dd79a4a879043065005a5dea32ea879 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Tue, 14 Mar 2023 10:56:32 +0100 Subject: [PATCH 005/162] Sync pangram docs with problem-specifications (#282) The pangram exercise has been overhauled as part of a project to make practice exercises more consistent and friendly. For more context, please see the discussion in the forum, as well as the pull request that updated the exercise in the problem-specifications repository: - https://forum.exercism.org/t/new-project-making-practice-exercises-more-consistent-and-human-across-exercism/3943 - https://github.com/exercism/problem-specifications/pull/2215 ---- If you approve this pull request, I will eventually merge it. However, if you are happy with this change **please merge the pull request**, as it will get the changes into the hands of the students much more quickly. --- exercises/practice/pangram/.docs/instructions.md | 9 ++++----- exercises/practice/pangram/.docs/introduction.md | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 exercises/practice/pangram/.docs/introduction.md diff --git a/exercises/practice/pangram/.docs/instructions.md b/exercises/practice/pangram/.docs/instructions.md index de83d54e..d5698bc2 100644 --- a/exercises/practice/pangram/.docs/instructions.md +++ b/exercises/practice/pangram/.docs/instructions.md @@ -1,9 +1,8 @@ # Instructions -Determine if a sentence is a pangram. -A pangram (Greek: παν γράμμα, pan gramma, "every letter") is a sentence using every letter of the alphabet at least once. -The best known English pangram is: +Your task is to figure out if a sentence is a pangram. -> The quick brown fox jumps over the lazy dog. +A pangram is a sentence using every letter of the alphabet at least once. +It is case insensitive, so it doesn't matter if a letter is lower-case (e.g. `k`) or upper-case (e.g. `K`). -The alphabet used consists of letters `a` to `z`, inclusive, and is case insensitive. +For this exercise we only use the basic letters used in the English alphabet: `a` to `z`. diff --git a/exercises/practice/pangram/.docs/introduction.md b/exercises/practice/pangram/.docs/introduction.md new file mode 100644 index 00000000..d38fa341 --- /dev/null +++ b/exercises/practice/pangram/.docs/introduction.md @@ -0,0 +1,16 @@ +# Introduction + +You work for a company that sells fonts through their website. +They'd like to show a different sentence each time someone views a font on their website. +To give a comprehensive sense of the font, the random sentences should use **all** the letters in the English alphabet. + +They're running a competition to get suggestions for sentences that they can use. +You're in charge of checking the submissions to see if they are valid. + +```exercism/note +Pangram comes from Greek, παν γράμμα, pan gramma, which means "every letter". + +The best known English pangram is: + +> The quick brown fox jumps over the lazy dog. +``` From 9d8ddb8d1d28debfcabed18ea56d86b76fc0e161 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Mar 2023 18:47:19 +0100 Subject: [PATCH 006/162] Bump purcell/setup-emacs (#280) Bumps [purcell/setup-emacs](https://github.com/purcell/setup-emacs) from ddbe7a402671fcbad2a5e1a0f503d61dd95a0b7c to ac5a5667ef01c598f55e66e0b0abdad5d825daf8. - [Release notes](https://github.com/purcell/setup-emacs/releases) - [Commits](https://github.com/purcell/setup-emacs/compare/ddbe7a402671fcbad2a5e1a0f503d61dd95a0b7c...ac5a5667ef01c598f55e66e0b0abdad5d825daf8) --- updated-dependencies: - dependency-name: purcell/setup-emacs dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e219afb3..2723bb8c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: purcell/setup-emacs@ddbe7a402671fcbad2a5e1a0f503d61dd95a0b7c + - uses: purcell/setup-emacs@ac5a5667ef01c598f55e66e0b0abdad5d825daf8 with: version: 28.1 From 3e8700558472969203dfd4f5662dd5b168157799 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Thu, 30 Mar 2023 22:47:34 +0200 Subject: [PATCH 007/162] Sync two-fer docs with problem-specifications (#281) The two-fer exercise has been overhauled as part of a project to make practice exercises more consistent and friendly. For more context, please see the discussion in the forum, as well as the pull request that updated the exercise in the problem-specifications repository: - https://forum.exercism.org/t/new-project-making-practice-exercises-more-consistent-and-human-across-exercism/3943 - https://github.com/exercism/problem-specifications/pull/2204 --- exercises/practice/two-fer/.docs/instructions.md | 16 +++++++--------- exercises/practice/two-fer/.docs/introduction.md | 8 ++++++++ 2 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 exercises/practice/two-fer/.docs/introduction.md diff --git a/exercises/practice/two-fer/.docs/instructions.md b/exercises/practice/two-fer/.docs/instructions.md index bdd72bde..a9bb4a3c 100644 --- a/exercises/practice/two-fer/.docs/instructions.md +++ b/exercises/practice/two-fer/.docs/instructions.md @@ -1,17 +1,15 @@ # Instructions -`Two-fer` or `2-fer` is short for two for one. -One for you and one for me. +Your task is to determine what you will say as you give away the extra cookie. -Given a name, return a string with the message: +If your friend likes cookies, and is named Do-yun, then you will say: ```text -One for name, one for me. +One for Do-yun, one for me. ``` -Where "name" is the given name. - -However, if the name is missing, return the string: +If your friend doesn't like cookies, you give the cookie to the next person in line at the bakery. +Since you don't know their name, you will say _you_ instead. ```text One for you, one for me. @@ -19,9 +17,9 @@ One for you, one for me. Here are some examples: -|Name |String to return +|Name |Dialogue |:-------|:------------------ |Alice |One for Alice, one for me. -|Bob |One for Bob, one for me. +|Bohdan |One for Bohdan, one for me. | |One for you, one for me. |Zaphod |One for Zaphod, one for me. diff --git a/exercises/practice/two-fer/.docs/introduction.md b/exercises/practice/two-fer/.docs/introduction.md new file mode 100644 index 00000000..8c124394 --- /dev/null +++ b/exercises/practice/two-fer/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +In some English accents, when you say "two for" quickly, it sounds like "two fer". +Two-for-one is a way of saying that if you buy one, you also get one for free. +So the phrase "two-fer" often implies a two-for-one offer. + +Imagine a bakery that has a holiday offer where you can buy two cookies for the price of one ("two-fer one!"). +You go for the offer and (very generously) decide to give the extra cookie to a friend. From a97bf2a628f607d031457e94248694aef020da57 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Sun, 23 Apr 2023 22:01:37 +0200 Subject: [PATCH 008/162] Sync etl docs with problem-specifications (#285) The etl exercise has been overhauled as part of a project to make practice exercises more consistent and friendly. For more context, please see the discussion in the forum, as well as the pull request that updated the exercise in the problem-specifications repository: - https://forum.exercism.org/t/new-project-making-practice-exercises-more-consistent-and-human-across-exercism/3943 - https://github.com/exercism/problem-specifications/pull/2250 --- exercises/practice/etl/.docs/instructions.md | 29 ++++++-------------- exercises/practice/etl/.docs/introduction.md | 16 +++++++++++ 2 files changed, 24 insertions(+), 21 deletions(-) create mode 100644 exercises/practice/etl/.docs/introduction.md diff --git a/exercises/practice/etl/.docs/instructions.md b/exercises/practice/etl/.docs/instructions.md index fffe64f2..802863b5 100644 --- a/exercises/practice/etl/.docs/instructions.md +++ b/exercises/practice/etl/.docs/instructions.md @@ -1,19 +1,8 @@ # Instructions -We are going to do the `Transform` step of an Extract-Transform-Load. +Your task is to change the data format of letters and their point values in the game. -## ETL - -Extract-Transform-Load (ETL) is a fancy way of saying, "We have some crufty, legacy data over in this system, and now we need it in this shiny new system over here, so we're going to migrate this." - -(Typically, this is followed by, "We're only going to need to run this once." -That's then typically followed by much forehead slapping and moaning about how stupid we could possibly be.) - -## The goal - -We're going to extract some Scrabble scores from a legacy system. - -The old system stored a list of letters per score: +Currently, letters are stored in groups based on their score, in a one-to-many mapping. - 1 point: "A", "E", "I", "O", "U", "L", "N", "R", "S", "T", - 2 points: "D", "G", @@ -23,18 +12,16 @@ The old system stored a list of letters per score: - 8 points: "J", "X", - 10 points: "Q", "Z", -The shiny new Scrabble system instead stores the score per letter, which makes it much faster and easier to calculate the score for a word. -It also stores the letters in lower-case regardless of the case of the input letters: +This needs to be changed to store each individual letter with its score in a one-to-one mapping. - "a" is worth 1 point. - "b" is worth 3 points. - "c" is worth 3 points. - "d" is worth 2 points. -- Etc. - -Your mission, should you choose to accept it, is to transform the legacy data format to the shiny new format. +- etc. -## Notes +As part of this change, the team has also decided to change the letters to be lower-case rather than upper-case. -A final note about scoring, Scrabble is played around the world in a variety of languages, each with its own unique scoring table. -For example, an "E" is scored at 2 in the Māori-language version of the game while being scored at 4 in the Hawaiian-language version. +~~~~exercism/note +If you want to look at how the data was previously structured and how it needs to change, take a look at the examples in the test suite. +~~~~ diff --git a/exercises/practice/etl/.docs/introduction.md b/exercises/practice/etl/.docs/introduction.md new file mode 100644 index 00000000..5be65147 --- /dev/null +++ b/exercises/practice/etl/.docs/introduction.md @@ -0,0 +1,16 @@ +# Introduction + +You work for a company that makes an online multiplayer game called Lexiconia. + +To play the game, each player is given 13 letters, which they must rearrange to create words. +Different letters have different point values, since it's easier to create words with some letters than others. + +The game was originally launched in English, but it is very popular, and now the company wants to expand to other languages as well. + +Different languages need to support different point values for letters. +The point values are determined by how often letters are used, compared to other letters in that language. + +For example, the letter 'C' is quite common in English, and is only worth 3 points. +But in Norwegian it's a very rare letter, and is worth 10 points. + +To make it easier to add new languages, your team needs to change the way letters and their point values are stored in the game. From af4e5681a8d52fd1c5316788719219249be16bc0 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Sun, 23 Apr 2023 22:01:48 +0200 Subject: [PATCH 009/162] Sync word-count docs with problem-specifications (#286) The word-count exercise has been overhauled as part of a project to make practice exercises more consistent and friendly. For more context, please see the discussion in the forum, as well as the pull request that updated the exercise in the problem-specifications repository: - https://forum.exercism.org/t/new-project-making-practice-exercises-more-consistent-and-human-across-exercism/3943 - https://github.com/exercism/problem-specifications/pull/2247 --- .../practice/word-count/.docs/instructions.md | 52 ++++++++++++------- .../practice/word-count/.docs/introduction.md | 8 +++ 2 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 exercises/practice/word-count/.docs/introduction.md diff --git a/exercises/practice/word-count/.docs/instructions.md b/exercises/practice/word-count/.docs/instructions.md index 8b7f03ed..064393c8 100644 --- a/exercises/practice/word-count/.docs/instructions.md +++ b/exercises/practice/word-count/.docs/instructions.md @@ -1,31 +1,47 @@ # Instructions -Given a phrase, count the occurrences of each _word_ in that phrase. +Your task is to count how many times each word occurs in a subtitle of a drama. -For the purposes of this exercise you can expect that a _word_ will always be one of: +The subtitles from these dramas use only ASCII characters. -1. A _number_ composed of one or more ASCII digits (ie "0" or "1234") OR -2. A _simple word_ composed of one or more ASCII letters (ie "a" or "they") OR -3. A _contraction_ of two _simple words_ joined by a single apostrophe (ie "it's" or "they're") +The characters often speak in casual English, using contractions like _they're_ or _it's_. +Though these contractions come from two words (e.g. _we are_), the contraction (_we're_) is considered a single word. -When counting words you can assume the following rules: +Words can be separated by any form of punctuation (e.g. ":", "!", or "?") or whitespace (e.g. "\t", "\n", or " "). +The only punctuation that does not separate words is the apostrophe in contractions. -1. The count is _case insensitive_ (ie "You", "you", and "YOU" are 3 uses of the same word) -2. The count is _unordered_; the tests will ignore how words and counts are ordered -3. Other than the apostrophe in a _contraction_ all forms of _punctuation_ are regarded as spaces -4. The words can be separated by _any_ form of whitespace (ie "\t", "\n", " ") +Numbers are considered words. +If the subtitles say _It costs 100 dollars._ then _100_ will be its own word. -For example, for the phrase `"That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled.` the count would be: +Words are case insensitive. +For example, the word _you_ occurs three times in the following sentence: + +> You come back, you hear me? DO YOU HEAR ME? + +The ordering of the word counts in the results doesn't matter. + +Here's an example that incorporates several of the elements discussed above: + +- simple words +- contractions +- numbers +- case insensitive words +- punctuation (including apostrophes) to separate words +- different forms of whitespace to separate words + +`"That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled.` + +The mapping for this subtitle would be: ```text -that's: 1 -the: 2 -password: 2 123: 1 -cried: 1 -special: 1 agent: 1 -so: 1 -i: 1 +cried: 1 fled: 1 +i: 1 +password: 2 +so: 1 +special: 1 +that's: 1 +the: 2 ``` diff --git a/exercises/practice/word-count/.docs/introduction.md b/exercises/practice/word-count/.docs/introduction.md new file mode 100644 index 00000000..1654508e --- /dev/null +++ b/exercises/practice/word-count/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +You teach English as a foreign language to high school students. + +You've decided to base your entire curriculum on TV shows. +You need to analyze which words are used, and how often they're repeated. + +This will let you choose the simplest shows to start with, and to gradually increase the difficulty as time passes. From 084640866073f7f4d051198e5bd417e13e6cd3c1 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Sun, 23 Apr 2023 22:01:58 +0200 Subject: [PATCH 010/162] Sync rna-transcription docs with problem-specifications (#287) The rna-transcription exercise has been overhauled as part of a project to make practice exercises more consistent and friendly. For more context, please see the discussion in the forum, as well as the pull request that updated the exercise in the problem-specifications repository: - https://forum.exercism.org/t/new-project-making-practice-exercises-more-consistent-and-human-across-exercism/3943 - https://github.com/exercism/problem-specifications/pull/2251 --- .../rna-transcription/.docs/instructions.md | 6 +++++- .../rna-transcription/.docs/introduction.md | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 exercises/practice/rna-transcription/.docs/introduction.md diff --git a/exercises/practice/rna-transcription/.docs/instructions.md b/exercises/practice/rna-transcription/.docs/instructions.md index 851bdb49..36da381f 100644 --- a/exercises/practice/rna-transcription/.docs/instructions.md +++ b/exercises/practice/rna-transcription/.docs/instructions.md @@ -1,6 +1,6 @@ # Instructions -Given a DNA strand, return its RNA complement (per RNA transcription). +Your task is determine the RNA complement of a given DNA sequence. Both DNA and RNA strands are a sequence of nucleotides. @@ -14,3 +14,7 @@ Given a DNA strand, its transcribed RNA strand is formed by replacing each nucle - `C` -> `G` - `T` -> `A` - `A` -> `U` + +~~~~exercism/note +If you want to look at how the inputs and outputs are structured, take a look at the examples in the test suite. +~~~~ diff --git a/exercises/practice/rna-transcription/.docs/introduction.md b/exercises/practice/rna-transcription/.docs/introduction.md new file mode 100644 index 00000000..6b3f44b5 --- /dev/null +++ b/exercises/practice/rna-transcription/.docs/introduction.md @@ -0,0 +1,16 @@ +# Introduction + +You work for a bioengineering company that specializes in developing therapeutic solutions. + +Your team has just been given a new project to develop a targeted therapy for a rare type of cancer. + +~~~~exercism/note +It's all very complicated, but the basic idea is that sometimes people's bodies produce too much of a given protein. +That can cause all sorts of havoc. + +But if you can create a very specific molecule (called a micro-RNA), it can prevent the protein from being produced. + +This technique is called [RNA Interference][rnai]. + +[rnai]: https://admin.acceleratingscience.com/ask-a-scientist/what-is-rnai/ +~~~~ From c750585d93abd53f27f52e125c0177c8c065dff4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 23 Apr 2023 22:02:06 +0200 Subject: [PATCH 011/162] Bump actions/checkout from 3.3.0 to 3.5.2 (#289) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.3.0 to 3.5.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/ac593985615ec2ede58e132d2e21d2b1cbd6127c...8e5e7e5ab8b370d6c329ec480221332ada57f0ab) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/configlet-sync.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2723bb8c..2eba947f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: with: version: 28.1 - - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Run exercism/emacs-lisp ci (runs tests) for all exercises run: | diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index 457cbcf5..28dc20ed 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Fetch configlet uses: exercism/github-actions/configlet-ci@main From e00327acdfd7e79b7e9c2e2cb5b34915b1624473 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Sun, 23 Apr 2023 22:02:20 +0200 Subject: [PATCH 012/162] Sync practice exercises with `problem-specifications` upstream (#290) Upstream: https://github.com/exercism/problem-specifications/ closes #279 --- exercises/practice/etl/.meta/config.json | 4 ++-- exercises/practice/gigasecond/.docs/introduction.md | 4 ++-- exercises/practice/pangram/.docs/instructions.md | 2 +- exercises/practice/pangram/.docs/introduction.md | 4 ++-- exercises/practice/two-fer/.docs/instructions.md | 12 ++++++------ 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/exercises/practice/etl/.meta/config.json b/exercises/practice/etl/.meta/config.json index c925d017..f8ba576e 100644 --- a/exercises/practice/etl/.meta/config.json +++ b/exercises/practice/etl/.meta/config.json @@ -15,7 +15,7 @@ ".meta/example.el" ] }, - "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/gigasecond/.docs/introduction.md b/exercises/practice/gigasecond/.docs/introduction.md index 74afaa99..18a3dc20 100644 --- a/exercises/practice/gigasecond/.docs/introduction.md +++ b/exercises/practice/gigasecond/.docs/introduction.md @@ -13,7 +13,7 @@ Then we can use metric system prefixes for writing large numbers of seconds in m - Perhaps you and your family would travel to somewhere exotic for two megaseconds (that's two million seconds). - And if you and your spouse were married for _a thousand million_ seconds, you would celebrate your one gigasecond anniversary. -```exercism/note +~~~~exercism/note If we ever colonize Mars or some other planet, measuring time is going to get even messier. If someone says "year" do they mean a year on Earth or a year on Mars? @@ -21,4 +21,4 @@ The idea for this exercise came from the science fiction novel ["A Deepness in t In it the author uses the metric system as the basis for time measurements. [vinge-novel]: https://www.tor.com/2017/08/03/science-fiction-with-something-for-everyone-a-deepness-in-the-sky-by-vernor-vinge/ -``` +~~~~ diff --git a/exercises/practice/pangram/.docs/instructions.md b/exercises/practice/pangram/.docs/instructions.md index d5698bc2..817c872d 100644 --- a/exercises/practice/pangram/.docs/instructions.md +++ b/exercises/practice/pangram/.docs/instructions.md @@ -5,4 +5,4 @@ Your task is to figure out if a sentence is a pangram. A pangram is a sentence using every letter of the alphabet at least once. It is case insensitive, so it doesn't matter if a letter is lower-case (e.g. `k`) or upper-case (e.g. `K`). -For this exercise we only use the basic letters used in the English alphabet: `a` to `z`. +For this exercise, a sentence is a pangram if it contains each of the 26 letters in the English alphabet. diff --git a/exercises/practice/pangram/.docs/introduction.md b/exercises/practice/pangram/.docs/introduction.md index d38fa341..32b6f1fc 100644 --- a/exercises/practice/pangram/.docs/introduction.md +++ b/exercises/practice/pangram/.docs/introduction.md @@ -7,10 +7,10 @@ To give a comprehensive sense of the font, the random sentences should use **all They're running a competition to get suggestions for sentences that they can use. You're in charge of checking the submissions to see if they are valid. -```exercism/note +~~~~exercism/note Pangram comes from Greek, παν γράμμα, pan gramma, which means "every letter". The best known English pangram is: > The quick brown fox jumps over the lazy dog. -``` +~~~~ diff --git a/exercises/practice/two-fer/.docs/instructions.md b/exercises/practice/two-fer/.docs/instructions.md index a9bb4a3c..37aa7529 100644 --- a/exercises/practice/two-fer/.docs/instructions.md +++ b/exercises/practice/two-fer/.docs/instructions.md @@ -17,9 +17,9 @@ One for you, one for me. Here are some examples: -|Name |Dialogue -|:-------|:------------------ -|Alice |One for Alice, one for me. -|Bohdan |One for Bohdan, one for me. -| |One for you, one for me. -|Zaphod |One for Zaphod, one for me. +| Name | Dialogue | +| :----- | :-------------------------- | +| Alice | One for Alice, one for me. | +| Bohdan | One for Bohdan, one for me. | +| | One for you, one for me. | +| Zaphod | One for Zaphod, one for me. | From 2e367799e1c8a23f426fd33d2291601bc6c06dbe Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Mon, 8 May 2023 13:01:20 +0200 Subject: [PATCH 013/162] Make README.md more inviting and informative (#292) * Make README.md more inviting and informative Takes influence from the READMEs of the Python, Common Lisp, and Javascript tracks. --- README.md | 129 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 110 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 6de56924..e02ffbba 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,124 @@ -# Exercism Emacs Lisp Track +# Exercism Emacs Lisp Track +![Discourse posts](https://img.shields.io/discourse/posts?server=https%3A%2F%2Fforum.exercism.org%2F) +![Discord](https://img.shields.io/discord/854117591135027261) [![Configlet Status](https://github.com/exercism/emacs-lisp/workflows/Configlet/badge.svg)](https://github.com/exercism/emacs-lisp/workflows/Configlet/badge.svg) [![Exercise Test Status](https://github.com/exercism/emacs-lisp/workflows/emacs-lisp%20%2F%20main/badge.svg)](https://github.com/exercism/emacs-lisp/workflows/emacs-lisp%20%2F%20main/badge.svg) -Exercism problems in Emacs Lisp. +**`exercism/emacs-lisp`** is one of many programming language tracks you can study on [exercism.org][exercism-website]. +This repo holds all the instructions, tests, code, & support files for Emacs Lisp _exercises_ currently under development or implemented & available for students. +If you haven't already, you can check out and study the live language track [here][exercism-emacs-lisp-track]. -## Contributing to The Emacs Lisp Track +🌟   The test runner is currently running Emacs 28.1 -### Contributing Guide +Currently the Emacs Lisp track doesn't feature a syllabus, so it only contains practice exercises. Practice exercises are open-ended problems that allow you to build and test your knowledge of a programming language. You can find the practice exercises referenced in the [config.json][config-json] and the files in the [`exercises/practice`][emacs-lisp-exercises-practice-dir] directory. The practice exercises are shared between tracks. You can find the canonical problem description in the [problem specifications repository][problem-specifications-repository]. -Please see the [contributing guide](https://exercism.org/contributing) -This describes how all the language tracks are put together, -as well as details about the common metadata, and high-level -information about contributing to existing problems and adding new problems. +
-### Issues +
+ + + + -Feel free to file any issues on the [elisp issue tracker](https://github.com/exercism/elisp/issues) for problems of -any size. Feel free to report typographical errors or poor wording for -example. You can greatly help improve the quality of the exercises by -filing reports of invalid solutions that pass tests or of valid solutions -that fail tests. +🌟🌟  Please take a moment to read our [Code of Conduct][exercism-code-of-conduct] 🌟🌟  +It might also be helpful to look at [Being a Good Community Member][being-a-good-community-member] & [The words that we use][the-words-that-we-use]. -New exercises or changes to existing ones can be submitted via a pull -request. You will need a GitHub account and you will need to fork -[exercism/emacs-lisp](https://github.com/exercism/emacs-lisp) to your account. See GitHub Help if you are unfamiliar -with the process. +                         Some defined roles in our community: [Contributors][exercism-contributors] **|** [Mentors][exercism-mentors] **|** [Maintainers][exercism-track-maintainers] **|** [Admins][exercism-admins] +
-### GNU Emacs icon +
+ +

Contributing to The Emacs Lisp Track

+ + + +We 💙 our community and welcome contributions. +
+The following guide is intended to give you an overview about the different ways to help and to point you to the relevant documentation. + +
+There are several ways of contributing to the Emacs Lisp track. Examples would be + +- [reporting][emacs-lisp-new-issue] problems with the track or possible improvements +- working on [practice exercises][practice-exercises] +- working on track [tooling][emacs-lisp-tooling] and [CI][emacs-lisp-ci] +- working on the [test runner][emacs-lisp-test-runner] +- working on track documents +- contributing [approaches][exercism-approaches] +- contributing [articles][exercism-articles] + +Feel free to open an issue or open a pull request for any of those items. +Pull Requests should be focused on a single change. +They must pass the CI system and need a review by a maintainer before they can get merged. + +You can also start work on + +- a [syllabus][exercism-syllabus] / [concept exercises][exercism-concept-exercises-stories], used to teach a language step by step +- an [analyzer][exercism-analyzers], used to give automated feedback on student solutions +- a [representer][exercism-representers], used to give automated feedback on sutdent solutions + +If you want to start work on one of those items please first get in touch via [GitHub issues][emacs-lisp-github-issues] or the [discourse forum][discourse-forum-emacs-lisp]. + + + +✨ 🦄  _**Not sure how to do something? Check out the documentation!**_ +     [Structure][exercism-track-structure] **|** [Tasks][exercism-tasks] **|** [Concepts][exercism-concepts] **|** [Concept Exercises][concept-exercises] **|** [Practice Exercises][practice-exercises] **|** [Presentation][exercise-presentation] +     [Writing Style Guide][exercism-writing-style] **|** [Markdown Specification][exercism-markdown-specification] (_markdown guidelines for [contributing][website-contributing-section] on exercism.org_) + +
+
+ +## Related repositories + +- [Emacs Lisp Test Runner][emacs-lisp-test-runner] - used to test the solutions submitted by students +- [Website Copy][exercism-website-copy] - contains [mentoring notes](https://exercism.org/docs/building/product/mentoring-notes) + +## Exercism Emacs Lisp Track License + +This repository uses the [MIT License][license]. + +## GNU Emacs icon The GNU Emacs icon was designed by Andrew Zhilin and is licensed under the Creative Commons Attribution-ShareAlike 3.0 License. We have modified the GNU Emacs icon to create the Emacs Lisp icon for Exercism. + +[exercism-website]: https://exercism.org/ +[emacs-lisp-new-issue]: https://github.com/exercism/emacs-lisp/issues/new +[exercism-emacs-lisp-track]: https://exercism.org/tracks/emacs-lisp +[emacs-lisp-exercises-practice-dir]: exercises/practice +[emacs-lisp-tooling]: /bin +[emacs-lisp-ci]: .github/workflows +[emacs-lisp-github-issues]: https://github.com/exercism/emacs-lisp/issues +[emacs-lisp-test-runner]: https://github.com/exercism/emacs-lisp-test-runner +[discourse-forum-emacs-lisp]: https://forum.exercism.org/c/programming/emacs-lisp/86 +[config-json]: https://github.com/exercism/emacs-lisp/blob/main/config.json +[being-a-good-community-member]: https://github.com/exercism/docs/tree/main/community/good-member +[chestertons-fence]: https://github.com/exercism/docs/blob/main/community/good-member/chestertons-fence.md +[concept-exercises]: https://github.com/exercism/docs/blob/main/building/tracks/concept-exercises.md +[exercise-presentation]: https://github.com/exercism/docs/blob/main/building/tracks/presentation.md +[exercism-admins]: https://github.com/exercism/docs/blob/main/community/administrators.md +[exercism-code-of-conduct]: https://exercism.org/docs/using/legal/code-of-conduct +[exercism-concepts]: https://github.com/exercism/docs/blob/main/building/tracks/concepts.md +[exercism-contributors]: https://github.com/exercism/docs/blob/main/community/contributors.md +[exercism-markdown-specification]: https://github.com/exercism/docs/blob/main/building/markdown/markdown.md +[exercism-mentors]: https://github.com/exercism/docs/tree/main/mentoring +[exercism-tasks]: https://exercism.org/docs/building/product/tasks +[exercism-track-maintainers]: https://github.com/exercism/docs/blob/main/community/maintainers.md +[exercism-track-structure]: https://github.com/exercism/docs/tree/main/building/tracks +[exercism-website]: https://exercism.org/ +[exercism-writing-style]: https://github.com/exercism/docs/blob/main/building/markdown/style-guide.md +[exercism-approaches]: https://exercism.org/docs/building/tracks/approaches +[exercism-articles]: https://exercism.org/docs/building/tracks/articles +[exercism-syllabus]: https://exercism.org/docs/building/tracks/syllabus +[exercism-concept-exercises-stories]: https://exercism.org/docs/building/tracks/stories +[exercism-analyzers]: https://exercism.org/docs/building/tooling/analyzers +[exercism-representers]: https://exercism.org/docs/building/tooling/representers +[practice-exercises]: https://exercism.org/docs/building/tracks/practice-exercises +[prs]: https://github.com/exercism/docs/blob/main/community/good-member/pull-requests.md +[problem-specifications-repository]: https://github.com/exercism/problem-specifications/ +[suggesting-improvements]: https://github.com/exercism/docs/blob/main/community/good-member/suggesting-exercise-improvements.md +[the-words-that-we-use]: https://github.com/exercism/docs/blob/main/community/good-member/words.md +[website-contributing-section]: https://exercism.org/docs/building +[exercism-website-copy]: https://github.com/exercism/website-copy +[license]: /LICENSE From 02586df0d2be10d74dfc22c617906fd6d249f156 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Mon, 8 May 2023 13:02:51 +0200 Subject: [PATCH 014/162] Upgrade CI test run to Emacs 28.2 (#291) Brings the CI test run in sync with the test runner. See https://github.com/exercism/emacs-lisp-test-runner/pull/58 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2eba947f..7732325d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: purcell/setup-emacs@ac5a5667ef01c598f55e66e0b0abdad5d825daf8 with: - version: 28.1 + version: 28.2 - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 From 1504fd60c4ea321d9705243ddd47f3aaeba09002 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Mon, 8 May 2023 13:34:02 +0200 Subject: [PATCH 015/162] Add practice exercise generator (#275) Adds a practice exercise generator called via `bin/generate_practice_exercise`. * adds instruction and configuration files via `configlet` * generates stubs for the solution and test file via Emacs Lisp --- Why does the generator not use the newer libjansson based JSON parser? The jansson library used by the new JSON support powered by libjansson fails on large integers. A few of the Exercism exercises feature large integers in the expected test data. There is an upstream issue: https://github.com/akheron/jansson/issues/69 The built-in json parsing written in Emacs Lisp doesn't have that problem. Since we won't run into performance issues this is a good solution for this tool. See https://emacs.stackexchange.com/questions/76530/json-parsing-fails-json-parse-error-too-big-integer/ for more info --- bin/generate_practice_exercise | 55 +++++ tools/README.md | 6 + tools/install-packages.el | 14 ++ tools/practice-exercise-generator.el | 197 ++++++++++++++++++ .../exercises/practice/solution.mustache | 10 + .../exercises/practice/test.mustache | 20 ++ tools/templates/partials/footer.mustache | 2 + tools/templates/partials/header.mustache | 5 + 8 files changed, 309 insertions(+) create mode 100755 bin/generate_practice_exercise create mode 100644 tools/README.md create mode 100644 tools/install-packages.el create mode 100644 tools/practice-exercise-generator.el create mode 100644 tools/templates/exercises/practice/solution.mustache create mode 100644 tools/templates/exercises/practice/test.mustache create mode 100644 tools/templates/partials/footer.mustache create mode 100644 tools/templates/partials/header.mustache diff --git a/bin/generate_practice_exercise b/bin/generate_practice_exercise new file mode 100755 index 00000000..fabc2646 --- /dev/null +++ b/bin/generate_practice_exercise @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +# Exit if anything fails. +set -euo pipefail + +# If argument not provided, print usage and exit +if [ -z "$1" ]; then + echo "Usage: bin/generate_practice_exercise " + exit 1 +fi + +if ! [ -x "$(command -v jq)" ]; then + echo "jq is required. Please install jq and make sure it is on the $PATH: https://stedolan.github.io/jq/download/" >&2 + exit 1 +fi + +if ! [ -x "$(command -v emacs)" ]; then + echo "Emacs is required. Please install Emacs and make sure it is on the $PATH: https://www.gnu.org/software/emacs/download.html" >&2 + exit 1 +fi + +SLUG="$1" +exercise_dir="exercises/practice/${SLUG}" + +download() { + file="$1" + url="$2" + curl --silent --show-error --fail --retry 3 --max-time 3 \ + --output "$file" "$url" +} + +# build configlet +echo "Fetching latest version of configlet..." +./bin/fetch-configlet + +# Preparing config.json +echo "Adding instructions and configuration files..." +UUID=$(bin/configlet uuid) +jq --arg slug "$SLUG" --arg uuid "$UUID" \ + '.exercises.practice += [{slug: $slug, name: "TODO", uuid: $uuid, practices: [], prerequisites: [], difficulty: 5}]' \ + config.json > config.json.tmp +# jq always rounds whole numbers, but average_run_time needs to be a float +sed -i 's/"average_run_time": \([[:digit:]]\+\)$/"average_run_time": 2.0/' config.json.tmp +mv config.json.tmp config.json + +# Create instructions and config files +./bin/configlet sync --update --yes --docs --filepaths --metadata --exercise "$SLUG" + +pushd tools +emacs -batch -l install-packages.el -l practice-exercise-generator.el --eval "(exercism/generate-practice-exercise \"$SLUG\")" +popd + +echo "All stub files were created. After implementing the solution, tests and configuration, please run:" +echo " ./bin/configlet sync --update --tests --exercise ${SLUG}" +echo " ./bin/configlet fmt --update --yes --exercise ${SLUG}" diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 00000000..7b5b7170 --- /dev/null +++ b/tools/README.md @@ -0,0 +1,6 @@ +# Exercism Emacs Lisp track tools + +## practice-exercise-generator.el + +The exercise generator creates solution stub files and test stub files from the canonical data json. +Don't call it directly, instead call via /bin/generate_practice_exercise . diff --git a/tools/install-packages.el b/tools/install-packages.el new file mode 100644 index 00000000..8f14e5d8 --- /dev/null +++ b/tools/install-packages.el @@ -0,0 +1,14 @@ +(defun exercism//install-required-packages () + (require 'package) + (package-initialize) + (unless package-archive-contents + (add-to-list + 'package-archives '("gnu" . "https://elpa.gnu.org/packages/") + t) + (add-to-list + 'package-archives '("melpa" . "https://melpa.org/packages/") + t) + (package-refresh-contents)) + (dolist (pkg '(mustache ht string-inflection)) + (unless (package-installed-p pkg) + (package-install pkg)))) diff --git a/tools/practice-exercise-generator.el b/tools/practice-exercise-generator.el new file mode 100644 index 00000000..09548633 --- /dev/null +++ b/tools/practice-exercise-generator.el @@ -0,0 +1,197 @@ +;;; practice-exercise-generator.el --- Practice Exercise Generator (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Used to generate solution and test stub files for practice exercises. +;;; Intended to be called by /bin/generate_practice_exercise. + +;;; Known issues: +;;; Generates two newlines at the end of the solution and test file. + +;;; Code: + +(exercism//install-required-packages) + +(require 'mustache) +(require 'ht) +(require 'string-inflection) +(require 'json) +(require 'subr-x) +(require 'seq) + +(defun exercism/generate-practice-exercise (exercise-slug) + "Generate scaffolding for practice exercise EXERCISE-SLUG from the canonical data found in the problem-specifications." + (with-temp-buffer + (url-insert-file-contents + (concat + "https://raw.githubusercontent.com/exercism/problem-specifications/main/exercises/" + exercise-slug + "/canonical-data.json")) + (goto-char 1) + + (let* ((json-object-type 'hash-table) + (json-key-type 'string) + (canonical-data (json-read)) + (functions (exercism//retrieve-functions canonical-data))) + (exercism//generate-solution-stubs + exercise-slug canonical-data functions) + (exercism//generate-test-stubs + exercise-slug canonical-data functions)))) + +(defun exercism//generate-solution-stubs + (exercise-slug canonical-data functions) + "Generate solution file with function stubs. +File location is exercises/practice/EXERCISE-SLUG/EXERCISE-SLUG.el." + (let* ((mustache-partial-paths (list "templates/partials")) + (package-title (exercism//retrieve-title exercise-slug)) + (generated-stubs + (mustache-render + (exercism//file-to-string + "templates/exercises/practice/solution.mustache") + (ht + ("filename" exercise-slug) + ("package-title" package-title) + ("functions" functions))))) + (exercism//write-to-file + (concat + "../exercises/practice/" exercise-slug "/" exercise-slug ".el") + generated-stubs) + (exercism//write-to-file + (concat + "../exercises/practice/" exercise-slug "/.meta/example.el") + generated-stubs))) + +(defun exercism//retrieve-functions (canonical-data) + "For each function to implement, retrieve function-name and function-paramater from CANONICAL-DATA. + +Returns a list of hash-tables. +Each hash-table has the keys: + function-name: The name of the function in kebab-case + function-parameters: The parameters of the function in kebab-case, separated by spaces" + (seq-uniq (flatten-tree + (append + (named-let retrieve ((cases canonical-data)) + (if (hash-table-p cases) + (retrieve (gethash "cases" cases)) + (mapcar + (lambda (elem) + (if (gethash "cases" elem) + (retrieve (gethash "cases" elem)) + (ht + ("function-name" + (string-inflection-kebab-case-function + (gethash "property" elem))) + ("function-parameters" (string-join + (seq-map + 'string-inflection-kebab-case-function + (hash-table-keys (gethash "input" elem))) + " "))))) + cases))))) + (lambda (elem1 elem2) + (equal + (gethash "function-name" elem1) + (gethash "function-name" elem2))))) + +(defun exercism//retrieve-title (exercise-slug) + "Retrieve canonical title of exercise EXERCISE-SLUG from metadata.toml." + (with-temp-buffer + (url-insert-file-contents + (concat + "https://raw.githubusercontent.com/exercism/problem-specifications/main/exercises/" + exercise-slug + "/metadata.toml")) + (beginning-of-buffer) + (save-match-data + (re-search-forward "^title *= *\"\\(.*\\)\"$") + (match-string 1)))) + +(defun exercism//write-to-file (file string) + "Writes STRING into FILE." + (with-temp-file file + (insert string))) + +(defun exercism//file-to-string (file) + "Convert FILE to string." + (with-temp-buffer + (insert-file-contents file) + (buffer-string))) + +(defun exercism//generate-test-stubs + (exercise-slug canonical-data functions) + "Generate test file with test function stubs. +File location is exercises/practice/EXERCISE-SLUG/EXERCISE-SLUG-test.el. + +Includes the expected input and output as a comment, so contributors +don't have to look up that information separately." + (let* ((tests (exercism//retrieve-tests canonical-data)) + (package-title (exercism//retrieve-title exercise-slug)) + (mustache-partial-paths (list "templates/partials")) + (generated-test-stubs + (mustache-render + (exercism//file-to-string + "templates/exercises/practice/test.mustache") + (ht + ("solution-filename" exercise-slug) + ("filename" (concat exercise-slug "-test")) + ("package-title" package-title) + ("functions" functions) + ("tests" tests))))) + (exercism//write-to-file + (concat + "../exercises/practice/" + exercise-slug + "/" + exercise-slug + "-test.el") + generated-test-stubs))) + +(defun exercism//retrieve-tests (canonical-data) + "Retrieve test data from CANONICAL-DATA. +Deprecated tests (tests that get reimplemented) are discarded. + +Returns a list of hash-tables. +Each hash-table has the keys: + test-name: name of test function in kebab-case + uuid: uuid that identifies the test + reimplements: either nil or uuid of test that gets reimplemented by that test + function-under-test: name of the function under test in kebab-case + input: text representation of the input to the function under test + expected: text representation of the expected result of the function under test" + (let* ((tests + (flatten-tree + (append + (named-let retrieve ((cases canonical-data)) + (if (hash-table-p cases) + (retrieve (gethash "cases" cases)) + (mapcar + (lambda (elem) + (if (gethash "cases" elem) + (retrieve (gethash "cases" elem)) + (ht + ("test-name" + (string-inflection-kebab-case-function + (replace-regexp-in-string + "[ |_]" "-" (gethash "description" elem)))) + ("uuid" (gethash "uuid" elem)) + ("reimplements" (gethash "reimplements" elem)) + ("function-under-test" + (string-inflection-kebab-case-function + (gethash "property" elem))) + ("input" (json-encode (gethash "input" elem))) + ("expected" + (json-encode (gethash "expected" elem)))))) + cases)))))) + (reimplemented-uuids + (seq-map + (lambda (hash) (gethash "reimplements" hash)) tests)) + (tests-without-reimplemented + (seq-filter + (lambda (elem) + (not + (seq-contains + reimplemented-uuids (gethash "uuid" elem)))) + tests))) + tests-without-reimplemented)) + +(provide 'practice-exercise-generator) +;;; practice-exercise-generator.el ends here diff --git a/tools/templates/exercises/practice/solution.mustache b/tools/templates/exercises/practice/solution.mustache new file mode 100644 index 00000000..521b637d --- /dev/null +++ b/tools/templates/exercises/practice/solution.mustache @@ -0,0 +1,10 @@ +{{> header}} + +{{#functions}} + +(defun {{function-name}} ({{function-parameters}}) + (error "Delete this S-Expression and write your own implementation")) +{{/functions}} + + +{{> footer}} diff --git a/tools/templates/exercises/practice/test.mustache b/tools/templates/exercises/practice/test.mustache new file mode 100644 index 00000000..3caccbad --- /dev/null +++ b/tools/templates/exercises/practice/test.mustache @@ -0,0 +1,20 @@ +{{> header}} + +(load-file "{{solution-filename}}.el") +{{#functions}} +(declare-function {{function-name}} "{{solution-filename}}.el" ({{function-parameters}})) +{{/functions}} + + +{{#tests}} + + +(defun {{test-name}} () + ;; Function under test: {{function-under-test}} + ;; Input: {{{input}}} + ;; Expected: {{{expected}}} + (error "Delete this S-Expression and implement the test")) +{{/tests}} + + +{{> footer}} diff --git a/tools/templates/partials/footer.mustache b/tools/templates/partials/footer.mustache new file mode 100644 index 00000000..f68600f0 --- /dev/null +++ b/tools/templates/partials/footer.mustache @@ -0,0 +1,2 @@ +(provide '{{filename}}) +;;; {{filename}}.el ends here diff --git a/tools/templates/partials/header.mustache b/tools/templates/partials/header.mustache new file mode 100644 index 00000000..cfe2f11a --- /dev/null +++ b/tools/templates/partials/header.mustache @@ -0,0 +1,5 @@ +;;; {{filename}}.el --- {{package-title}} (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: From 6317baa24a17e2875353a7f52e0ae3b2f1de7b58 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Tue, 9 May 2023 11:27:51 +0200 Subject: [PATCH 016/162] Update Emacs version in README.md (#294) Test runner is on Emacs 28.2 now --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e02ffbba..5dd5119d 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This repo holds all the instructions, tests, code, & support files for Emacs Lisp _exercises_ currently under development or implemented & available for students. If you haven't already, you can check out and study the live language track [here][exercism-emacs-lisp-track]. -🌟   The test runner is currently running Emacs 28.1 +🌟   The test runner is currently running Emacs 28.2 Currently the Emacs Lisp track doesn't feature a syllabus, so it only contains practice exercises. Practice exercises are open-ended problems that allow you to build and test your knowledge of a programming language. You can find the practice exercises referenced in the [config.json][config-json] and the files in the [`exercises/practice`][emacs-lisp-exercises-practice-dir] directory. The practice exercises are shared between tracks. You can find the canonical problem description in the [problem specifications repository][problem-specifications-repository]. From eaf8a2adfb559a58bc6062900c7c8e438478d33c Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Tue, 9 May 2023 15:40:08 +0200 Subject: [PATCH 017/162] Link to Discourse and Discord from corresponding badges (#295) - add missing links - make alt texts a bit clearer --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5dd5119d..1ce0bbe6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Exercism Emacs Lisp Track -![Discourse posts](https://img.shields.io/discourse/posts?server=https%3A%2F%2Fforum.exercism.org%2F) -![Discord](https://img.shields.io/discord/854117591135027261) +[![Exercism Discourse Forum](https://img.shields.io/discourse/posts?server=https%3A%2F%2Fforum.exercism.org%2F)](https://forum.exercism.org/) +[![Exercism Discord Invite](https://img.shields.io/discord/854117591135027261)](https://exercism.org/r/discord) [![Configlet Status](https://github.com/exercism/emacs-lisp/workflows/Configlet/badge.svg)](https://github.com/exercism/emacs-lisp/workflows/Configlet/badge.svg) [![Exercise Test Status](https://github.com/exercism/emacs-lisp/workflows/emacs-lisp%20%2F%20main/badge.svg)](https://github.com/exercism/emacs-lisp/workflows/emacs-lisp%20%2F%20main/badge.svg) From 3a27bbe6de728a61d33c89bfd31db54b1f7bbec7 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Wed, 10 May 2023 20:37:17 +0200 Subject: [PATCH 018/162] Fix stub generation for tests in practice exercise generator (#297) - need to use `ert-deftest` for tests instead of `defun` --- tools/templates/exercises/practice/test.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/templates/exercises/practice/test.mustache b/tools/templates/exercises/practice/test.mustache index 3caccbad..77a589e8 100644 --- a/tools/templates/exercises/practice/test.mustache +++ b/tools/templates/exercises/practice/test.mustache @@ -9,7 +9,7 @@ {{#tests}} -(defun {{test-name}} () +(ert-deftest {{test-name}} () ;; Function under test: {{function-under-test}} ;; Input: {{{input}}} ;; Expected: {{{expected}}} From 42786d22110b98432bab1e0530e7182e7d4ebfbe Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Fri, 12 May 2023 12:37:18 +0200 Subject: [PATCH 019/162] Add darts exercise (#296) --- config.json | 8 ++ .../practice/darts/.docs/instructions.md | 23 ++++ exercises/practice/darts/.meta/config.json | 18 +++ exercises/practice/darts/.meta/example.el | 22 ++++ exercises/practice/darts/.meta/tests.toml | 49 ++++++++ exercises/practice/darts/darts-test.el | 105 ++++++++++++++++++ exercises/practice/darts/darts.el | 14 +++ 7 files changed, 239 insertions(+) create mode 100644 exercises/practice/darts/.docs/instructions.md create mode 100644 exercises/practice/darts/.meta/config.json create mode 100644 exercises/practice/darts/.meta/example.el create mode 100644 exercises/practice/darts/.meta/tests.toml create mode 100644 exercises/practice/darts/darts-test.el create mode 100644 exercises/practice/darts/darts.el diff --git a/config.json b/config.json index 0b3ef12e..52126727 100644 --- a/config.json +++ b/config.json @@ -437,6 +437,14 @@ "pattern-matching", "recursion" ] + }, + { + "slug": "darts", + "name": "Darts", + "uuid": "ca189b4e-713d-4722-b21e-c07d1b975b58", + "practices": [], + "prerequisites": [], + "difficulty": 1 } ] }, diff --git a/exercises/practice/darts/.docs/instructions.md b/exercises/practice/darts/.docs/instructions.md new file mode 100644 index 00000000..70f0e53d --- /dev/null +++ b/exercises/practice/darts/.docs/instructions.md @@ -0,0 +1,23 @@ +# Instructions + +Write a function that returns the earned points in a single toss of a Darts game. + +[Darts][darts] is a game where players throw darts at a [target][darts-target]. + +In our particular instance of the game, the target rewards 4 different amounts of points, depending on where the dart lands: + +- If the dart lands outside the target, player earns no points (0 points). +- If the dart lands in the outer circle of the target, player earns 1 point. +- If the dart lands in the middle circle of the target, player earns 5 points. +- If the dart lands in the inner circle of the target, player earns 10 points. + +The outer circle has a radius of 10 units (this is equivalent to the total radius for the entire target), the middle circle a radius of 5 units, and the inner circle a radius of 1. +Of course, they are all centered at the same point — that is, the circles are [concentric][] defined by the coordinates (0, 0). + +Write a function that given a point in the target (defined by its [Cartesian coordinates][cartesian-coordinates] `x` and `y`, where `x` and `y` are [real][real-numbers]), returns the correct amount earned by a dart landing at that point. + +[darts]: https://en.wikipedia.org/wiki/Darts +[darts-target]: https://en.wikipedia.org/wiki/Darts#/media/File:Darts_in_a_dartboard.jpg +[concentric]: https://mathworld.wolfram.com/ConcentricCircles.html +[cartesian-coordinates]: https://www.mathsisfun.com/data/cartesian-coordinates.html +[real-numbers]: https://www.mathsisfun.com/numbers/real-numbers.html diff --git a/exercises/practice/darts/.meta/config.json b/exercises/practice/darts/.meta/config.json new file mode 100644 index 00000000..fc17e154 --- /dev/null +++ b/exercises/practice/darts/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "fap" + ], + "files": { + "solution": [ + "darts.el" + ], + "test": [ + "darts-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Write a function that returns the earned points in a single toss of a Darts game.", + "source": "Inspired by an exercise created by a professor Della Paolera in Argentina" +} diff --git a/exercises/practice/darts/.meta/example.el b/exercises/practice/darts/.meta/example.el new file mode 100644 index 00000000..b9264a29 --- /dev/null +++ b/exercises/practice/darts/.meta/example.el @@ -0,0 +1,22 @@ +;;; darts.el --- Darts (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun score (x y) + (let ((distance-to-center (sqrt (+ (expt x 2) (expt y 2))))) + (cond + ((<= distance-to-center 1) + 10) + ((<= distance-to-center 5) + 5) + ((<= distance-to-center 10) + 1) + (t + 0)))) + + +(provide 'darts) +;;; darts.el ends here diff --git a/exercises/practice/darts/.meta/tests.toml b/exercises/practice/darts/.meta/tests.toml new file mode 100644 index 00000000..fbe2976d --- /dev/null +++ b/exercises/practice/darts/.meta/tests.toml @@ -0,0 +1,49 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[9033f731-0a3a-4d9c-b1c0-34a1c8362afb] +description = "Missed target" + +[4c9f6ff4-c489-45fd-be8a-1fcb08b4d0ba] +description = "On the outer circle" + +[14378687-ee58-4c9b-a323-b089d5274be8] +description = "On the middle circle" + +[849e2e63-85bd-4fed-bc3b-781ae962e2c9] +description = "On the inner circle" + +[1c5ffd9f-ea66-462f-9f06-a1303de5a226] +description = "Exactly on center" + +[b65abce3-a679-4550-8115-4b74bda06088] +description = "Near the center" + +[66c29c1d-44f5-40cf-9927-e09a1305b399] +description = "Just within the inner circle" + +[d1012f63-c97c-4394-b944-7beb3d0b141a] +description = "Just outside the inner circle" + +[ab2b5666-b0b4-49c3-9b27-205e790ed945] +description = "Just within the middle circle" + +[70f1424e-d690-4860-8caf-9740a52c0161] +description = "Just outside the middle circle" + +[a7dbf8db-419c-4712-8a7f-67602b69b293] +description = "Just within the outer circle" + +[e0f39315-9f9a-4546-96e4-a9475b885aa7] +description = "Just outside the outer circle" + +[045d7d18-d863-4229-818e-b50828c75d19] +description = "Asymmetric position between the inner and middle circles" diff --git a/exercises/practice/darts/darts-test.el b/exercises/practice/darts/darts-test.el new file mode 100644 index 00000000..0b5d5a39 --- /dev/null +++ b/exercises/practice/darts/darts-test.el @@ -0,0 +1,105 @@ +;;; darts-test.el --- Darts (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "darts.el") +(declare-function score "darts.el" (x y)) + + +(ert-deftest missed-target () + ;; Function under test: score + ;; Input: {"x":-9,"y":9} + ;; Expected: 0 + (should (equal 0 (score -9 9)))) + + +(ert-deftest on-the-outer-circle () + ;; Function under test: score + ;; Input: {"x":0,"y":10} + ;; Expected: 1 + (should (equal 1 (score 0 10)))) + + +(ert-deftest on-the-middle-circle () + ;; Function under test: score + ;; Input: {"x":-5,"y":0} + ;; Expected: 5 + (should (equal 5 (score -5 0)))) + + +(ert-deftest on-the-inner-circle () + ;; Function under test: score + ;; Input: {"x":0,"y":-1} + ;; Expected: 10 + (should (equal 10 (score 0 -1)))) + + +(ert-deftest exactly-on-center () + ;; Function under test: score + ;; Input: {"x":0,"y":0} + ;; Expected: 10 + (should (equal 10 (score 0 0)))) + + +(ert-deftest near-the-center () + ;; Function under test: score + ;; Input: {"x":-0.1,"y":-0.1} + ;; Expected: 10 + (should (equal 10 (score -0.1 -0.1)))) + + +(ert-deftest just-within-the-inner-circle () + ;; Function under test: score + ;; Input: {"x":0.7,"y":0.7} + ;; Expected: 10 + (should (equal 10 (score 0.7 0.7)))) + + +(ert-deftest just-outside-the-inner-circle () + ;; Function under test: score + ;; Input: {"x":0.8,"y":-0.8} + ;; Expected: 5 + (should (equal 5 (score 0.8 0.8)))) + + +(ert-deftest just-within-the-middle-circle () + ;; Function under test: score + ;; Input: {"x":-3.5,"y":3.5} + ;; Expected: 5 + (should (equal 5 (score -3.5 3.5)))) + + +(ert-deftest just-outside-the-middle-circle () + ;; Function under test: score + ;; Input: {"x":-3.6,"y":-3.6} + ;; Expected: 1 + (should (equal 1 (score -3.6 -3.6)))) + + +(ert-deftest just-within-the-outer-circle () + ;; Function under test: score + ;; Input: {"x":-7.0,"y":7.0} + ;; Expected: 1 + (should (equal 1 (score -7.0 7.0)))) + + +(ert-deftest just-outside-the-outer-circle () + ;; Function under test: score + ;; Input: {"x":7.1,"y":-7.1} + ;; Expected: 0 + (should (equal 0 (score 7.1 -7.1)))) + + +(ert-deftest asymmetric-position-between-the-inner-and-middle-circles + () + ;; Function under test: score + ;; Input: {"x":0.5,"y":-4} + ;; Expected: 5 + (should (equal 5 (score 0.5 -4)))) + + +(provide 'darts-test) +;;; darts-test.el ends here diff --git a/exercises/practice/darts/darts.el b/exercises/practice/darts/darts.el new file mode 100644 index 00000000..4e079d1c --- /dev/null +++ b/exercises/practice/darts/darts.el @@ -0,0 +1,14 @@ +;;; darts.el --- Darts (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun score (x y) + (error + "Delete this S-Expression and write your own implementation")) + + +(provide 'darts) +;;; darts.el ends here From 13510b5f17a4c945742dfa4a71c08fabc5e1e203 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Fri, 12 May 2023 12:37:57 +0200 Subject: [PATCH 020/162] Sync practice exercises with `problem-specifications` upstream (#298) Upstream: https://github.com/exercism/problem-specifications/ closes #293 --- exercises/practice/roman-numerals/.docs/instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/roman-numerals/.docs/instructions.md b/exercises/practice/roman-numerals/.docs/instructions.md index bb7e909d..247ea089 100644 --- a/exercises/practice/roman-numerals/.docs/instructions.md +++ b/exercises/practice/roman-numerals/.docs/instructions.md @@ -36,6 +36,6 @@ In Roman numerals 1990 is MCMXC: 2000=MM 8=VIII -Learn more about [Roman numberals on Wikipedia][roman-numerals]. +Learn more about [Roman numerals on Wikipedia][roman-numerals]. [roman-numerals]: https://wiki.imperivm-romanvm.com/wiki/Roman_Numerals From 3bf3677f5097ad3b320d936939ef5e213b390f47 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Fri, 19 May 2023 10:15:04 +0200 Subject: [PATCH 021/162] Add affine-cipher practice exercise (#299) --------- Co-authored-by: Erik Schierboom --- config.json | 8 ++ .../affine-cipher/.docs/instructions.md | 74 +++++++++++ .../practice/affine-cipher/.meta/config.json | 19 +++ .../practice/affine-cipher/.meta/example.el | 95 ++++++++++++++ .../practice/affine-cipher/.meta/tests.toml | 58 +++++++++ .../affine-cipher/affine-cipher-test.el | 123 ++++++++++++++++++ .../practice/affine-cipher/affine-cipher.el | 18 +++ 7 files changed, 395 insertions(+) create mode 100644 exercises/practice/affine-cipher/.docs/instructions.md create mode 100644 exercises/practice/affine-cipher/.meta/config.json create mode 100644 exercises/practice/affine-cipher/.meta/example.el create mode 100644 exercises/practice/affine-cipher/.meta/tests.toml create mode 100644 exercises/practice/affine-cipher/affine-cipher-test.el create mode 100644 exercises/practice/affine-cipher/affine-cipher.el diff --git a/config.json b/config.json index 52126727..bce76fa0 100644 --- a/config.json +++ b/config.json @@ -445,6 +445,14 @@ "practices": [], "prerequisites": [], "difficulty": 1 + }, + { + "slug": "affine-cipher", + "name": "Affine Cipher", + "uuid": "7d966a40-3cf7-422a-99b1-c0bf05e151b2", + "practices": [], + "prerequisites": [], + "difficulty": 4 } ] }, diff --git a/exercises/practice/affine-cipher/.docs/instructions.md b/exercises/practice/affine-cipher/.docs/instructions.md new file mode 100644 index 00000000..2ad6d152 --- /dev/null +++ b/exercises/practice/affine-cipher/.docs/instructions.md @@ -0,0 +1,74 @@ +# Instructions + +Create an implementation of the affine cipher, an ancient encryption system created in the Middle East. + +The affine cipher is a type of monoalphabetic substitution cipher. +Each character is mapped to its numeric equivalent, encrypted with a mathematical function and then converted to the letter relating to its new numeric value. +Although all monoalphabetic ciphers are weak, the affine cipher is much stronger than the atbash cipher, because it has many more keys. + +[//]: # ( monoalphabetic as spelled by Merriam-Webster, compare to polyalphabetic ) + +## Encryption + +The encryption function is: + +```text +E(x) = (ai + b) mod m +``` + +Where: + +- `i` is the letter's index from `0` to the length of the alphabet - 1 +- `m` is the length of the alphabet. + For the Roman alphabet `m` is `26`. +- `a` and `b` are integers which make the encryption key + +Values `a` and `m` must be *coprime* (or, *relatively prime*) for automatic decryption to succeed, i.e., they have number `1` as their only common factor (more information can be found in the [Wikipedia article about coprime integers][coprime-integers]). +In case `a` is not coprime to `m`, your program should indicate that this is an error. +Otherwise it should encrypt or decrypt with the provided key. + +For the purpose of this exercise, digits are valid input but they are not encrypted. +Spaces and punctuation characters are excluded. +Ciphertext is written out in groups of fixed length separated by space, the traditional group size being `5` letters. +This is to make it harder to guess encrypted text based on word boundaries. + +## Decryption + +The decryption function is: + +```text +D(y) = (a^-1)(y - b) mod m +``` + +Where: + +- `y` is the numeric value of an encrypted letter, i.e., `y = E(x)` +- it is important to note that `a^-1` is the modular multiplicative inverse (MMI) of `a mod m` +- the modular multiplicative inverse only exists if `a` and `m` are coprime. + +The MMI of `a` is `x` such that the remainder after dividing `ax` by `m` is `1`: + +```text +ax mod m = 1 +``` + +More information regarding how to find a Modular Multiplicative Inverse and what it means can be found in the [related Wikipedia article][mmi]. + +## General Examples + +- Encrypting `"test"` gives `"ybty"` with the key `a = 5`, `b = 7` +- Decrypting `"ybty"` gives `"test"` with the key `a = 5`, `b = 7` +- Decrypting `"ybty"` gives `"lqul"` with the wrong key `a = 11`, `b = 7` +- Decrypting `"kqlfd jzvgy tpaet icdhm rtwly kqlon ubstx"` gives `"thequickbrownfoxjumpsoverthelazydog"` with the key `a = 19`, `b = 13` +- Encrypting `"test"` with the key `a = 18`, `b = 13` is an error because `18` and `26` are not coprime + +## Example of finding a Modular Multiplicative Inverse (MMI) + +Finding MMI for `a = 15`: + +- `(15 * x) mod 26 = 1` +- `(15 * 7) mod 26 = 1`, ie. `105 mod 26 = 1` +- `7` is the MMI of `15 mod 26` + +[mmi]: https://en.wikipedia.org/wiki/Modular_multiplicative_inverse +[coprime-integers]: https://en.wikipedia.org/wiki/Coprime_integers diff --git a/exercises/practice/affine-cipher/.meta/config.json b/exercises/practice/affine-cipher/.meta/config.json new file mode 100644 index 00000000..5738ea8f --- /dev/null +++ b/exercises/practice/affine-cipher/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "fapdash" + ], + "files": { + "solution": [ + "affine-cipher.el" + ], + "test": [ + "affine-cipher-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Create an implementation of the Affine cipher, an ancient encryption algorithm from the Middle East.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Affine_cipher" +} diff --git a/exercises/practice/affine-cipher/.meta/example.el b/exercises/practice/affine-cipher/.meta/example.el new file mode 100644 index 00000000..be7b9cbf --- /dev/null +++ b/exercises/practice/affine-cipher/.meta/example.el @@ -0,0 +1,95 @@ +;;; affine-cipher.el --- Affine Cipher (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'seq) + +(defconst letters-in-latin 26) + +(defun encode (phrase key) + (let ((a (cdr (assoc "a" key))) + (b (cdr (assoc "b" key))) + (m letters-in-latin) + (phrase-cleaned + (replace-regexp-in-string "[^a-z0-9]" "" (downcase phrase)))) + (unless (coprime-p a m) + (error "a and m must be coprime.")) + (mapconcat + 'identity + (seq-partition + (mapcar + (apply-partially 'exercism-encode-char a b m) phrase-cleaned) + 5) + " "))) + +(defun exercism-encode-char (a b m char) + (if (<= ?0 char ?9) + char + (+ (mod (+ (* a (- char ?a)) b) m) ?a))) + +(defun decode (phrase key) + (let ((a (cdr (assoc "a" key))) + (b (cdr (assoc "b" key))) + (m letters-in-latin) + (phrase-cleaned + (replace-regexp-in-string "[^a-z0-9]" "" (downcase phrase)))) + (unless (coprime-p a m) + (error "a and m must be coprime.")) + (seq-into + (mapcar + (apply-partially 'exercism-decode-char a b m) phrase-cleaned) + 'string))) + +(defun exercism-decode-char (a b m char) + (if (<= ?0 char ?9) + char + (+ (mod (* (mmi a m) (- (- char ?a) b)) m) ?a))) + +(defun mmi (a m) + "Find the modular multiplicative inverse (MMI) of A mod M using the extended Euclidean algorithm." + (let ((tt 0) ;; t is already used as constant for truth + (newtt 1) + (r m) + (newr a)) + (while (not (= newr 0)) + (let ((quotient (/ r newr)) + temp) + (setq temp newtt) + (setq newtt (- tt (* quotient newtt))) + (setq tt temp) + (setq temp newr) + (setq newr (- r (* quotient newr))) + (setq r temp))) + + (if (> r 1) + (error + "a is not invertible (provided numbers are not coprime)")) + (if (< tt 0) + (setq tt (+ tt m))) + tt)) + +(defun coprime-p (m n) + (= (gcd m n) 1)) + +(defun gcd (m n) + "Find greatest common divisor of M and N. +Uses the Euclidian Algorithm." + (let ((m + (if (< m n) + n + m)) + (n + (if (< m n) + m + n)) + r) + (while (not (= n 0)) + (setq r (mod m n)) + (setq m n) + (setq n r)) + m)) + +(provide 'affine-cipher) +;;; affine-cipher.el ends here diff --git a/exercises/practice/affine-cipher/.meta/tests.toml b/exercises/practice/affine-cipher/.meta/tests.toml new file mode 100644 index 00000000..07cce7c7 --- /dev/null +++ b/exercises/practice/affine-cipher/.meta/tests.toml @@ -0,0 +1,58 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[2ee1d9af-1c43-416c-b41b-cefd7d4d2b2a] +description = "encode -> encode yes" + +[785bade9-e98b-4d4f-a5b0-087ba3d7de4b] +description = "encode -> encode no" + +[2854851c-48fb-40d8-9bf6-8f192ed25054] +description = "encode -> encode OMG" + +[bc0c1244-b544-49dd-9777-13a770be1bad] +description = "encode -> encode O M G" + +[381a1a20-b74a-46ce-9277-3778625c9e27] +description = "encode -> encode mindblowingly" + +[6686f4e2-753b-47d4-9715-876fdc59029d] +description = "encode -> encode numbers" + +[ae23d5bd-30a8-44b6-afbe-23c8c0c7faa3] +description = "encode -> encode deep thought" + +[c93a8a4d-426c-42ef-9610-76ded6f7ef57] +description = "encode -> encode all the letters" + +[0673638a-4375-40bd-871c-fb6a2c28effb] +description = "encode -> encode with a not coprime to m" + +[3f0ac7e2-ec0e-4a79-949e-95e414953438] +description = "decode -> decode exercism" + +[241ee64d-5a47-4092-a5d7-7939d259e077] +description = "decode -> decode a sentence" + +[33fb16a1-765a-496f-907f-12e644837f5e] +description = "decode -> decode numbers" + +[20bc9dce-c5ec-4db6-a3f1-845c776bcbf7] +description = "decode -> decode all the letters" + +[623e78c0-922d-49c5-8702-227a3e8eaf81] +description = "decode -> decode with no spaces in input" + +[58fd5c2a-1fd9-4563-a80a-71cff200f26f] +description = "decode -> decode with too many spaces" + +[b004626f-c186-4af9-a3f4-58f74cdb86d5] +description = "decode -> decode with a not coprime to m" diff --git a/exercises/practice/affine-cipher/affine-cipher-test.el b/exercises/practice/affine-cipher/affine-cipher-test.el new file mode 100644 index 00000000..0c820fde --- /dev/null +++ b/exercises/practice/affine-cipher/affine-cipher-test.el @@ -0,0 +1,123 @@ +;;; affine-cipher-test.el --- Affine Cipher (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "affine-cipher.el") +(declare-function encode "affine-cipher.el" (phrase key)) +(declare-function decode "affine-cipher.el" (phrase key)) + + +(ert-deftest encode-yes () + (should (equal "xbt" (encode "yes" '(("a" . 5) ("b" . 7)))))) + + +(ert-deftest encode-no () + (should (equal "fu" (encode "no" '(("a" . 15) ("b" . 18)))))) + + +(ert-deftest encode-omg () + (should (equal "lvz" (encode "OMG" '(("a" . 21) ("b" . 3)))))) + + +(ert-deftest encode-o-m-g () + (should (equal "hjp" (encode "O M G" '(("a" . 25) ("b" . 47)))))) + + +(ert-deftest encode-mindblowingly () + (should + (equal + "rzcwa gnxzc dgt" + (encode "mindblowingly" '(("a" . 11) ("b" . 15)))))) + + +(ert-deftest encode-numbers () + (should + (equal + "jqgjc rw123 jqgjc rw" + (encode "Testing,1 2 3, testing." '(("a" . 3) ("b" . 4)))))) + + +(ert-deftest encode-deep-thought () + (should + (equal + "iynia fdqfb ifje" + (encode "Truth is fiction." '(("a" . 5) ("b" . 17)))))) + + +(ert-deftest encode-all-the-letters () + (should + (equal + "swxtj npvyk lruol iejdc blaxk swxmh qzglf" + (encode + "The quick brown fox jumps over the lazy dog." + '(("a" . 17) ("b" . 33)))))) + + +(ert-deftest encode-with-a-not-coprime-to-m () + (let ((error-data + (should-error + (encode "This is a test." '(("a" . 6) ("b" . 17)))))) + (should + (string= + "a and m must be coprime." (error-message-string error-data))))) + + +(ert-deftest decode-exercism () + (should + (equal "exercism" (decode "tytgn fjr" '(("a" . 3) ("b" . 7)))))) + + +(ert-deftest decode-a-sentence () + (should + (equal + "anobstacleisoftenasteppingstone" + (decode + "qdwju nqcro muwhn odqun oppmd aunwd o" + '(("a" . 19) ("b" . 16)))))) + + +(ert-deftest decode-numbers () + (should + (equal + "testing123testing" + (decode "odpoz ub123 odpoz ub" '(("a" . 25) ("b" . 7)))))) + + +(ert-deftest decode-all-the-letters () + (should + (equal + "thequickbrownfoxjumpsoverthelazydog" + (decode + "swxtj npvyk lruol iejdc blaxk swxmh qzglf" + '(("a" . 17) ("b" . 33)))))) + + +(ert-deftest decode-with-no-spaces-in-input () + (should + (equal + "thequickbrownfoxjumpsoverthelazydog" + (decode + "swxtjnpvyklruoliejdcblaxkswxmhqzglf" + '(("a" . 17) ("b" . 33)))))) + + +(ert-deftest decode-with-too-many-spaces () + (should + (equal + "jollygreengiant" + (decode "vszzm cly yd cg qdp" '(("a" . 15) ("b" . 16)))))) + + +(ert-deftest decode-with-a-not-coprime-to-m () + (let ((error-data + (should-error (decode "Test" '(("a" . 13) ("b" . 5)))))) + (should + (string= + "a and m must be coprime." (error-message-string error-data))))) + + +(provide 'affine-cipher-test) +;;; affine-cipher-test.el ends here diff --git a/exercises/practice/affine-cipher/affine-cipher.el b/exercises/practice/affine-cipher/affine-cipher.el new file mode 100644 index 00000000..c816f02c --- /dev/null +++ b/exercises/practice/affine-cipher/affine-cipher.el @@ -0,0 +1,18 @@ +;;; affine-cipher.el --- Affine Cipher (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun encode (phrase key) + (error + "Delete this S-Expression and write your own implementation")) + +(defun decode (phrase key) + (error + "Delete this S-Expression and write your own implementation")) + + +(provide 'affine-cipher) +;;; affine-cipher.el ends here From 0672eb84677347649bc135a571fcf980894adb54 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Fri, 19 May 2023 10:27:24 +0200 Subject: [PATCH 022/162] Add simple-cipher practice exercise (#300) * Add simple-cipher practice exercise `(random)` in Emacs Lisp (28.2) is not cryptographically secure. It has the option to get the seed for the PRNG from `/dev/urandom`, but uses libc's `rand()` to generate the numbers, which has a bias. See https://stackoverflow.com/questions/14678957/libc-random-number-generator-flawed Use `(random)` with LIMIT, should be the the fastest option. > With argument t, set the random number seed from the system's entropy > pool if available, otherwise from less-random volatile data such as the time. Co-authored-by: Erik Schierboom --------- Co-authored-by: Erik Schierboom --- config.json | 8 ++ .../simple-cipher/.docs/instructions.md | 66 ++++++++++++++++ .../practice/simple-cipher/.meta/config.json | 19 +++++ .../practice/simple-cipher/.meta/example.el | 52 +++++++++++++ .../practice/simple-cipher/.meta/tests.toml | 46 +++++++++++ .../simple-cipher/simple-cipher-test.el | 76 +++++++++++++++++++ .../practice/simple-cipher/simple-cipher.el | 22 ++++++ 7 files changed, 289 insertions(+) create mode 100644 exercises/practice/simple-cipher/.docs/instructions.md create mode 100644 exercises/practice/simple-cipher/.meta/config.json create mode 100644 exercises/practice/simple-cipher/.meta/example.el create mode 100644 exercises/practice/simple-cipher/.meta/tests.toml create mode 100644 exercises/practice/simple-cipher/simple-cipher-test.el create mode 100644 exercises/practice/simple-cipher/simple-cipher.el diff --git a/config.json b/config.json index bce76fa0..5faa5297 100644 --- a/config.json +++ b/config.json @@ -446,6 +446,14 @@ "prerequisites": [], "difficulty": 1 }, + { + "slug": "simple-cipher", + "name": "Simple Cipher", + "uuid": "c3cc6d91-b633-44d6-b7e1-04abb33e712c", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "affine-cipher", "name": "Affine Cipher", diff --git a/exercises/practice/simple-cipher/.docs/instructions.md b/exercises/practice/simple-cipher/.docs/instructions.md new file mode 100644 index 00000000..475af618 --- /dev/null +++ b/exercises/practice/simple-cipher/.docs/instructions.md @@ -0,0 +1,66 @@ +# Instructions + +Implement a simple shift cipher like Caesar and a more secure substitution cipher. + +## Step 1 + +"If he had anything confidential to say, he wrote it in cipher, that is, by so changing the order of the letters of the alphabet, that not a word could be made out. +If anyone wishes to decipher these, and get at their meaning, he must substitute the fourth letter of the alphabet, namely D, for A, and so with the others." +—Suetonius, Life of Julius Caesar + +Ciphers are very straight-forward algorithms that allow us to render text less readable while still allowing easy deciphering. +They are vulnerable to many forms of cryptanalysis, but Caesar was lucky that his enemies were not cryptanalysts. + +The Caesar Cipher was used for some messages from Julius Caesar that were sent afield. +Now Caesar knew that the cipher wasn't very good, but he had one ally in that respect: almost nobody could read well. +So even being a couple letters off was sufficient so that people couldn't recognize the few words that they did know. + +Your task is to create a simple shift cipher like the Caesar Cipher. +This image is a great example of the Caesar Cipher: + +![Caesar Cipher][img-caesar-cipher] + +For example: + +Giving "iamapandabear" as input to the encode function returns the cipher "ldpdsdqgdehdu". +Obscure enough to keep our message secret in transit. + +When "ldpdsdqgdehdu" is put into the decode function it would return the original "iamapandabear" letting your friend read your original message. + +## Step 2 + +Shift ciphers quickly cease to be useful when the opposition commander figures them out. +So instead, let's try using a substitution cipher. +Try amending the code to allow us to specify a key and use that for the shift distance. + +Here's an example: + +Given the key "aaaaaaaaaaaaaaaaaa", encoding the string "iamapandabear" +would return the original "iamapandabear". + +Given the key "ddddddddddddddddd", encoding our string "iamapandabear" +would return the obscured "ldpdsdqgdehdu" + +In the example above, we've set a = 0 for the key value. +So when the plaintext is added to the key, we end up with the same message coming out. +So "aaaa" is not an ideal key. +But if we set the key to "dddd", we would get the same thing as the Caesar Cipher. + +## Step 3 + +The weakest link in any cipher is the human being. +Let's make your substitution cipher a little more fault tolerant by providing a source of randomness and ensuring that the key contains only lowercase letters. + +If someone doesn't submit a key at all, generate a truly random key of at least 100 lowercase characters in length. + +## Extensions + +Shift ciphers work by making the text slightly odd, but are vulnerable to frequency analysis. +Substitution ciphers help that, but are still very vulnerable when the key is short or if spaces are preserved. +Later on you'll see one solution to this problem in the exercise "crypto-square". + +If you want to go farther in this field, the questions begin to be about how we can exchange keys in a secure way. +Take a look at [Diffie-Hellman on Wikipedia][dh] for one of the first implementations of this scheme. + +[img-caesar-cipher]: https://upload.wikimedia.org/wikipedia/commons/thumb/4/4a/Caesar_cipher_left_shift_of_3.svg/320px-Caesar_cipher_left_shift_of_3.svg.png +[dh]: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange diff --git a/exercises/practice/simple-cipher/.meta/config.json b/exercises/practice/simple-cipher/.meta/config.json new file mode 100644 index 00000000..74ea7671 --- /dev/null +++ b/exercises/practice/simple-cipher/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "fapdash" + ], + "files": { + "solution": [ + "simple-cipher.el" + ], + "test": [ + "simple-cipher-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Implement a simple shift cipher like Caesar and a more secure substitution cipher.", + "source": "Substitution Cipher at Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Substitution_cipher" +} diff --git a/exercises/practice/simple-cipher/.meta/example.el b/exercises/practice/simple-cipher/.meta/example.el new file mode 100644 index 00000000..c22ed0c9 --- /dev/null +++ b/exercises/practice/simple-cipher/.meta/example.el @@ -0,0 +1,52 @@ +;;; simple-cipher.el --- Simple Cipher (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'seq) +(require 'cl-lib) + +(defconst alphabet-for-random-letter "abcdefghijklmnopqrstuvwxyz") + +(defun encode (plaintext key) + (simple-cipher plaintext key '+)) + +(defun decode (ciphertext key) + (simple-cipher ciphertext key '-)) + +(defun simple-cipher (text key fun) + (let ((calc-key + (if (<= (length text) (length key)) + key + (dotimes (_index (/ (length text) (length key)) key) + (let ((key-copy key)) + (setq key (concat key key-copy))))))) + (mapconcat + 'identity + (cl-mapcar (lambda (char1 char2) + (char-to-string + (+ ?a + (mod + (funcall fun (- char1 ?a) (- char2 ?a)) + (length alphabet-for-random-letter))))) + text + calc-key) + ""))) + +(defun generate-key () + (let ((key "")) + (dotimes (_i 100 key) + (setq + key + (concat + key + (char-to-string + (seq-elt + alphabet-for-random-letter + ;; NOT cryptographically secure! + ;; see https://emacs.stackexchange.com/questions/35615/secure-random-numbers + (random (length alphabet-for-random-letter))))))))) + +(provide 'simple-cipher) +;;; simple-cipher.el ends here diff --git a/exercises/practice/simple-cipher/.meta/tests.toml b/exercises/practice/simple-cipher/.meta/tests.toml new file mode 100644 index 00000000..77e6571e --- /dev/null +++ b/exercises/practice/simple-cipher/.meta/tests.toml @@ -0,0 +1,46 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[b8bdfbe1-bea3-41bb-a999-b41403f2b15d] +description = "Random key cipher -> Can encode" + +[3dff7f36-75db-46b4-ab70-644b3f38b81c] +description = "Random key cipher -> Can decode" + +[8143c684-6df6-46ba-bd1f-dea8fcb5d265] +description = "Random key cipher -> Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method" + +[defc0050-e87d-4840-85e4-51a1ab9dd6aa] +description = "Random key cipher -> Key is made only of lowercase letters" + +[565e5158-5b3b-41dd-b99d-33b9f413c39f] +description = "Substitution cipher -> Can encode" + +[d44e4f6a-b8af-4e90-9d08-fd407e31e67b] +description = "Substitution cipher -> Can decode" + +[70a16473-7339-43df-902d-93408c69e9d1] +description = "Substitution cipher -> Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method" + +[69a1458b-92a6-433a-a02d-7beac3ea91f9] +description = "Substitution cipher -> Can double shift encode" + +[21d207c1-98de-40aa-994f-86197ae230fb] +description = "Substitution cipher -> Can wrap on encode" + +[a3d7a4d7-24a9-4de6-bdc4-a6614ced0cb3] +description = "Substitution cipher -> Can wrap on decode" + +[e31c9b8c-8eb6-45c9-a4b5-8344a36b9641] +description = "Substitution cipher -> Can encode messages longer than the key" + +[93cfaae0-17da-4627-9a04-d6d1e1be52e3] +description = "Substitution cipher -> Can decode messages longer than the key" diff --git a/exercises/practice/simple-cipher/simple-cipher-test.el b/exercises/practice/simple-cipher/simple-cipher-test.el new file mode 100644 index 00000000..80246cac --- /dev/null +++ b/exercises/practice/simple-cipher/simple-cipher-test.el @@ -0,0 +1,76 @@ +;;; simple-cipher-test.el --- Simple Cipher (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "simple-cipher.el") +(declare-function encode "simple-cipher.el" (plaintext key)) +(declare-function decode "simple-cipher.el" (ciphertext key)) +(declare-function generate-key "simple-cipher.el" ()) + + +(ert-deftest can-encode-random-key () + (let ((key (generate-key))) + (should + (string= + (substring key 0 (length "aaaaaaaaaa")) + (encode "aaaaaaaaaa" key))))) + + +(ert-deftest can-decode-random-key () + (let ((key (generate-key))) + (should + (string= + "aaaaaaaaaa" + (decode (substring key 0 (length "aaaaaaaaaa")) key))))) + + +(ert-deftest is-reversible-random-key () + (let* ((key (generate-key)) + (encoded (encode "abcdefghij" key))) + (should (string= "abcdefghij" (decode encoded key))))) + + +(ert-deftest key-is-made-only-of-lowercase-letters () + (should (string-match "^[a-z]+$" (generate-key)))) + + +(ert-deftest can-encode () + (should (string= "abcdefghij" (encode "aaaaaaaaaa" "abcdefghij")))) + + +(ert-deftest can-decode () + (should (string= "aaaaaaaaaa" (decode "abcdefghij" "abcdefghij")))) + + +(ert-deftest is-reversible () + (let ((encoded (encode "abcdefghij" "abcdefghij"))) + (should (string= "abcdefghij" (decode encoded "abcdefghij"))))) + + +(ert-deftest can-double-shift-encode () + (should + (string= + "qayaeaagaciai" (encode "iamapandabear" "iamapandabear")))) + + +(ert-deftest can-wrap-on-encode () + (should (string= "zabcdefghi" (encode "zzzzzzzzzz" "abcdefghij")))) + + +(ert-deftest can-wrap-on-decode () + (should (string= "zzzzzzzzzz" (decode "zabcdefghi" "abcdefghij")))) + + +(ert-deftest can-encode-messages-longer-than-the-key () + (should (string= "iboaqcnecbfcr" (encode "iamapandabear" "abc")))) + + +(ert-deftest can-decode-messages-longer-than-the-key () + (should (string= "iamapandabear" (decode "iboaqcnecbfcr" "abc")))) + + +(provide 'simple-cipher-test) +;;; simple-cipher-test.el ends here diff --git a/exercises/practice/simple-cipher/simple-cipher.el b/exercises/practice/simple-cipher/simple-cipher.el new file mode 100644 index 00000000..b38942db --- /dev/null +++ b/exercises/practice/simple-cipher/simple-cipher.el @@ -0,0 +1,22 @@ +;;; simple-cipher.el --- Simple Cipher (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun encode (plaintext key) + (error + "Delete this S-Expression and write your own implementation")) + +(defun decode (ciphertext key) + (error + "Delete this S-Expression and write your own implementation")) + +(defun generate-key () + (error + "Delete this S-Expression and write your own implementation")) + + +(provide 'simple-cipher) +;;; simple-cipher.el ends here From 4dcec0f5aa7a13fe7d9243bff009226a278356a7 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Fri, 19 May 2023 10:30:30 +0200 Subject: [PATCH 023/162] Add rotational-cipher practice exercise (#301) Co-authored-by: Erik Schierboom --------- Co-authored-by: Erik Schierboom --- config.json | 8 +++ .../rotational-cipher/.docs/instructions.md | 29 +++++++++ .../rotational-cipher/.meta/config.json | 19 ++++++ .../rotational-cipher/.meta/example.el | 25 ++++++++ .../rotational-cipher/.meta/tests.toml | 40 +++++++++++++ .../rotational-cipher-test.el | 60 +++++++++++++++++++ .../rotational-cipher/rotational-cipher.el | 14 +++++ 7 files changed, 195 insertions(+) create mode 100644 exercises/practice/rotational-cipher/.docs/instructions.md create mode 100644 exercises/practice/rotational-cipher/.meta/config.json create mode 100644 exercises/practice/rotational-cipher/.meta/example.el create mode 100644 exercises/practice/rotational-cipher/.meta/tests.toml create mode 100644 exercises/practice/rotational-cipher/rotational-cipher-test.el create mode 100644 exercises/practice/rotational-cipher/rotational-cipher.el diff --git a/config.json b/config.json index 5faa5297..aa3760d2 100644 --- a/config.json +++ b/config.json @@ -446,6 +446,14 @@ "prerequisites": [], "difficulty": 1 }, + { + "slug": "rotational-cipher", + "name": "Rotational Cipher", + "uuid": "4faa2bae-ecda-4c16-9f6d-148793117995", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "simple-cipher", "name": "Simple Cipher", diff --git a/exercises/practice/rotational-cipher/.docs/instructions.md b/exercises/practice/rotational-cipher/.docs/instructions.md new file mode 100644 index 00000000..4dee51b3 --- /dev/null +++ b/exercises/practice/rotational-cipher/.docs/instructions.md @@ -0,0 +1,29 @@ +# Instructions + +Create an implementation of the rotational cipher, also sometimes called the Caesar cipher. + +The Caesar cipher is a simple shift cipher that relies on transposing all the letters in the alphabet using an integer key between `0` and `26`. +Using a key of `0` or `26` will always yield the same output due to modular arithmetic. +The letter is shifted for as many values as the value of the key. + +The general notation for rotational ciphers is `ROT + `. +The most commonly used rotational cipher is `ROT13`. + +A `ROT13` on the Latin alphabet would be as follows: + +```text +Plain: abcdefghijklmnopqrstuvwxyz +Cipher: nopqrstuvwxyzabcdefghijklm +``` + +It is stronger than the Atbash cipher because it has 27 possible keys, and 25 usable keys. + +Ciphertext is written out in the same formatting as the input including spaces and punctuation. + +## Examples + +- ROT5 `omg` gives `trl` +- ROT0 `c` gives `c` +- ROT26 `Cool` gives `Cool` +- ROT13 `The quick brown fox jumps over the lazy dog.` gives `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` +- ROT13 `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` gives `The quick brown fox jumps over the lazy dog.` diff --git a/exercises/practice/rotational-cipher/.meta/config.json b/exercises/practice/rotational-cipher/.meta/config.json new file mode 100644 index 00000000..bf003b29 --- /dev/null +++ b/exercises/practice/rotational-cipher/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "fapdash" + ], + "files": { + "solution": [ + "rotational-cipher.el" + ], + "test": [ + "rotational-cipher-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Create an implementation of the rotational cipher, also sometimes called the Caesar cipher.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Caesar_cipher" +} diff --git a/exercises/practice/rotational-cipher/.meta/example.el b/exercises/practice/rotational-cipher/.meta/example.el new file mode 100644 index 00000000..2e8e1894 --- /dev/null +++ b/exercises/practice/rotational-cipher/.meta/example.el @@ -0,0 +1,25 @@ +;;; rotational-cipher.el --- Rotational Cipher (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(defconst shift-max 26) + +(defun rotate (text shift-key) + (let ((normalized-shift-key (mod shift-key shift-max))) + (concat + (mapcar + (lambda (char) + (cond + ((<= ?A char ?Z) + (+ (mod (+ (- char ?A) normalized-shift-key) shift-max) ?A)) + ((<= ?a char ?z) + (+ (mod (+ (- char ?a) normalized-shift-key) shift-max) ?a)) + (t + char))) + text)))) + + +(provide 'rotational-cipher) +;;; rotational-cipher.el ends here diff --git a/exercises/practice/rotational-cipher/.meta/tests.toml b/exercises/practice/rotational-cipher/.meta/tests.toml new file mode 100644 index 00000000..53441ed2 --- /dev/null +++ b/exercises/practice/rotational-cipher/.meta/tests.toml @@ -0,0 +1,40 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[74e58a38-e484-43f1-9466-877a7515e10f] +description = "rotate a by 0, same output as input" + +[7ee352c6-e6b0-4930-b903-d09943ecb8f5] +description = "rotate a by 1" + +[edf0a733-4231-4594-a5ee-46a4009ad764] +description = "rotate a by 26, same output as input" + +[e3e82cb9-2a5b-403f-9931-e43213879300] +description = "rotate m by 13" + +[19f9eb78-e2ad-4da4-8fe3-9291d47c1709] +description = "rotate n by 13 with wrap around alphabet" + +[a116aef4-225b-4da9-884f-e8023ca6408a] +description = "rotate capital letters" + +[71b541bb-819c-4dc6-a9c3-132ef9bb737b] +description = "rotate spaces" + +[ef32601d-e9ef-4b29-b2b5-8971392282e6] +description = "rotate numbers" + +[32dd74f6-db2b-41a6-b02c-82eb4f93e549] +description = "rotate punctuation" + +[9fb93fe6-42b0-46e6-9ec1-0bf0a062d8c9] +description = "rotate all letters" diff --git a/exercises/practice/rotational-cipher/rotational-cipher-test.el b/exercises/practice/rotational-cipher/rotational-cipher-test.el new file mode 100644 index 00000000..854e4b81 --- /dev/null +++ b/exercises/practice/rotational-cipher/rotational-cipher-test.el @@ -0,0 +1,60 @@ +;;; rotational-cipher-test.el --- Rotational Cipher (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "rotational-cipher.el") +(declare-function rotate "rotational-cipher.el" (text shift-key)) + + +(ert-deftest rotate-a-by-0-same-output-as-input () + (should (string= (rotate "a" 0) "a"))) + + +(ert-deftest rotate-a-by-1 () + (should (string= (rotate "a" 1) "b"))) + + +(ert-deftest rotate-a-by-26-same-output-as-input () + (should (string= (rotate "a" 26) "a"))) + + +(ert-deftest rotate-m-by-13 () + (should (string= (rotate "m" 13) "z"))) + + +(ert-deftest rotate-n-by-13-with-wrap-around-alphabet () + (should (string= (rotate "n" 13) "a"))) + + +(ert-deftest rotate-capital-letters () + (should (string= (rotate "OMG" 5) "TRL"))) + + +(ert-deftest rotate-spaces () + (should (string= (rotate "O M G" 5) "T R L"))) + + +(ert-deftest rotate-numbers () + (should + (string= + (rotate "Testing 1 2 3 testing" 4) "Xiwxmrk 1 2 3 xiwxmrk"))) + + +(ert-deftest rotate-punctuation () + (should + (string= (rotate "Let's eat, Grandma!" 21) "Gzo'n zvo, Bmviyhv!"))) + + +(ert-deftest rotate-all-letters () + (should + (string= + (rotate + "The quick brown fox jumps over the lazy dog." 13) + "Gur dhvpx oebja sbk whzcf bire gur ynml qbt."))) + + +(provide 'rotational-cipher-test) +;;; rotational-cipher-test.el ends here diff --git a/exercises/practice/rotational-cipher/rotational-cipher.el b/exercises/practice/rotational-cipher/rotational-cipher.el new file mode 100644 index 00000000..dd0df423 --- /dev/null +++ b/exercises/practice/rotational-cipher/rotational-cipher.el @@ -0,0 +1,14 @@ +;;; rotational-cipher.el --- Rotational Cipher (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun rotate (text shift-key) + (error + "Delete this S-Expression and write your own implementation")) + + +(provide 'rotational-cipher) +;;; rotational-cipher.el ends here From 54b0dfc2f93ee675d4e1a27321c8baa234297323 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Fri, 19 May 2023 10:35:30 +0200 Subject: [PATCH 024/162] Add rail-fence-cipher practice exercise (#303) Co-authored-by: Erik Schierboom --------- Co-authored-by: Erik Schierboom --- config.json | 8 +++ .../rail-fence-cipher/.docs/instructions.md | 57 ++++++++++++++++ .../rail-fence-cipher/.meta/config.json | 19 ++++++ .../rail-fence-cipher/.meta/example.el | 67 +++++++++++++++++++ .../rail-fence-cipher/.meta/tests.toml | 28 ++++++++ .../rail-fence-cipher-test.el | 49 ++++++++++++++ .../rail-fence-cipher/rail-fence-cipher.el | 18 +++++ 7 files changed, 246 insertions(+) create mode 100644 exercises/practice/rail-fence-cipher/.docs/instructions.md create mode 100644 exercises/practice/rail-fence-cipher/.meta/config.json create mode 100644 exercises/practice/rail-fence-cipher/.meta/example.el create mode 100644 exercises/practice/rail-fence-cipher/.meta/tests.toml create mode 100644 exercises/practice/rail-fence-cipher/rail-fence-cipher-test.el create mode 100644 exercises/practice/rail-fence-cipher/rail-fence-cipher.el diff --git a/config.json b/config.json index aa3760d2..9321cc0b 100644 --- a/config.json +++ b/config.json @@ -469,6 +469,14 @@ "practices": [], "prerequisites": [], "difficulty": 4 + }, + { + "slug": "rail-fence-cipher", + "name": "Rail Fence Cipher", + "uuid": "bcd4671e-4fb9-4abb-af98-315fc83daa52", + "practices": [], + "prerequisites": [], + "difficulty": 4 } ] }, diff --git a/exercises/practice/rail-fence-cipher/.docs/instructions.md b/exercises/practice/rail-fence-cipher/.docs/instructions.md new file mode 100644 index 00000000..e311de6c --- /dev/null +++ b/exercises/practice/rail-fence-cipher/.docs/instructions.md @@ -0,0 +1,57 @@ +# Instructions + +Implement encoding and decoding for the rail fence cipher. + +The Rail Fence cipher is a form of transposition cipher that gets its name from the way in which it's encoded. +It was already used by the ancient Greeks. + +In the Rail Fence cipher, the message is written downwards on successive "rails" of an imaginary fence, then moving up when we get to the bottom (like a zig-zag). +Finally the message is then read off in rows. + +For example, using three "rails" and the message "WE ARE DISCOVERED FLEE AT ONCE", the cipherer writes out: + +```text +W . . . E . . . C . . . R . . . L . . . T . . . E +. E . R . D . S . O . E . E . F . E . A . O . C . +. . A . . . I . . . V . . . D . . . E . . . N . . +``` + +Then reads off: + +```text +WECRLTEERDSOEEFEAOCAIVDEN +``` + +To decrypt a message you take the zig-zag shape and fill the ciphertext along the rows. + +```text +? . . . ? . . . ? . . . ? . . . ? . . . ? . . . ? +. ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . +. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . . +``` + +The first row has seven spots that can be filled with "WECRLTE". + +```text +W . . . E . . . C . . . R . . . L . . . T . . . E +. ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . +. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . . +``` + +Now the 2nd row takes "ERDSOEEFEAOC". + +```text +W . . . E . . . C . . . R . . . L . . . T . . . E +. E . R . D . S . O . E . E . F . E . A . O . C . +. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . . +``` + +Leaving "AIVDEN" for the last row. + +```text +W . . . E . . . C . . . R . . . L . . . T . . . E +. E . R . D . S . O . E . E . F . E . A . O . C . +. . A . . . I . . . V . . . D . . . E . . . N . . +``` + +If you now read along the zig-zag shape you can read the original message. diff --git a/exercises/practice/rail-fence-cipher/.meta/config.json b/exercises/practice/rail-fence-cipher/.meta/config.json new file mode 100644 index 00000000..e8e48811 --- /dev/null +++ b/exercises/practice/rail-fence-cipher/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "fapdash" + ], + "files": { + "solution": [ + "rail-fence-cipher.el" + ], + "test": [ + "rail-fence-cipher-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Implement encoding and decoding for the rail fence cipher.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Transposition_cipher#Rail_Fence_cipher" +} diff --git a/exercises/practice/rail-fence-cipher/.meta/example.el b/exercises/practice/rail-fence-cipher/.meta/example.el new file mode 100644 index 00000000..83e345dd --- /dev/null +++ b/exercises/practice/rail-fence-cipher/.meta/example.el @@ -0,0 +1,67 @@ +;;; rail-fence-cipher.el --- Rail Fence Cipher (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(require 'seq) +(require 'cl-lib) + +(defun encode (message rails) + (let ((rail-list (make-list rails "")) + (index 0) + (direction 'down)) + (seq-do + (lambda (char) + (setf (nth index rail-list) + (concat (char-to-string char) (nth index rail-list))) + (cond + ((>= index (1- rails)) + (setq direction 'down)) + ((<= index 0) + (setq direction 'up))) + (if (equal direction 'up) + (cl-incf index) + (cl-decf index))) + message) + (mapconcat 'nreverse rail-list ""))) + +(defun decode (message rails) + (let* ((message-length (length message)) + (cycle-length (* 2 (1- rails))) + (cycles (/ message-length cycle-length)) + (decoded (make-vector message-length nil))) + ;; format: off + (cl-loop + for rail-index below rails + with message-index = -1 + with decoded-index + do + (cl-loop + for cycle-index upto cycles + do (setf decoded-index (+ rail-index (* cycle-index cycle-length))) + while (< decoded-index message-length) + do + (setf (elt decoded decoded-index) + (elt message (cl-incf message-index))) + and + if (is-middle-rail rail-index rails) + ;; middle rails consume two characters per cycle + do + (setf decoded-index + (+ (- cycle-length rail-index) (* cycle-index cycle-length))) + and + if (< decoded-index message-length) + do + (setf (elt decoded decoded-index) + (elt message (cl-incf message-index))))) + ;; format: on + (seq-into decoded 'string))) + +(defun is-middle-rail (rail-index rails) + (< 0 rail-index (1- rails))) + + +(provide 'rail-fence-cipher) +;;; rail-fence-cipher.el ends here diff --git a/exercises/practice/rail-fence-cipher/.meta/tests.toml b/exercises/practice/rail-fence-cipher/.meta/tests.toml new file mode 100644 index 00000000..dfc5e16b --- /dev/null +++ b/exercises/practice/rail-fence-cipher/.meta/tests.toml @@ -0,0 +1,28 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[46dc5c50-5538-401d-93a5-41102680d068] +description = "encode -> encode with two rails" + +[25691697-fbd8-4278-8c38-b84068b7bc29] +description = "encode -> encode with three rails" + +[384f0fea-1442-4f1a-a7c4-5cbc2044002c] +description = "encode -> encode with ending in the middle" + +[cd525b17-ec34-45ef-8f0e-4f27c24a7127] +description = "decode -> decode with three rails" + +[dd7b4a98-1a52-4e5c-9499-cbb117833507] +description = "decode -> decode with five rails" + +[93e1ecf4-fac9-45d9-9cd2-591f47d3b8d3] +description = "decode -> decode with six rails" diff --git a/exercises/practice/rail-fence-cipher/rail-fence-cipher-test.el b/exercises/practice/rail-fence-cipher/rail-fence-cipher-test.el new file mode 100644 index 00000000..6086adb7 --- /dev/null +++ b/exercises/practice/rail-fence-cipher/rail-fence-cipher-test.el @@ -0,0 +1,49 @@ +;;; rail-fence-cipher-test.el --- Rail Fence Cipher (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "rail-fence-cipher.el") +(declare-function encode "rail-fence-cipher.el" (message rails)) +(declare-function decode "rail-fence-cipher.el" (message rails)) + + +(ert-deftest encode-with-two-rails () + (should + (string= (encode "XOXOXOXOXOXOXOXOXO" 2) "XXXXXXXXXOOOOOOOOO"))) + + +(ert-deftest encode-with-three-rails () + (should + (string= + (encode "WEAREDISCOVEREDFLEEATONCE" 3) + "WECRLTEERDSOEEFEAOCAIVDEN"))) + + +(ert-deftest encode-with-ending-in-the-middle () + (should (string= (encode "EXERCISES" 4) "ESXIEECSR"))) + + +(ert-deftest decode-with-three-rails () + (should + (string= + (decode "TEITELHDVLSNHDTISEIIEA" 3) "THEDEVILISINTHEDETAILS"))) + + +(ert-deftest decode-with-five-rails () + (should + (string= (decode "EIEXMSMESAORIWSCE" 5) "EXERCISMISAWESOME"))) + + +(ert-deftest decode-with-six-rails () + (should + (string= + (decode + "133714114238148966225439541018335470986172518171757571896261" 6) + "112358132134558914423337761098715972584418167651094617711286"))) + + +(provide 'rail-fence-cipher-test) +;;; rail-fence-cipher-test.el ends here diff --git a/exercises/practice/rail-fence-cipher/rail-fence-cipher.el b/exercises/practice/rail-fence-cipher/rail-fence-cipher.el new file mode 100644 index 00000000..cfdc87d9 --- /dev/null +++ b/exercises/practice/rail-fence-cipher/rail-fence-cipher.el @@ -0,0 +1,18 @@ +;;; rail-fence-cipher.el --- Rail Fence Cipher (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun encode (message rails) + (error + "Delete this S-Expression and write your own implementation")) + +(defun decode (message rails) + (error + "Delete this S-Expression and write your own implementation")) + + +(provide 'rail-fence-cipher) +;;; rail-fence-cipher.el ends here From 02348db1967d8320d41bd350940f3bb54c3c37bc Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Fri, 19 May 2023 10:38:35 +0200 Subject: [PATCH 025/162] Add matching-brackets practice exercise (#304) Co-authored-by: Erik Schierboom --------- Co-authored-by: Erik Schierboom --- config.json | 8 ++ .../matching-brackets/.docs/instructions.md | 4 + .../matching-brackets/.meta/config.json | 18 ++++ .../matching-brackets/.meta/example.el | 43 ++++++++ .../matching-brackets/.meta/tests.toml | 70 +++++++++++++ .../matching-brackets-test.el | 97 +++++++++++++++++++ .../matching-brackets/matching-brackets.el | 14 +++ 7 files changed, 254 insertions(+) create mode 100644 exercises/practice/matching-brackets/.docs/instructions.md create mode 100644 exercises/practice/matching-brackets/.meta/config.json create mode 100644 exercises/practice/matching-brackets/.meta/example.el create mode 100644 exercises/practice/matching-brackets/.meta/tests.toml create mode 100644 exercises/practice/matching-brackets/matching-brackets-test.el create mode 100644 exercises/practice/matching-brackets/matching-brackets.el diff --git a/config.json b/config.json index 9321cc0b..f4da6d4c 100644 --- a/config.json +++ b/config.json @@ -477,6 +477,14 @@ "practices": [], "prerequisites": [], "difficulty": 4 + }, + { + "slug": "matching-brackets", + "name": "Matching Brackets", + "uuid": "c000a3e1-3488-41ba-9d4c-6f06a96bc892", + "practices": [], + "prerequisites": [], + "difficulty": 3 } ] }, diff --git a/exercises/practice/matching-brackets/.docs/instructions.md b/exercises/practice/matching-brackets/.docs/instructions.md new file mode 100644 index 00000000..544daa96 --- /dev/null +++ b/exercises/practice/matching-brackets/.docs/instructions.md @@ -0,0 +1,4 @@ +# Instructions + +Given a string containing brackets `[]`, braces `{}`, parentheses `()`, or any combination thereof, verify that any and all pairs are matched and nested correctly. +The string may also contain other characters, which for the purposes of this exercise should be ignored. diff --git a/exercises/practice/matching-brackets/.meta/config.json b/exercises/practice/matching-brackets/.meta/config.json new file mode 100644 index 00000000..c33a2fd3 --- /dev/null +++ b/exercises/practice/matching-brackets/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "fapdash" + ], + "files": { + "solution": [ + "matching-brackets.el" + ], + "test": [ + "matching-brackets-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Make sure the brackets and braces all match.", + "source": "Ginna Baker" +} diff --git a/exercises/practice/matching-brackets/.meta/example.el b/exercises/practice/matching-brackets/.meta/example.el new file mode 100644 index 00000000..8911d25a --- /dev/null +++ b/exercises/practice/matching-brackets/.meta/example.el @@ -0,0 +1,43 @@ +;;; matching-brackets.el --- Matching Brackets (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(require 'seq) + +(defun is-paired (value) + (let ((brackets '())) + (and + (seq-every-p + (lambda (char) + (cond + ((= char ?\() + (push ?\) brackets)) + ((= char ?\[) + (push ?\] brackets)) + ((= char ?{) + (push ?} brackets)) + ((= char ?\)) + ;; need to use equal because = doesn't accept nil + (if (equal (car brackets) ?\)) + ;; make sure return is true when brackets gets set to nil / empty list + (or (setq brackets (cdr brackets)) t) + nil)) + ((= char ?\]) + (if (equal (car brackets) ?\]) + (or (setq brackets (cdr brackets)) t) + nil)) + ((= char ?}) + (if (equal (car brackets) ?}) + (or (setq brackets (cdr brackets)) t) + nil)) + (t + t))) + value) + (seq-empty-p brackets)))) + + +(provide 'matching-brackets) +;;; matching-brackets.el ends here diff --git a/exercises/practice/matching-brackets/.meta/tests.toml b/exercises/practice/matching-brackets/.meta/tests.toml new file mode 100644 index 00000000..35a98a04 --- /dev/null +++ b/exercises/practice/matching-brackets/.meta/tests.toml @@ -0,0 +1,70 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[81ec11da-38dd-442a-bcf9-3de7754609a5] +description = "paired square brackets" + +[287f0167-ac60-4b64-8452-a0aa8f4e5238] +description = "empty string" + +[6c3615a3-df01-4130-a731-8ef5f5d78dac] +description = "unpaired brackets" + +[9d414171-9b98-4cac-a4e5-941039a97a77] +description = "wrong ordered brackets" + +[f0f97c94-a149-4736-bc61-f2c5148ffb85] +description = "wrong closing bracket" + +[754468e0-4696-4582-a30e-534d47d69756] +description = "paired with whitespace" + +[ba84f6ee-8164-434a-9c3e-b02c7f8e8545] +description = "partially paired brackets" + +[3c86c897-5ff3-4a2b-ad9b-47ac3a30651d] +description = "simple nested brackets" + +[2d137f2c-a19e-4993-9830-83967a2d4726] +description = "several paired brackets" + +[2e1f7b56-c137-4c92-9781-958638885a44] +description = "paired and nested brackets" + +[84f6233b-e0f7-4077-8966-8085d295c19b] +description = "unopened closing brackets" + +[9b18c67d-7595-4982-b2c5-4cb949745d49] +description = "unpaired and nested brackets" + +[a0205e34-c2ac-49e6-a88a-899508d7d68e] +description = "paired and wrong nested brackets" + +[1d5c093f-fc84-41fb-8c2a-e052f9581602] +description = "paired and wrong nested brackets but innermost are correct" + +[ef47c21b-bcfd-4998-844c-7ad5daad90a8] +description = "paired and incomplete brackets" + +[a4675a40-a8be-4fc2-bc47-2a282ce6edbe] +description = "too many closing brackets" + +[a345a753-d889-4b7e-99ae-34ac85910d1a] +description = "early unexpected brackets" + +[21f81d61-1608-465a-b850-baa44c5def83] +description = "early mismatched brackets" + +[99255f93-261b-4435-a352-02bdecc9bdf2] +description = "math expression" + +[8e357d79-f302-469a-8515-2561877256a1] +description = "complex latex expression" diff --git a/exercises/practice/matching-brackets/matching-brackets-test.el b/exercises/practice/matching-brackets/matching-brackets-test.el new file mode 100644 index 00000000..2d94d4a5 --- /dev/null +++ b/exercises/practice/matching-brackets/matching-brackets-test.el @@ -0,0 +1,97 @@ +;;; matching-brackets-test.el --- Matching Brackets (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "matching-brackets.el") +(declare-function is-paired "matching-brackets.el" (value)) + + +(ert-deftest paired-square-brackets () + (should (is-paired "[]"))) + + +(ert-deftest empty-string () + (should (is-paired "[]"))) + + +(ert-deftest unpaired-brackets () + (should (not (is-paired "[[")))) + + +(ert-deftest wrong-ordered-brackets () + (should (not (is-paired "}{")))) + + +(ert-deftest wrong-closing-bracket () + (should (not (is-paired "{]")))) + + +(ert-deftest paired-with-whitespace () + (should (is-paired "{ }"))) + + +(ert-deftest partially-paired-brackets () + (should (not (is-paired "{[])")))) + + +(ert-deftest simple-nested-brackets () + (should (is-paired "{[]}"))) + + +(ert-deftest several-paired-brackets () + (should (is-paired "{}[]"))) + + +(ert-deftest paired-and-nested-brackets () + (should (is-paired "[{}({}[])]"))) + + +(ert-deftest unopened-closing-brackets () + (should (not (is-paired "{[)][]}")))) + + +(ert-deftest unpaired-and-nested-brackets () + (should (not (is-paired "({])")))) + + +(ert-deftest paired-and-wrong-nested-brackets () + (should (not (is-paired "[({]})")))) + + +(ert-deftest + paired-and-wrong-nested-brackets-but-innermost-are-correct + () + (should (not (is-paired "[({}])")))) + + +(ert-deftest paired-and-incomplete-brackets () + (should (not (is-paired "{}[")))) + + +(ert-deftest too-many-closing-brackets () + (should (not (is-paired "[]]")))) + + +(ert-deftest early-unexpected-brackets () + (should (not (is-paired ")()")))) + + +(ert-deftest early-mismatched-brackets () + (should (not (is-paired "{)()")))) + + +(ert-deftest math-expression () + (should (is-paired "(((185 + 223.85) * 15) - 543)/2"))) + + +(ert-deftest complex-latex-expression () + (should + (is-paired + "\\left(\\begin{array}{cc} \\frac{1}{3} & x\\\\ \\mathrm{e}^{x} &... x^2 \\end{array}\\right)"))) + + +(provide 'matching-brackets-test) +;;; matching-brackets-test.el ends here diff --git a/exercises/practice/matching-brackets/matching-brackets.el b/exercises/practice/matching-brackets/matching-brackets.el new file mode 100644 index 00000000..a9ba2438 --- /dev/null +++ b/exercises/practice/matching-brackets/matching-brackets.el @@ -0,0 +1,14 @@ +;;; matching-brackets.el --- Matching Brackets (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun is-paired (value) + (error + "Delete this S-Expression and write your own implementation")) + + +(provide 'matching-brackets) +;;; matching-brackets.el ends here From e924efa1be859680e55b1f4850fec86f784b2318 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Fri, 19 May 2023 10:40:45 +0200 Subject: [PATCH 026/162] Use GitHub username instead of Exercism username in config.json (#306) --- exercises/practice/darts/.meta/config.json | 2 +- exercises/practice/word-count/.meta/config.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/practice/darts/.meta/config.json b/exercises/practice/darts/.meta/config.json index fc17e154..bc583451 100644 --- a/exercises/practice/darts/.meta/config.json +++ b/exercises/practice/darts/.meta/config.json @@ -1,6 +1,6 @@ { "authors": [ - "fap" + "fapdash" ], "files": { "solution": [ diff --git a/exercises/practice/word-count/.meta/config.json b/exercises/practice/word-count/.meta/config.json index d15a2f59..b66c3c7c 100644 --- a/exercises/practice/word-count/.meta/config.json +++ b/exercises/practice/word-count/.meta/config.json @@ -6,7 +6,7 @@ "vermiculus", "wasamasa", "yurrriq", - "fap" + "fapdash" ], "files": { "solution": [ From afa62f7a81a810336050c65e41f4a79d4983f690 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Fri, 19 May 2023 10:41:05 +0200 Subject: [PATCH 027/162] Add queen-attack practice exercise (#305) --- config.json | 8 +++ .../queen-attack/.docs/instructions.md | 25 +++++++ .../practice/queen-attack/.meta/config.json | 19 +++++ .../practice/queen-attack/.meta/example.el | 23 +++++++ .../queen-attack/queen-attack-test.el | 69 +++++++++++++++++++ .../practice/queen-attack/queen-attack.el | 18 +++++ 6 files changed, 162 insertions(+) create mode 100644 exercises/practice/queen-attack/.docs/instructions.md create mode 100644 exercises/practice/queen-attack/.meta/config.json create mode 100644 exercises/practice/queen-attack/.meta/example.el create mode 100644 exercises/practice/queen-attack/queen-attack-test.el create mode 100644 exercises/practice/queen-attack/queen-attack.el diff --git a/config.json b/config.json index f4da6d4c..f5199737 100644 --- a/config.json +++ b/config.json @@ -485,6 +485,14 @@ "practices": [], "prerequisites": [], "difficulty": 3 + }, + { + "slug": "queen-attack", + "name": "Queen Attack", + "uuid": "bfa1d997-f0bd-432b-aa29-7018607d772d", + "practices": [], + "prerequisites": [], + "difficulty": 2 } ] }, diff --git a/exercises/practice/queen-attack/.docs/instructions.md b/exercises/practice/queen-attack/.docs/instructions.md new file mode 100644 index 00000000..ad7ea954 --- /dev/null +++ b/exercises/practice/queen-attack/.docs/instructions.md @@ -0,0 +1,25 @@ +# Instructions + +Given the position of two queens on a chess board, indicate whether or not they are positioned so that they can attack each other. + +In the game of chess, a queen can attack pieces which are on the same row, column, or diagonal. + +A chessboard can be represented by an 8 by 8 array. + +So if you are told the white queen is at `c5` (zero-indexed at column 2, row 3) and the black queen at `f2` (zero-indexed at column 5, row 6), then you know that the set-up is like so: + +```text + a b c d e f g h +8 _ _ _ _ _ _ _ _ 8 +7 _ _ _ _ _ _ _ _ 7 +6 _ _ _ _ _ _ _ _ 6 +5 _ _ W _ _ _ _ _ 5 +4 _ _ _ _ _ _ _ _ 4 +3 _ _ _ _ _ _ _ _ 3 +2 _ _ _ _ _ B _ _ 2 +1 _ _ _ _ _ _ _ _ 1 + a b c d e f g h +``` + +You are also able to answer whether the queens can attack each other. +In this case, that answer would be yes, they can, because both pieces share a diagonal. diff --git a/exercises/practice/queen-attack/.meta/config.json b/exercises/practice/queen-attack/.meta/config.json new file mode 100644 index 00000000..442addae --- /dev/null +++ b/exercises/practice/queen-attack/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "fapdash" + ], + "files": { + "solution": [ + "queen-attack.el" + ], + "test": [ + "queen-attack-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given the position of two queens on a chess board, indicate whether or not they are positioned so that they can attack each other.", + "source": "J Dalbey's Programming Practice problems", + "source_url": "https://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html" +} diff --git a/exercises/practice/queen-attack/.meta/example.el b/exercises/practice/queen-attack/.meta/example.el new file mode 100644 index 00000000..2f31b58f --- /dev/null +++ b/exercises/practice/queen-attack/.meta/example.el @@ -0,0 +1,23 @@ +;;; queen-attack.el --- Queen Attack (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun valid-position-p (queen) + (and (<= 0 (car queen) 7) (<= 0 (cdr queen) 7))) + +(defun can-attack-p (white-queen black-queen) + (let ((row-white (car white-queen)) + (column-white (cdr white-queen)) + (row-black (car black-queen)) + (column-black (cdr black-queen))) + (or (= row-white row-black) + (= column-white column-black) + (= (- row-white column-white) (- row-black column-black)) + (= (+ row-white column-white) (+ row-black column-black))))) + + +(provide 'queen-attack) +;;; queen-attack.el ends here diff --git a/exercises/practice/queen-attack/queen-attack-test.el b/exercises/practice/queen-attack/queen-attack-test.el new file mode 100644 index 00000000..4f15b34b --- /dev/null +++ b/exercises/practice/queen-attack/queen-attack-test.el @@ -0,0 +1,69 @@ +;;; queen-attack-test.el --- Queen Attack (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "queen-attack.el") +(declare-function valid-position-p "queen-attack.el" (queen)) +(declare-function can-attack-p "queen-attack.el" + (white-queen black-queen)) + + +(ert-deftest queen-with-a-valid-position () + (should (valid-position-p '(2 . 2)))) + + +(ert-deftest queen-must-have-positive-row () + (should (not (valid-position-p '(-2 . 2))))) + + +(ert-deftest queen-must-have-row-on-board () + (should (not (valid-position-p '(8 . 4))))) + + +(ert-deftest queen-must-have-positive-column () + (should (not (valid-position-p '(2 . -2))))) + + +(ert-deftest queen-must-have-column-on-board () + (should (not (valid-position-p '(4 . 8))))) + + +(ert-deftest cannot-attack () + (should (not (can-attack-p '(2 . 4) '(6 . 6))))) + + +(ert-deftest can-attack-on-same-row () + (should (can-attack-p '(2 . 4) '(2 . 6)))) + + +(ert-deftest can-attack-on-same-column () + (should (can-attack-p '(4 . 5) '(2 . 5)))) + + +(ert-deftest can-attack-on-first-diagonal () + (should (can-attack-p '(2 . 2) '(0 . 4)))) + + +(ert-deftest can-attack-on-second-diagonal () + (should (can-attack-p '(2 . 2) '(3 . 1)))) + + +(ert-deftest can-attack-on-third-diagonal () + (should (can-attack-p '(2 . 2) '(1 . 1)))) + + +(ert-deftest can-attack-on-fourth-diagonal () + (should (can-attack-p '(1 . 7) '(0 . 6)))) + + +(ert-deftest + cannot-attack-if-falling-diagonals-are-only-the-same-when-reflected-across-the-longest-falling-diagonal + () + (should (not (can-attack-p '(4 . 1) '(2 . 5))))) + + +(provide 'queen-attack-test) +;;; queen-attack-test.el ends here diff --git a/exercises/practice/queen-attack/queen-attack.el b/exercises/practice/queen-attack/queen-attack.el new file mode 100644 index 00000000..26cff306 --- /dev/null +++ b/exercises/practice/queen-attack/queen-attack.el @@ -0,0 +1,18 @@ +;;; queen-attack.el --- Queen Attack (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun valid-position-p (queen) + (error + "Delete this S-Expression and write your own implementation")) + +(defun can-attack-p (white-queen black-queen) + (error + "Delete this S-Expression and write your own implementation")) + + +(provide 'queen-attack) +;;; queen-attack.el ends here From 2fb516731084c6ebf484111bc983e472aff58274 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Wed, 24 May 2023 00:45:09 +0200 Subject: [PATCH 028/162] Add reverse-string practice exercise (#307) The canonical data defines the function to implement as `reverse` but it got changed to `reverse-string` so Emacs users don't overwrite the built in `reverse` function while doing REPL driven programming. --- config.json | 8 ++++ .../reverse-string/.docs/instructions.md | 7 ++++ .../practice/reverse-string/.meta/config.json | 19 ++++++++++ .../practice/reverse-string/.meta/example.el | 13 +++++++ .../practice/reverse-string/.meta/tests.toml | 28 ++++++++++++++ .../reverse-string/reverse-string-test.el | 37 +++++++++++++++++++ .../practice/reverse-string/reverse-string.el | 14 +++++++ 7 files changed, 126 insertions(+) create mode 100644 exercises/practice/reverse-string/.docs/instructions.md create mode 100644 exercises/practice/reverse-string/.meta/config.json create mode 100644 exercises/practice/reverse-string/.meta/example.el create mode 100644 exercises/practice/reverse-string/.meta/tests.toml create mode 100644 exercises/practice/reverse-string/reverse-string-test.el create mode 100644 exercises/practice/reverse-string/reverse-string.el diff --git a/config.json b/config.json index f5199737..1dd0e141 100644 --- a/config.json +++ b/config.json @@ -493,6 +493,14 @@ "practices": [], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "reverse-string", + "name": "Reverse String", + "uuid": "59c6319b-2799-4e4c-bef1-e28626878446", + "practices": [], + "prerequisites": [], + "difficulty": 1 } ] }, diff --git a/exercises/practice/reverse-string/.docs/instructions.md b/exercises/practice/reverse-string/.docs/instructions.md new file mode 100644 index 00000000..039ee33a --- /dev/null +++ b/exercises/practice/reverse-string/.docs/instructions.md @@ -0,0 +1,7 @@ +# Instructions + +Reverse a string + +For example: +input: "cool" +output: "looc" diff --git a/exercises/practice/reverse-string/.meta/config.json b/exercises/practice/reverse-string/.meta/config.json new file mode 100644 index 00000000..2fffa5fc --- /dev/null +++ b/exercises/practice/reverse-string/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "fapdash" + ], + "files": { + "solution": [ + "reverse-string.el" + ], + "test": [ + "reverse-string-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Reverse a string.", + "source": "Introductory challenge to reverse an input string", + "source_url": "https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb" +} diff --git a/exercises/practice/reverse-string/.meta/example.el b/exercises/practice/reverse-string/.meta/example.el new file mode 100644 index 00000000..73fab7ac --- /dev/null +++ b/exercises/practice/reverse-string/.meta/example.el @@ -0,0 +1,13 @@ +;;; reverse-string.el --- Reverse String (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun reverse-string (value) + (reverse value)) + + +(provide 'reverse-string) +;;; reverse-string.el ends here diff --git a/exercises/practice/reverse-string/.meta/tests.toml b/exercises/practice/reverse-string/.meta/tests.toml new file mode 100644 index 00000000..0b04c4cd --- /dev/null +++ b/exercises/practice/reverse-string/.meta/tests.toml @@ -0,0 +1,28 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[c3b7d806-dced-49ee-8543-933fd1719b1c] +description = "an empty string" + +[01ebf55b-bebb-414e-9dec-06f7bb0bee3c] +description = "a word" + +[0f7c07e4-efd1-4aaa-a07a-90b49ce0b746] +description = "a capitalized word" + +[71854b9c-f200-4469-9f5c-1e8e5eff5614] +description = "a sentence with punctuation" + +[1f8ed2f3-56f3-459b-8f3e-6d8d654a1f6c] +description = "a palindrome" + +[b9e7dec1-c6df-40bd-9fa3-cd7ded010c4c] +description = "an even-sized word" diff --git a/exercises/practice/reverse-string/reverse-string-test.el b/exercises/practice/reverse-string/reverse-string-test.el new file mode 100644 index 00000000..dc0535e4 --- /dev/null +++ b/exercises/practice/reverse-string/reverse-string-test.el @@ -0,0 +1,37 @@ +;;; reverse-string-test.el --- Reverse String (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "reverse-string.el") +(declare-function reverse-string "reverse-string.el" (value)) + + +(ert-deftest an-empty-string () + (should (string= (reverse-string "") ""))) + + +(ert-deftest a-word () + (should (string= (reverse-string "robot") "tobor"))) + + +(ert-deftest a-capitalized-word () + (should (string= (reverse-string "Ramen") "nemaR"))) + + +(ert-deftest a-sentence-with-punctuation () + (should (string= (reverse-string "I'm hungry!") "!yrgnuh m'I"))) + + +(ert-deftest a-palindrome () + (should (string= (reverse-string "racecar") "racecar"))) + + +(ert-deftest an-even-sized-word () + (should (string= (reverse-string "drawer") "reward"))) + + +(provide 'reverse-string-test) +;;; reverse-string-test.el ends here diff --git a/exercises/practice/reverse-string/reverse-string.el b/exercises/practice/reverse-string/reverse-string.el new file mode 100644 index 00000000..aca6ca2c --- /dev/null +++ b/exercises/practice/reverse-string/reverse-string.el @@ -0,0 +1,14 @@ +;;; reverse-string.el --- Reverse String (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun reverse-string (value) + (error + "Delete this S-Expression and write your own implementation")) + + +(provide 'reverse-string) +;;; reverse-string.el ends here From 2d5fb6c19149addd7baeaca40ecd67f0e2e57cf0 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Wed, 24 May 2023 00:48:46 +0200 Subject: [PATCH 029/162] Add flatten-array practice exercise (#308) - reverse lists instead of arrays since they are the more common data structure in Emacs Lisp - use `list-flatten` function name to make it extra clear that lists are the expected input - use `list-flatten` function name instead of `flatten-list` to avoid overwriting built-in Emacs function (alias) --- config.json | 8 ++ .../flatten-array/.docs/instructions.md | 11 +++ .../practice/flatten-array/.meta/config.json | 19 +++++ .../practice/flatten-array/.meta/example.el | 13 ++++ .../practice/flatten-array/.meta/tests.toml | 43 +++++++++++ .../flatten-array/flatten-array-test.el | 74 +++++++++++++++++++ .../practice/flatten-array/flatten-array.el | 14 ++++ 7 files changed, 182 insertions(+) create mode 100644 exercises/practice/flatten-array/.docs/instructions.md create mode 100644 exercises/practice/flatten-array/.meta/config.json create mode 100644 exercises/practice/flatten-array/.meta/example.el create mode 100644 exercises/practice/flatten-array/.meta/tests.toml create mode 100644 exercises/practice/flatten-array/flatten-array-test.el create mode 100644 exercises/practice/flatten-array/flatten-array.el diff --git a/config.json b/config.json index 1dd0e141..94f762d3 100644 --- a/config.json +++ b/config.json @@ -501,6 +501,14 @@ "practices": [], "prerequisites": [], "difficulty": 1 + }, + { + "slug": "flatten-array", + "name": "Flatten Array", + "uuid": "66f266a8-9c5c-4aad-8a27-92810b288a2b", + "practices": [], + "prerequisites": [], + "difficulty": 6 } ] }, diff --git a/exercises/practice/flatten-array/.docs/instructions.md b/exercises/practice/flatten-array/.docs/instructions.md new file mode 100644 index 00000000..51bea679 --- /dev/null +++ b/exercises/practice/flatten-array/.docs/instructions.md @@ -0,0 +1,11 @@ +# Instructions + +Take a nested list and return a single flattened list with all values except nil/null. + +The challenge is to write a function that accepts an arbitrarily-deep nested list-like structure and returns a flattened structure without any nil/null values. + +For example: + +input: [1,[2,3,null,4],[null],5] + +output: [1,2,3,4,5] diff --git a/exercises/practice/flatten-array/.meta/config.json b/exercises/practice/flatten-array/.meta/config.json new file mode 100644 index 00000000..e66ad273 --- /dev/null +++ b/exercises/practice/flatten-array/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "fapdash" + ], + "files": { + "solution": [ + "flatten-array.el" + ], + "test": [ + "flatten-array-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Take a nested list and return a single list with all values except nil/null.", + "source": "Interview Question", + "source_url": "https://reference.wolfram.com/language/ref/Flatten.html" +} diff --git a/exercises/practice/flatten-array/.meta/example.el b/exercises/practice/flatten-array/.meta/example.el new file mode 100644 index 00000000..97456c0c --- /dev/null +++ b/exercises/practice/flatten-array/.meta/example.el @@ -0,0 +1,13 @@ +;;; flatten-array.el --- Flatten Array (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun list-flatten (list) + (flatten-tree list)) + + +(provide 'flatten-array) +;;; flatten-array.el ends here diff --git a/exercises/practice/flatten-array/.meta/tests.toml b/exercises/practice/flatten-array/.meta/tests.toml new file mode 100644 index 00000000..6300219d --- /dev/null +++ b/exercises/practice/flatten-array/.meta/tests.toml @@ -0,0 +1,43 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[8c71dabd-da60-422d-a290-4a571471fb14] +description = "empty" + +[d268b919-963c-442d-9f07-82b93f1b518c] +description = "no nesting" + +[3f15bede-c856-479e-bb71-1684b20c6a30] +description = "flattens a nested array" + +[c84440cc-bb3a-48a6-862c-94cf23f2815d] +description = "flattens array with just integers present" + +[d3d99d39-6be5-44f5-a31d-6037d92ba34f] +description = "5 level nesting" + +[d572bdba-c127-43ed-bdcd-6222ac83d9f7] +description = "6 level nesting" + +[0705a8e5-dc86-4cec-8909-150c5e54fa9c] +description = "null values are omitted from the final result" + +[c6cf26de-8ccd-4410-84bd-b9efd88fd2bc] +description = "consecutive null values at the front of the list are omitted from the final result" + +[382c5242-587e-4577-b8ce-a5fb51e385a1] +description = "consecutive null values in the middle of the list are omitted from the final result" + +[ef1d4790-1b1e-4939-a179-51ace0829dbd] +description = "6 level nest list with null values" + +[85721643-705a-4150-93ab-7ae398e2942d] +description = "all values in nested list are null" diff --git a/exercises/practice/flatten-array/flatten-array-test.el b/exercises/practice/flatten-array/flatten-array-test.el new file mode 100644 index 00000000..d70a1318 --- /dev/null +++ b/exercises/practice/flatten-array/flatten-array-test.el @@ -0,0 +1,74 @@ +;;; flatten-array-test.el --- Flatten Array (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "flatten-array.el") +(declare-function list-flatten "flatten-array.el" (array)) + + +(ert-deftest empty () + (should (equal (list-flatten '()) '()))) + + +(ert-deftest no-nesting () + (should (equal (list-flatten '(0 1 2)) '(0 1 2)))) + + +(ert-deftest flattens-a-nested-array () + (should (equal (list-flatten '((()))) '()))) + + +(ert-deftest flattens-array-with-just-integers-present () + (should + (equal (list-flatten '(1 (2 3 4 5 6 7) 8)) '(1 2 3 4 5 6 7 8)))) + + +(ert-deftest 5-level-nesting () + (should + (equal + (list-flatten '(0 2 ((2 3) 8 100 4 (((50)))) -2)) + '(0 2 2 3 8 100 4 50 -2)))) + + +(ert-deftest 6-level-nesting () + (should + (equal + (list-flatten '(1 (2 ((3)) (4 ((5))) 6 7) 8)) + '(1 2 3 4 5 6 7 8)))) + + +(ert-deftest null-values-are-omitted-from-the-final-result () + (should (equal (list-flatten '(1 2 nil)) '(1 2)))) + + +(ert-deftest + consecutive-null-values-at-the-front-of-the-list-are-omitted-from-the-final-result + () + (should (equal (list-flatten '(nil nil 3)) '(3)))) + + +(ert-deftest + consecutive-null-values-in-the-middle-of-the-list-are-omitted-from-the-final-result + () + (should (equal (list-flatten '(1 nil nil 4)) '(1 4)))) + + +(ert-deftest 6-level-nest-list-with-null-values () + (should + (equal + (list-flatten + '(0 2 ((2 3) 8 ((100)) nil ((nil))) -2)) + '(0 2 2 3 8 100 -2)))) + + +(ert-deftest all-values-in-nested-list-are-null () + (should + (equal + (list-flatten '(nil (((nil))) nil nil ((nil nil) nil) nil)) '()))) + + +(provide 'flatten-array-test) +;;; flatten-array-test.el ends here diff --git a/exercises/practice/flatten-array/flatten-array.el b/exercises/practice/flatten-array/flatten-array.el new file mode 100644 index 00000000..d0f19e10 --- /dev/null +++ b/exercises/practice/flatten-array/flatten-array.el @@ -0,0 +1,14 @@ +;;; flatten-array.el --- Flatten Array (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun list-flatten (list) + (error + "Delete this S-Expression and write your own implementation")) + + +(provide 'flatten-array) +;;; flatten-array.el ends here From 7c13c497f051e1d881c82036ba004db4cbe3bc3d Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Wed, 24 May 2023 00:51:40 +0200 Subject: [PATCH 030/162] Add binary-search practice exercise (#309) --- config.json | 8 +++ .../binary-search/.docs/instructions.md | 29 +++++++++ .../binary-search/.docs/introduction.md | 13 ++++ .../practice/binary-search/.meta/config.json | 19 ++++++ .../practice/binary-search/.meta/example.el | 26 ++++++++ .../practice/binary-search/.meta/tests.toml | 43 ++++++++++++++ .../binary-search/binary-search-test.el | 59 +++++++++++++++++++ .../practice/binary-search/binary-search.el | 14 +++++ 8 files changed, 211 insertions(+) create mode 100644 exercises/practice/binary-search/.docs/instructions.md create mode 100644 exercises/practice/binary-search/.docs/introduction.md create mode 100644 exercises/practice/binary-search/.meta/config.json create mode 100644 exercises/practice/binary-search/.meta/example.el create mode 100644 exercises/practice/binary-search/.meta/tests.toml create mode 100644 exercises/practice/binary-search/binary-search-test.el create mode 100644 exercises/practice/binary-search/binary-search.el diff --git a/config.json b/config.json index 94f762d3..b4caf9a2 100644 --- a/config.json +++ b/config.json @@ -502,6 +502,14 @@ "prerequisites": [], "difficulty": 1 }, + { + "slug": "binary-search", + "name": "Binary Search", + "uuid": "fb36c27f-0ad5-42d1-90c0-6718f01e61a4", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "flatten-array", "name": "Flatten Array", diff --git a/exercises/practice/binary-search/.docs/instructions.md b/exercises/practice/binary-search/.docs/instructions.md new file mode 100644 index 00000000..aa1946cf --- /dev/null +++ b/exercises/practice/binary-search/.docs/instructions.md @@ -0,0 +1,29 @@ +# Instructions + +Your task is to implement a binary search algorithm. + +A binary search algorithm finds an item in a list by repeatedly splitting it in half, only keeping the half which contains the item we're looking for. +It allows us to quickly narrow down the possible locations of our item until we find it, or until we've eliminated all possible locations. + +~~~~exercism/caution +Binary search only works when a list has been sorted. +~~~~ + +The algorithm looks like this: + +- Find the middle element of a *sorted* list and compare it with the item we're looking for. +- If the middle element is our item, then we're done! +- If the middle element is greater than our item, we can eliminate that element and all the elements **after** it. +- If the middle element is less than our item, we can eliminate that element and all the elements **before** it. +- If every element of the list has been eliminated then the item is not in the list. +- Otherwise, repeat the process on the part of the list that has not been eliminated. + +Here's an example: + +Let's say we're looking for the number 23 in the following sorted list: `[4, 8, 12, 16, 23, 28, 32]`. + +- We start by comparing 23 with the middle element, 16. +- Since 23 is greater than 16, we can eliminate the left half of the list, leaving us with `[23, 28, 32]`. +- We then compare 23 with the new middle element, 28. +- Since 23 is less than 28, we can eliminate the right half of the list: `[23]`. +- We've found our item. diff --git a/exercises/practice/binary-search/.docs/introduction.md b/exercises/practice/binary-search/.docs/introduction.md new file mode 100644 index 00000000..03496599 --- /dev/null +++ b/exercises/practice/binary-search/.docs/introduction.md @@ -0,0 +1,13 @@ +# Introduction + +You have stumbled upon a group of mathematicians who are also singer-songwriters. +They have written a song for each of their favorite numbers, and, as you can imagine, they have a lot of favorite numbers (like [0][zero] or [73][seventy-three] or [6174][kaprekars-constant]). + +You are curious to hear the song for your favorite number, but with so many songs to wade through, finding the right song could take a while. +Fortunately, they have organized their songs in a playlist sorted by the title — which is simply the number that the song is about. + +You realize that you can use a binary search algorithm to quickly find a song given the title. + +[zero]: https://en.wikipedia.org/wiki/0 +[seventy-three]: https://en.wikipedia.org/wiki/73_(number) +[kaprekars-constant]: https://en.wikipedia.org/wiki/6174_(number) diff --git a/exercises/practice/binary-search/.meta/config.json b/exercises/practice/binary-search/.meta/config.json new file mode 100644 index 00000000..af9941be --- /dev/null +++ b/exercises/practice/binary-search/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "fapdash" + ], + "files": { + "solution": [ + "binary-search.el" + ], + "test": [ + "binary-search-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Implement a binary search algorithm.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Binary_search_algorithm" +} diff --git a/exercises/practice/binary-search/.meta/example.el b/exercises/practice/binary-search/.meta/example.el new file mode 100644 index 00000000..e63f5753 --- /dev/null +++ b/exercises/practice/binary-search/.meta/example.el @@ -0,0 +1,26 @@ +;;; binary-search.el --- Binary Search (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun find-binary (array value) + (let ((left 0) + (right (1- (length array))) + middle + index-of-value) + (while (and (not index-of-value) (<= left right)) + (setq middle (+ left (/ (- right left) 2))) + (cond + ((equal (aref array middle) value) + (setq index-of-value middle)) + ((< (aref array middle) value) + (setq left (1+ middle))) + ((> (aref array middle) value) + (setq right (1- middle))))) + index-of-value)) + + +(provide 'binary-search) +;;; binary-search.el ends here diff --git a/exercises/practice/binary-search/.meta/tests.toml b/exercises/practice/binary-search/.meta/tests.toml new file mode 100644 index 00000000..61e2b068 --- /dev/null +++ b/exercises/practice/binary-search/.meta/tests.toml @@ -0,0 +1,43 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[b55c24a9-a98d-4379-a08c-2adcf8ebeee8] +description = "finds a value in an array with one element" + +[73469346-b0a0-4011-89bf-989e443d503d] +description = "finds a value in the middle of an array" + +[327bc482-ab85-424e-a724-fb4658e66ddb] +description = "finds a value at the beginning of an array" + +[f9f94b16-fe5e-472c-85ea-c513804c7d59] +description = "finds a value at the end of an array" + +[f0068905-26e3-4342-856d-ad153cadb338] +description = "finds a value in an array of odd length" + +[fc316b12-c8b3-4f5e-9e89-532b3389de8c] +description = "finds a value in an array of even length" + +[da7db20a-354f-49f7-a6a1-650a54998aa6] +description = "identifies that a value is not included in the array" + +[95d869ff-3daf-4c79-b622-6e805c675f97] +description = "a value smaller than the array's smallest value is not found" + +[8b24ef45-6e51-4a94-9eac-c2bf38fdb0ba] +description = "a value larger than the array's largest value is not found" + +[f439a0fa-cf42-4262-8ad1-64bf41ce566a] +description = "nothing is found in an empty array" + +[2c353967-b56d-40b8-acff-ce43115eed64] +description = "nothing is found when the left and right bounds cross" diff --git a/exercises/practice/binary-search/binary-search-test.el b/exercises/practice/binary-search/binary-search-test.el new file mode 100644 index 00000000..84981701 --- /dev/null +++ b/exercises/practice/binary-search/binary-search-test.el @@ -0,0 +1,59 @@ +;;; binary-search-test.el --- Binary Search (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "binary-search.el") +(declare-function find-binary "binary-search.el" (array value)) + + +(ert-deftest finds-a-value-in-an-array-with-one-element () + (should (= (find-binary [6] 6) 0))) + + +(ert-deftest finds-a-value-in-the-middle-of-an-array () + (should (= (find-binary [1 3 4 6 8 9 11] 6) 3))) + + +(ert-deftest finds-a-value-at-the-beginning-of-an-array () + (should (= (find-binary [1 3 4 6 8 9 11] 1) 0))) + + +(ert-deftest finds-a-value-at-the-end-of-an-array () + (should (= (find-binary [1 3 4 6 8 9 11] 11) 6))) + + +(ert-deftest finds-a-value-in-an-array-of-odd-length () + (should + (= (find-binary [1 3 5 8 13 21 34 55 89 144 233 377 634] 144) 9))) + + +(ert-deftest finds-a-value-in-an-array-of-even-length () + (should + (= (find-binary [1 3 5 8 13 21 34 55 89 144 233 377] 21) 5))) + + +(ert-deftest identifies-that-a-value-is-not-included-in-the-array () + (should (equal (find-binary [1 3 4 6 8 9 11] 7) nil))) + + +(ert-deftest a-value-smaller-than-the-array () + (should (equal (find-binary [1 3 4 6 8 9 11] 0) nil))) + + +(ert-deftest a-value-larger-than-the-array () + (should (equal (find-binary [1 3 4 6 8 9 11] 13) nil))) + + +(ert-deftest nothing-is-found-in-an-empty-array () + (should (equal (find-binary [] 1) nil))) + + +(ert-deftest nothing-is-found-when-the-left-and-right-bounds-cross () + (should (equal (find-binary [1 2] 0) nil))) + + +(provide 'binary-search-test) +;;; binary-search-test.el ends here diff --git a/exercises/practice/binary-search/binary-search.el b/exercises/practice/binary-search/binary-search.el new file mode 100644 index 00000000..081a0976 --- /dev/null +++ b/exercises/practice/binary-search/binary-search.el @@ -0,0 +1,14 @@ +;;; binary-search.el --- Binary Search (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun find-binary (array value) + (error + "Delete this S-Expression and write your own implementation")) + + +(provide 'binary-search) +;;; binary-search.el ends here From b9639c448aeb867132138f69a68ba74439add84d Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 18 Jul 2023 10:36:28 +0200 Subject: [PATCH 031/162] Convert `average_run_time` to an integer. (#320) There are two reasons for this change: 1. Having the average run time as a float gives the impression of being exact, whereas the actual run time wildly varies due to a wide variety of reasons (e.g. how busy it is on the server). That fractional component will almost never actually conform the real situation. 2. jq is often used to work with track config.json config files (e.g. to add elements to it), and it will remove any trailing .0 fractional part from a number, which caused configlet lint to fail. Those JQ scripts then have to work around this by manually adding .0 to it. --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index b4caf9a2..27bd09c3 100644 --- a/config.json +++ b/config.json @@ -16,7 +16,7 @@ "highlightjs_language": "lisp" }, "test_runner": { - "average_run_time": 2.0 + "average_run_time": 2 }, "files": { "solution": [ From 8f6097e879d5028d0563e4363466ee5a7cf4127b Mon Sep 17 00:00:00 2001 From: Michael Kohl Date: Wed, 30 Aug 2023 17:25:41 +0700 Subject: [PATCH 032/162] Add key features (#323) * Add key features * Remove extraneous key feature --- config.json | 161 ++++++++++++++++++---------------------------------- 1 file changed, 56 insertions(+), 105 deletions(-) diff --git a/config.json b/config.json index 27bd09c3..9f75f04e 100644 --- a/config.json +++ b/config.json @@ -19,18 +19,10 @@ "average_run_time": 2 }, "files": { - "solution": [ - "%{kebab_slug}.el" - ], - "test": [ - "%{kebab_slug}-test.el" - ], - "example": [ - "example.el" - ], - "exemplar": [ - ".meta/exemplar.el" - ] + "solution": ["%{kebab_slug}.el"], + "test": ["%{kebab_slug}-test.el"], + "example": ["example.el"], + "exemplar": [".meta/exemplar.el"] }, "exercises": { "concept": [], @@ -42,9 +34,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "strings" - ] + "topics": ["strings"] }, { "slug": "two-fer", @@ -53,9 +43,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "strings" - ] + "topics": ["strings"] }, { "slug": "leap", @@ -64,12 +52,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "control_flow_conditionals", - "equality", - "integers", - "logic" - ] + "topics": ["control_flow_conditionals", "equality", "integers", "logic"] }, { "slug": "anagram", @@ -78,11 +61,7 @@ "practices": [], "prerequisites": [], "difficulty": 2, - "topics": [ - "equality", - "filtering", - "strings" - ] + "topics": ["equality", "filtering", "strings"] }, { "slug": "roman-numerals", @@ -121,11 +100,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "control_flow_conditionals", - "strings", - "transforming" - ] + "topics": ["control_flow_conditionals", "strings", "transforming"] }, { "slug": "bob", @@ -134,11 +109,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "control_flow_conditionals", - "parsing", - "strings" - ] + "topics": ["control_flow_conditionals", "parsing", "strings"] }, { "slug": "word-count", @@ -161,10 +132,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "strings", - "transforming" - ] + "topics": ["strings", "transforming"] }, { "slug": "allergies", @@ -187,9 +155,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "math" - ] + "topics": ["math"] }, { "slug": "binary", @@ -236,11 +202,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "control_flow_loops", - "maps", - "transforming" - ] + "topics": ["control_flow_loops", "maps", "transforming"] }, { "slug": "gigasecond", @@ -249,13 +211,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "date", - "integers", - "time", - "transforming", - "variables" - ] + "topics": ["date", "integers", "time", "transforming", "variables"] }, { "slug": "grains", @@ -264,10 +220,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "integers", - "variables" - ] + "topics": ["integers", "variables"] }, { "slug": "nucleotide-count", @@ -276,12 +229,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "control_flow_loops", - "maps", - "sorting", - "strings" - ] + "topics": ["control_flow_loops", "maps", "sorting", "strings"] }, { "slug": "pangram", @@ -290,10 +238,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "control_flow_loops", - "strings" - ] + "topics": ["control_flow_loops", "strings"] }, { "slug": "perfect-numbers", @@ -302,10 +247,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "math", - "number_theory" - ] + "topics": ["math", "number_theory"] }, { "slug": "raindrops", @@ -314,11 +256,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "control_flow_conditionals", - "filtering", - "integers" - ] + "topics": ["control_flow_conditionals", "filtering", "integers"] }, { "slug": "trinary", @@ -327,9 +265,7 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": [ - "math" - ] + "topics": ["math"] }, { "slug": "atbash-cipher", @@ -352,11 +288,7 @@ "practices": [], "prerequisites": [], "difficulty": 2, - "topics": [ - "cryptograpy", - "strings", - "transforming" - ] + "topics": ["cryptograpy", "strings", "transforming"] }, { "slug": "phone-number", @@ -365,11 +297,7 @@ "practices": [], "prerequisites": [], "difficulty": 2, - "topics": [ - "interfaces", - "parsing", - "strings" - ] + "topics": ["interfaces", "parsing", "strings"] }, { "slug": "robot-name", @@ -378,11 +306,7 @@ "practices": [], "prerequisites": [], "difficulty": 2, - "topics": [ - "randomness", - "strings", - "variables" - ] + "topics": ["randomness", "strings", "variables"] }, { "slug": "run-length-encoding", @@ -400,11 +324,7 @@ "practices": [], "prerequisites": [], "difficulty": 3, - "topics": [ - "checksums", - "list_operations", - "strings" - ] + "topics": ["checksums", "list_operations", "strings"] }, { "slug": "list-ops", @@ -521,7 +441,38 @@ ] }, "concepts": [], - "key_features": [], + "key_features": [ + { + "title": "Simple syntax", + "content": "Emacs Lisp's syntax is simple, expressive and easy to learn.", + "icon": "easy" + }, + { + "title": "S-expressions", + "content": "Both source code and data are expressed using nested lists.", + "icon": "homoiconic" + }, + { + "title": "Macros", + "content": "It's easy to customize the language with Emacs Lisp's macro system.", + "icon": "powerful" + }, + { + "title": "Multi-paradigm", + "content": "Emacs Lisp support imperative and functional programming styles.", + "icon": "multi-paradigm" + }, + { + "title": "Scripting", + "content": "Emacs Lisp can be used as scripting language by using Emacs' batch mode.", + "icon": "embeddable" + }, + { + "title": "Well Documented", + "content": "Emacs Lisp is well documented right inside the editor.", + "icon": "documentation" + } + ], "tags": [ "paradigm/functional", "typing/dynamic", From 5be38c5135f8ceafddf5f4ec37eba35195d73423 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 14 Nov 2023 14:30:12 +0100 Subject: [PATCH 033/162] Pin GitHub Actions runners to a specific version (#331) --- .github/workflows/ci.yml | 2 +- .github/workflows/configlet-sync.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7732325d..e86e4608 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ on: jobs: ci: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: purcell/setup-emacs@ac5a5667ef01c598f55e66e0b0abdad5d825daf8 diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index 28dc20ed..ae66f3cc 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -9,7 +9,7 @@ jobs: configlet: if: github.repository_owner == 'exercism' # Stops this job from running on forks timeout-minutes: 30 - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 From 5f5a2420a7151b3622270b45b7a52f4482595850 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 24 Jan 2024 16:06:14 +0100 Subject: [PATCH 034/162] leap: sync (#332) * Sync the `leap` exercise's docs with the latest data. * Sync the `leap` exercise's metadata with the latest data. --- exercises/practice/leap/.docs/instructions.md | 21 +------------------ exercises/practice/leap/.docs/introduction.md | 16 ++++++++++++++ exercises/practice/leap/.meta/config.json | 2 +- 3 files changed, 18 insertions(+), 21 deletions(-) create mode 100644 exercises/practice/leap/.docs/introduction.md diff --git a/exercises/practice/leap/.docs/instructions.md b/exercises/practice/leap/.docs/instructions.md index a83826b2..b14f8565 100644 --- a/exercises/practice/leap/.docs/instructions.md +++ b/exercises/practice/leap/.docs/instructions.md @@ -1,22 +1,3 @@ # Instructions -Given a year, report if it is a leap year. - -The tricky thing here is that a leap year in the Gregorian calendar occurs: - -```text -on every year that is evenly divisible by 4 - except every year that is evenly divisible by 100 - unless the year is also evenly divisible by 400 -``` - -For example, 1997 is not a leap year, but 1996 is. -1900 is not a leap year, but 2000 is. - -## Notes - -Though our exercise adopts some very simple rules, there is more to learn! - -For a delightful, four minute explanation of the whole leap year phenomenon, go watch [this youtube video][video]. - -[video]: https://www.youtube.com/watch?v=xX96xng7sAE +Your task is to determine whether a given year is a leap year. diff --git a/exercises/practice/leap/.docs/introduction.md b/exercises/practice/leap/.docs/introduction.md new file mode 100644 index 00000000..4ffd2da5 --- /dev/null +++ b/exercises/practice/leap/.docs/introduction.md @@ -0,0 +1,16 @@ +# Introduction + +A leap year (in the Gregorian calendar) occurs: + +- In every year that is evenly divisible by 4. +- Unless the year is evenly divisible by 100, in which case it's only a leap year if the year is also evenly divisible by 400. + +Some examples: + +- 1997 was not a leap year as it's not divisible by 4. +- 1900 was not a leap year as it's not divisible by 400. +- 2000 was a leap year! + +~~~~exercism/note +For a delightful, four-minute explanation of the whole phenomenon of leap years, check out [this YouTube video](https://www.youtube.com/watch?v=xX96xng7sAE). +~~~~ diff --git a/exercises/practice/leap/.meta/config.json b/exercises/practice/leap/.meta/config.json index b9dc2928..4560b0c7 100644 --- a/exercises/practice/leap/.meta/config.json +++ b/exercises/practice/leap/.meta/config.json @@ -16,7 +16,7 @@ ".meta/example.el" ] }, - "blurb": "Given a year, report if it is a leap year.", + "blurb": "Determine whether a given year is a leap year.", "source": "CodeRanch Cattle Drive, Assignment 3", "source_url": "https://coderanch.com/t/718816/Leap" } From 6171a21efa838e940d5a7e71cb0a896d892b08c4 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 25 Jan 2024 08:19:13 +0100 Subject: [PATCH 035/162] reverse-string: sync (#333) * Sync the `reverse-string` exercise's docs with the latest data. * Sync the `reverse-string` exercise's metadata with the latest data. --- .../practice/reverse-string/.docs/instructions.md | 10 ++++++---- .../practice/reverse-string/.docs/introduction.md | 5 +++++ exercises/practice/reverse-string/.meta/config.json | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 exercises/practice/reverse-string/.docs/introduction.md diff --git a/exercises/practice/reverse-string/.docs/instructions.md b/exercises/practice/reverse-string/.docs/instructions.md index 039ee33a..0ff4198e 100644 --- a/exercises/practice/reverse-string/.docs/instructions.md +++ b/exercises/practice/reverse-string/.docs/instructions.md @@ -1,7 +1,9 @@ # Instructions -Reverse a string +Your task is to reverse a given string. -For example: -input: "cool" -output: "looc" +Some examples: + +- Turn `"stressed"` into `"desserts"`. +- Turn `"strops"` into `"sports"`. +- Turn `"racecar"` into `"racecar"`. diff --git a/exercises/practice/reverse-string/.docs/introduction.md b/exercises/practice/reverse-string/.docs/introduction.md new file mode 100644 index 00000000..02233e07 --- /dev/null +++ b/exercises/practice/reverse-string/.docs/introduction.md @@ -0,0 +1,5 @@ +# Introduction + +Reversing strings (reading them from right to left, rather than from left to right) is a surprisingly common task in programming. + +For example, in bioinformatics, reversing the sequence of DNA or RNA strings is often important for various analyses, such as finding complementary strands or identifying palindromic sequences that have biological significance. diff --git a/exercises/practice/reverse-string/.meta/config.json b/exercises/practice/reverse-string/.meta/config.json index 2fffa5fc..34a81d6c 100644 --- a/exercises/practice/reverse-string/.meta/config.json +++ b/exercises/practice/reverse-string/.meta/config.json @@ -13,7 +13,7 @@ ".meta/example.el" ] }, - "blurb": "Reverse a string.", + "blurb": "Reverse a given string.", "source": "Introductory challenge to reverse an input string", "source_url": "https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb" } From 0be974df071da7cfeec58e2064b32258a1b5e239 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 1 Feb 2024 10:15:58 +0100 Subject: [PATCH 036/162] Sync the `raindrops` exercise's docs with the latest data. (#335) --- .../practice/raindrops/.docs/instructions.md | 26 +++++++++++-------- .../practice/raindrops/.docs/introduction.md | 3 +++ 2 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 exercises/practice/raindrops/.docs/introduction.md diff --git a/exercises/practice/raindrops/.docs/instructions.md b/exercises/practice/raindrops/.docs/instructions.md index fc61d36e..df644107 100644 --- a/exercises/practice/raindrops/.docs/instructions.md +++ b/exercises/practice/raindrops/.docs/instructions.md @@ -1,20 +1,24 @@ # Instructions -Your task is to convert a number into a string that contains raindrop sounds corresponding to certain potential factors. -A factor is a number that evenly divides into another number, leaving no remainder. -The simplest way to test if one number is a factor of another is to use the [modulo operation][modulo]. +Your task is to convert a number into its corresponding raindrop sounds. -The rules of `raindrops` are that if a given number: +If a given number: -- has 3 as a factor, add 'Pling' to the result. -- has 5 as a factor, add 'Plang' to the result. -- has 7 as a factor, add 'Plong' to the result. -- _does not_ have any of 3, 5, or 7 as a factor, the result should be the digits of the number. +- is divisible by 3, add "Pling" to the result. +- is divisible by 5, add "Plang" to the result. +- is divisible by 7, add "Plong" to the result. +- **is not** divisible by 3, 5, or 7, the result should be the number as a string. ## Examples -- 28 has 7 as a factor, but not 3 or 5, so the result would be "Plong". -- 30 has both 3 and 5 as factors, but not 7, so the result would be "PlingPlang". -- 34 is not factored by 3, 5, or 7, so the result would be "34". +- 28 is divisible by 7, but not 3 or 5, so the result would be `"Plong"`. +- 30 is divisible by 3 and 5, but not 7, so the result would be `"PlingPlang"`. +- 34 is not divisible by 3, 5, or 7, so the result would be `"34"`. +~~~~exercism/note +A common way to test if one number is evenly divisible by another is to compare the [remainder][remainder] or [modulus][modulo] to zero. +Most languages provide operators or functions for one (or both) of these. + +[remainder]: https://exercism.org/docs/programming/operators/remainder [modulo]: https://en.wikipedia.org/wiki/Modulo_operation +~~~~ diff --git a/exercises/practice/raindrops/.docs/introduction.md b/exercises/practice/raindrops/.docs/introduction.md new file mode 100644 index 00000000..ba12100f --- /dev/null +++ b/exercises/practice/raindrops/.docs/introduction.md @@ -0,0 +1,3 @@ +# Introduction + +Raindrops is a slightly more complex version of the FizzBuzz challenge, a classic interview question. From ac216f861cf7e29be1c1193c2d8de37402720944 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 15 Feb 2024 14:11:39 +0100 Subject: [PATCH 037/162] roman-numerals: sync (#339) * Sync the `roman-numerals` exercise's docs with the latest data. * Sync the `roman-numerals` exercise's metadata with the latest data. --- .../roman-numerals/.docs/instructions.md | 45 +++----------- .../roman-numerals/.docs/introduction.md | 59 +++++++++++++++++++ .../practice/roman-numerals/.meta/config.json | 2 +- 3 files changed, 68 insertions(+), 38 deletions(-) create mode 100644 exercises/practice/roman-numerals/.docs/introduction.md diff --git a/exercises/practice/roman-numerals/.docs/instructions.md b/exercises/practice/roman-numerals/.docs/instructions.md index 247ea089..50e2f5bf 100644 --- a/exercises/practice/roman-numerals/.docs/instructions.md +++ b/exercises/practice/roman-numerals/.docs/instructions.md @@ -1,41 +1,12 @@ -# Instructions +# Introduction -Write a function to convert from normal numbers to Roman Numerals. +Your task is to convert a number from Arabic numerals to Roman numerals. -The Romans were a clever bunch. -They conquered most of Europe and ruled it for hundreds of years. -They invented concrete and straight roads and even bikinis. -One thing they never discovered though was the number zero. -This made writing and dating extensive histories of their exploits slightly more challenging, but the system of numbers they came up with is still in use today. -For example the BBC uses Roman numerals to date their programs. +For this exercise, we are only concerned about traditional Roman numerals, in which the largest number is MMMCMXCIX (or 3,999). -The Romans wrote numbers using letters - I, V, X, L, C, D, M. -(notice these letters have lots of straight lines and are hence easy to hack into stone tablets). +~~~~exercism/note +There are lots of different ways to convert between Arabic and Roman numerals. +We recommend taking a naive approach first to familiarise yourself with the concept of Roman numerals and then search for more efficient methods. -```text - 1 => I -10 => X - 7 => VII -``` - -The maximum number supported by this notation is 3,999. -(The Romans themselves didn't tend to go any higher) - -Wikipedia says: Modern Roman numerals ... are written by expressing each digit separately starting with the left most digit and skipping any digit with a value of zero. - -To see this in practice, consider the example of 1990. - -In Roman numerals 1990 is MCMXC: - -1000=M -900=CM -90=XC - -2008 is written as MMVIII: - -2000=MM -8=VIII - -Learn more about [Roman numerals on Wikipedia][roman-numerals]. - -[roman-numerals]: https://wiki.imperivm-romanvm.com/wiki/Roman_Numerals +Make sure to check out our Deep Dive video at the end to explore the different approaches you can take! +~~~~ diff --git a/exercises/practice/roman-numerals/.docs/introduction.md b/exercises/practice/roman-numerals/.docs/introduction.md new file mode 100644 index 00000000..6fd942fe --- /dev/null +++ b/exercises/practice/roman-numerals/.docs/introduction.md @@ -0,0 +1,59 @@ +# Description + +Today, most people in the world use Arabic numerals (0–9). +But if you travelled back two thousand years, you'd find that most Europeans were using Roman numerals instead. + +To write a Roman numeral we use the following Latin letters, each of which has a value: + +| M | D | C | L | X | V | I | +| ---- | --- | --- | --- | --- | --- | --- | +| 1000 | 500 | 100 | 50 | 10 | 5 | 1 | + +A Roman numeral is a sequence of these letters, and its value is the sum of the letters' values. +For example, `XVIII` has the value 18 (`10 + 5 + 1 + 1 + 1 = 18`). + +There's one rule that makes things trickier though, and that's that **the same letter cannot be used more than three times in succession**. +That means that we can't express numbers such as 4 with the seemingly natural `IIII`. +Instead, for those numbers, we use a subtraction method between two letters. +So we think of `4` not as `1 + 1 + 1 + 1` but instead as `5 - 1`. +And slightly confusingly to our modern thinking, we write the smaller number first. +This applies only in the following cases: 4 (`IV`), 9 (`IX`), 40 (`XL`), 90 (`XC`), 400 (`CD`) and 900 (`CM`). + +Order matters in Roman numerals! +Letters (and the special compounds above) must be ordered by decreasing value from left to right. + +Here are some examples: + +```text + 105 => CV +---- => -- + 100 => C ++ 5 => V +``` + +```text + 106 => CVI +---- => -- + 100 => C ++ 5 => V ++ 1 => I +``` + +```text + 104 => CIV +---- => --- + 100 => C ++ 4 => IV +``` + +And a final more complex example: + +```text + 1996 => MCMXCVI +----- => ------- + 1000 => M ++ 900 => CM ++ 90 => XC ++ 5 => V ++ 1 => I +``` diff --git a/exercises/practice/roman-numerals/.meta/config.json b/exercises/practice/roman-numerals/.meta/config.json index a31b48bd..a775247e 100644 --- a/exercises/practice/roman-numerals/.meta/config.json +++ b/exercises/practice/roman-numerals/.meta/config.json @@ -16,7 +16,7 @@ ".meta/example.el" ] }, - "blurb": "Write a function to convert from normal numbers to Roman Numerals.", + "blurb": "Convert modern Arabic numbers into Roman numerals.", "source": "The Roman Numeral Kata", "source_url": "https://codingdojo.org/kata/RomanNumerals/" } From 78996ea4b62701771fe99610d5a97e431a588824 Mon Sep 17 00:00:00 2001 From: Exercism Bot Date: Tue, 5 Mar 2024 14:44:10 +0000 Subject: [PATCH 038/162] =?UTF-8?q?=F0=9F=A4=96=20Sync=20org-wide=20files?= =?UTF-8?q?=20to=20upstream=20repo=20(#340)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More info: https://github.com/exercism/org-wide-files/commit/0c0972d1df4cd18d98c7df316348315b06ef49b4 --- .../workflows/no-important-files-changed.yml | 23 +++++++++++++++++++ CODE_OF_CONDUCT.md | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/no-important-files-changed.yml diff --git a/.github/workflows/no-important-files-changed.yml b/.github/workflows/no-important-files-changed.yml new file mode 100644 index 00000000..b940c599 --- /dev/null +++ b/.github/workflows/no-important-files-changed.yml @@ -0,0 +1,23 @@ +name: No important files changed + +on: + pull_request_target: + types: [opened] + branches: [main] + paths: + - "exercises/concept/**" + - "exercises/practice/**" + - "!exercises/*/*/.approaches/**" + - "!exercises/*/*/.articles/**" + - "!exercises/*/*/.docs/**" + - "!exercises/*/*/.meta/**" + +permissions: + pull-requests: write + +jobs: + pause: + uses: exercism/github-actions/.github/workflows/check-no-important-files-changed.yml@main + with: + repository: ${{ github.event.pull_request.head.repo.owner.login }}/${{ github.event.pull_request.head.repo.name }} + ref: ${{ github.head_ref }} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index df8e3676..3f7813de 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -90,4 +90,4 @@ This policy was initially adopted from the Front-end London Slack community and A version history can be seen on [GitHub](https://github.com/exercism/website-copy/edit/main/pages/code_of_conduct.md). _This policy is a "living" document, and subject to refinement and expansion in the future. -This policy applies to the Exercism website, the Exercism GitHub organization, any other Exercism-related communication channels (e.g. Slack, Twitter, email) and any other Exercism entity or event._ +This policy applies to the Exercism website, the Exercism GitHub organization, any other Exercism-related communication channels (e.g. Discord, Forum, Twitter, email) and any other Exercism entity or event._ From 1ce42148f0c3c308f536721d84e695c3ec7f17b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Mar 2024 09:14:40 +0100 Subject: [PATCH 039/162] Bump actions/checkout from 3.5.2 to 4.0.0 (#324) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.2 to 4.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/8e5e7e5ab8b370d6c329ec480221332ada57f0ab...3df4ab11eba7bda6032a0b82a6bb43b11571feac) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/configlet-sync.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e86e4608..7a876f2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: with: version: 28.2 - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: Run exercism/emacs-lisp ci (runs tests) for all exercises run: | diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index ae66f3cc..473f7f84 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: Fetch configlet uses: exercism/github-actions/configlet-ci@main From ee1dee9614f0d814018b22de01901f72286d7940 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Mar 2024 09:35:30 +0100 Subject: [PATCH 040/162] Bump actions/checkout (#342) Bumps [actions/checkout](https://github.com/actions/checkout) from 3df4ab11eba7bda6032a0b82a6bb43b11571feac to cd7d8d697e10461458bc61a30d094dc601a8b017. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/3df4ab11eba7bda6032a0b82a6bb43b11571feac...cd7d8d697e10461458bc61a30d094dc601a8b017) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/configlet-sync.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a876f2b..b4a7ce5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: with: version: 28.2 - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@cd7d8d697e10461458bc61a30d094dc601a8b017 # v4.0.0 - name: Run exercism/emacs-lisp ci (runs tests) for all exercises run: | diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index 473f7f84..10fae966 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@cd7d8d697e10461458bc61a30d094dc601a8b017 # v4.0.0 - name: Fetch configlet uses: exercism/github-actions/configlet-ci@main From 929386465a61791769971c76cd132ca75e0a3d09 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 12 Apr 2024 12:03:40 +0200 Subject: [PATCH 041/162] Sync the `two-fer` exercise's docs with the latest data. (#344) --- exercises/practice/two-fer/.docs/instructions.md | 5 ++--- exercises/practice/two-fer/.docs/introduction.md | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/exercises/practice/two-fer/.docs/instructions.md b/exercises/practice/two-fer/.docs/instructions.md index 37aa7529..adc53487 100644 --- a/exercises/practice/two-fer/.docs/instructions.md +++ b/exercises/practice/two-fer/.docs/instructions.md @@ -2,14 +2,13 @@ Your task is to determine what you will say as you give away the extra cookie. -If your friend likes cookies, and is named Do-yun, then you will say: +If you know the person's name (e.g. if they're named Do-yun), then you will say: ```text One for Do-yun, one for me. ``` -If your friend doesn't like cookies, you give the cookie to the next person in line at the bakery. -Since you don't know their name, you will say _you_ instead. +If you don't know the person's name, you will say _you_ instead. ```text One for you, one for me. diff --git a/exercises/practice/two-fer/.docs/introduction.md b/exercises/practice/two-fer/.docs/introduction.md index 8c124394..5947a223 100644 --- a/exercises/practice/two-fer/.docs/introduction.md +++ b/exercises/practice/two-fer/.docs/introduction.md @@ -5,4 +5,4 @@ Two-for-one is a way of saying that if you buy one, you also get one for free. So the phrase "two-fer" often implies a two-for-one offer. Imagine a bakery that has a holiday offer where you can buy two cookies for the price of one ("two-fer one!"). -You go for the offer and (very generously) decide to give the extra cookie to a friend. +You take the offer and (very generously) decide to give the extra cookie to someone else in the queue. From 026160ad0d3d05450bda8f82fd5df2c627323e4a Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 23 Apr 2024 13:55:08 +0200 Subject: [PATCH 042/162] Sync the `all-your-base` exercise's docs with the latest data. (#345) --- .../all-your-base/.docs/instructions.md | 29 ++++++++----------- .../all-your-base/.docs/introduction.md | 8 +++++ 2 files changed, 20 insertions(+), 17 deletions(-) create mode 100644 exercises/practice/all-your-base/.docs/introduction.md diff --git a/exercises/practice/all-your-base/.docs/instructions.md b/exercises/practice/all-your-base/.docs/instructions.md index d5a2cde6..1b688b69 100644 --- a/exercises/practice/all-your-base/.docs/instructions.md +++ b/exercises/practice/all-your-base/.docs/instructions.md @@ -1,33 +1,28 @@ # Instructions -Convert a number, represented as a sequence of digits in one base, to any other base. +Convert a sequence of digits in one base, representing a number, into a sequence of digits in another base, representing the same number. -Implement general base conversion. -Given a number in base **a**, represented as a sequence of digits, convert it to base **b**. - -## Note - -- Try to implement the conversion yourself. - Do not use something else to perform the conversion for you. +~~~~exercism/note +Try to implement the conversion yourself. +Do not use something else to perform the conversion for you. +~~~~ ## About [Positional Notation][positional-notation] In positional notation, a number in base **b** can be understood as a linear combination of powers of **b**. -The number 42, *in base 10*, means: - -`(4 * 10^1) + (2 * 10^0)` +The number 42, _in base 10_, means: -The number 101010, *in base 2*, means: +`(4 × 10¹) + (2 × 10⁰)` -`(1 * 2^5) + (0 * 2^4) + (1 * 2^3) + (0 * 2^2) + (1 * 2^1) + (0 * 2^0)` +The number 101010, _in base 2_, means: -The number 1120, *in base 3*, means: +`(1 × 2⁵) + (0 × 2⁴) + (1 × 2³) + (0 × 2²) + (1 × 2¹) + (0 × 2⁰)` -`(1 * 3^3) + (1 * 3^2) + (2 * 3^1) + (0 * 3^0)` +The number 1120, _in base 3_, means: -I think you got the idea! +`(1 × 3³) + (1 × 3²) + (2 × 3¹) + (0 × 3⁰)` -*Yes. Those three numbers above are exactly the same. Congratulations!* +_Yes. Those three numbers above are exactly the same. Congratulations!_ [positional-notation]: https://en.wikipedia.org/wiki/Positional_notation diff --git a/exercises/practice/all-your-base/.docs/introduction.md b/exercises/practice/all-your-base/.docs/introduction.md new file mode 100644 index 00000000..68aaffbe --- /dev/null +++ b/exercises/practice/all-your-base/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +You've just been hired as professor of mathematics. +Your first week went well, but something is off in your second week. +The problem is that every answer given by your students is wrong! +Luckily, your math skills have allowed you to identify the problem: the student answers _are_ correct, but they're all in base 2 (binary)! +Amazingly, it turns out that each week, the students use a different base. +To help you quickly verify the student answers, you'll be building a tool to translate between bases. From 6994c387d7b9d799ccd02e4d54db836c1419c0ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 06:28:38 -0700 Subject: [PATCH 043/162] Bump purcell/setup-emacs from 4.0 to 6.0 (#325) Bumps [purcell/setup-emacs](https://github.com/purcell/setup-emacs) from 4.0 to 6.0. - [Release notes](https://github.com/purcell/setup-emacs/releases) - [Commits](https://github.com/purcell/setup-emacs/compare/ac5a5667ef01c598f55e66e0b0abdad5d825daf8...c851e5408f2d2f657fa80375bbe3fb35029aa488) --- updated-dependencies: - dependency-name: purcell/setup-emacs dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4a7ce5a..044a1075 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: purcell/setup-emacs@ac5a5667ef01c598f55e66e0b0abdad5d825daf8 + - uses: purcell/setup-emacs@c851e5408f2d2f657fa80375bbe3fb35029aa488 with: version: 28.2 From a4ff26f7077fd36b32f737af605048162465899a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 06:29:52 -0700 Subject: [PATCH 044/162] Bump actions/checkout (#346) Bumps [actions/checkout](https://github.com/actions/checkout) from cd7d8d697e10461458bc61a30d094dc601a8b017 to 1d96c772d19495a3b5c517cd2bc0cb401ea0529f. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/cd7d8d697e10461458bc61a30d094dc601a8b017...1d96c772d19495a3b5c517cd2bc0cb401ea0529f) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/configlet-sync.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 044a1075..910d3311 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: with: version: 28.2 - - uses: actions/checkout@cd7d8d697e10461458bc61a30d094dc601a8b017 # v4.0.0 + - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.0.0 - name: Run exercism/emacs-lisp ci (runs tests) for all exercises run: | diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index 10fae966..154e3845 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@cd7d8d697e10461458bc61a30d094dc601a8b017 # v4.0.0 + - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.0.0 - name: Fetch configlet uses: exercism/github-actions/configlet-ci@main From db2c0318232269080bbbfa5be9853b36336afa0e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 06:30:32 -0700 Subject: [PATCH 045/162] Bump JasonEtco/create-an-issue from 2.9.1 to 2.9.2 (#343) Bumps [JasonEtco/create-an-issue](https://github.com/jasonetco/create-an-issue) from 2.9.1 to 2.9.2. - [Release notes](https://github.com/jasonetco/create-an-issue/releases) - [Commits](https://github.com/jasonetco/create-an-issue/compare/e27dddc79c92bc6e4562f268fffa5ed752639abd...1b14a70e4d8dc185e5cc76d3bec9eab20257b2c5) --- updated-dependencies: - dependency-name: JasonEtco/create-an-issue dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/configlet-sync.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index 154e3845..61dbad3d 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -34,7 +34,7 @@ jobs: - name: Create issue if: ${{ failure() }} - uses: JasonEtco/create-an-issue@e27dddc79c92bc6e4562f268fffa5ed752639abd # v2.9.1 + uses: JasonEtco/create-an-issue@1b14a70e4d8dc185e5cc76d3bec9eab20257b2c5 # v2.9.2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: From 5066e7c57f234bafde7d2f00c948a031af8ce5bc Mon Sep 17 00:00:00 2001 From: Exercism Bot Date: Tue, 23 Apr 2024 14:31:04 +0100 Subject: [PATCH 046/162] =?UTF-8?q?=F0=9F=A4=96=20Sync=20org-wide=20files?= =?UTF-8?q?=20to=20upstream=20repo=20(#341)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More info: https://github.com/exercism/org-wide-files/commit/45ce43faa93a84c84f407748aae3aa028383ec77 --- .github/workflows/no-important-files-changed.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/no-important-files-changed.yml b/.github/workflows/no-important-files-changed.yml index b940c599..812e9129 100644 --- a/.github/workflows/no-important-files-changed.yml +++ b/.github/workflows/no-important-files-changed.yml @@ -16,7 +16,7 @@ permissions: pull-requests: write jobs: - pause: + check: uses: exercism/github-actions/.github/workflows/check-no-important-files-changed.yml@main with: repository: ${{ github.event.pull_request.head.repo.owner.login }}/${{ github.event.pull_request.head.repo.name }} From 77d1fe6ef667d2836164b7253ca0dc29e4cc4f2a Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Wed, 24 Apr 2024 02:21:43 +1000 Subject: [PATCH 047/162] feat: Add exercise Scrabble Score (closes #311) (#315) * feat: Add exercise Scrabble Score (closes #311) * Update config.json --------- Co-authored-by: Jeremy Walker --- config.json | 12 ++++ .../scrabble-score/.docs/instructions.md | 40 ++++++++++++++ .../practice/scrabble-score/.meta/config.json | 19 +++++++ .../practice/scrabble-score/.meta/example.el | 36 ++++++++++++ .../practice/scrabble-score/.meta/tests.toml | 43 +++++++++++++++ .../scrabble-score/scrabble-score-test.el | 55 +++++++++++++++++++ .../practice/scrabble-score/scrabble-score.el | 11 ++++ 7 files changed, 216 insertions(+) create mode 100644 exercises/practice/scrabble-score/.docs/instructions.md create mode 100644 exercises/practice/scrabble-score/.meta/config.json create mode 100644 exercises/practice/scrabble-score/.meta/example.el create mode 100644 exercises/practice/scrabble-score/.meta/tests.toml create mode 100644 exercises/practice/scrabble-score/scrabble-score-test.el create mode 100644 exercises/practice/scrabble-score/scrabble-score.el diff --git a/config.json b/config.json index 9f75f04e..3a51f988 100644 --- a/config.json +++ b/config.json @@ -437,6 +437,18 @@ "practices": [], "prerequisites": [], "difficulty": 6 + }, + { + "slug": "scrabble-score", + "name": "Scrabble Score", + "uuid": "fb45c509-d83d-4f71-a8ef-f218c5426838", + "practices": [], + "prerequisites": [], + "difficulty": 3, + "topics": [ + "lists", + "strings" + ] } ] }, diff --git a/exercises/practice/scrabble-score/.docs/instructions.md b/exercises/practice/scrabble-score/.docs/instructions.md new file mode 100644 index 00000000..3f986c94 --- /dev/null +++ b/exercises/practice/scrabble-score/.docs/instructions.md @@ -0,0 +1,40 @@ +# Instructions + +Given a word, compute the Scrabble score for that word. + +## Letter Values + +You'll need these: + +```text +Letter Value +A, E, I, O, U, L, N, R, S, T 1 +D, G 2 +B, C, M, P 3 +F, H, V, W, Y 4 +K 5 +J, X 8 +Q, Z 10 +``` + +## Examples + +"cabbage" should be scored as worth 14 points: + +- 3 points for C +- 1 point for A, twice +- 3 points for B, twice +- 2 points for G +- 1 point for E + +And to total: + +- `3 + 2*1 + 2*3 + 2 + 1` +- = `3 + 2 + 6 + 3` +- = `5 + 9` +- = 14 + +## Extensions + +- You can play a double or a triple letter. +- You can play a double or a triple word. diff --git a/exercises/practice/scrabble-score/.meta/config.json b/exercises/practice/scrabble-score/.meta/config.json new file mode 100644 index 00000000..e78d541a --- /dev/null +++ b/exercises/practice/scrabble-score/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "scrabble-score.el" + ], + "test": [ + "scrabble-score-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given a word, compute the Scrabble score for that word.", + "source": "Inspired by the Extreme Startup game", + "source_url": "https://github.com/rchatley/extreme_startup" +} diff --git a/exercises/practice/scrabble-score/.meta/example.el b/exercises/practice/scrabble-score/.meta/example.el new file mode 100644 index 00000000..6e3e0ef6 --- /dev/null +++ b/exercises/practice/scrabble-score/.meta/example.el @@ -0,0 +1,36 @@ +;;; scrabble-score.el --- Scrabble Score (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defvar letters->score '( + ("AEIOULNRST" . 1) + ("DG" . 2) + ("BCMP" . 3) + ("FHVWY" . 4) + ("K" . 5) + ("JX" . 8) + ("QZ" . 10) +)) + +(defun letter-score (letter) + "The Scrabble score for letter" + (let ((table letters->score)) + (while + (not (cl-find letter (caar table))) + (setq table (cdr table))) + (cdar table))) + +(defun score (word) + "The Scrabble score for word" + (let ((total 0) + (letters (cl-coerce (upcase word) 'list))) + (dolist (letter letters) + (setq total (+ total (letter-score letter)))) + total)) + +(provide 'scrabble-score) +;;; scrabble-score.el ends here diff --git a/exercises/practice/scrabble-score/.meta/tests.toml b/exercises/practice/scrabble-score/.meta/tests.toml new file mode 100644 index 00000000..33a873c0 --- /dev/null +++ b/exercises/practice/scrabble-score/.meta/tests.toml @@ -0,0 +1,43 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[f46cda29-1ca5-4ef2-bd45-388a767e3db2] +description = "lowercase letter" + +[f7794b49-f13e-45d1-a933-4e48459b2201] +description = "uppercase letter" + +[eaba9c76-f9fa-49c9-a1b0-d1ba3a5b31fa] +description = "valuable letter" + +[f3c8c94e-bb48-4da2-b09f-e832e103151e] +description = "short word" + +[71e3d8fa-900d-4548-930e-68e7067c4615] +description = "short, valuable word" + +[d3088ad9-570c-4b51-8764-c75d5a430e99] +description = "medium word" + +[fa20c572-ad86-400a-8511-64512daac352] +description = "medium, valuable word" + +[9336f0ba-9c2b-4fa0-bd1c-2e2d328cf967] +description = "long, mixed-case word" + +[1e34e2c3-e444-4ea7-b598-3c2b46fd2c10] +description = "english-like word" + +[4efe3169-b3b6-4334-8bae-ff4ef24a7e4f] +description = "empty input" + +[3b305c1c-f260-4e15-a5b5-cb7d3ea7c3d7] +description = "entire alphabet available" diff --git a/exercises/practice/scrabble-score/scrabble-score-test.el b/exercises/practice/scrabble-score/scrabble-score-test.el new file mode 100644 index 00000000..94fddd9f --- /dev/null +++ b/exercises/practice/scrabble-score/scrabble-score-test.el @@ -0,0 +1,55 @@ +;;; scrabble-score-test.el --- Tests for Scrabble Score (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(load-file "scrabble-score.el") +(declare-function score "scrabble-score.el" (word)) + + +(ert-deftest lowercase-letter () + (should (equal 1 (score "a")))) + + +(ert-deftest uppercase-letter () + (should (equal 1 (score "A")))) + + +(ert-deftest valuable-letter () + (should (equal 4 (score "f")))) + + +(ert-deftest short-word () + (should (equal 2 (score "at")))) + + +(ert-deftest short-valuable-word () + (should (equal 12 (score "zoo")))) + + +(ert-deftest medium-word () + (should (equal 6 (score "street")))) + + +(ert-deftest medium-valuable-word () + (should (equal 22 (score "quirky")))) + + +(ert-deftest long-mixed-case-word () + (should (equal 41 (score "OxyphenButazone")))) + + +(ert-deftest english-like-word () + (should (equal 8 (score "pinata")))) + + +(ert-deftest empty-input () + (should (equal 0 (score "")))) + + +(ert-deftest entire-alphabet-available () + (should (equal 87 (score "abcdefghijklmnopqrstuvwxyz")))) + +(provide 'scrabble-score-test) +;;; scrabble-score-test.el ends here diff --git a/exercises/practice/scrabble-score/scrabble-score.el b/exercises/practice/scrabble-score/scrabble-score.el new file mode 100644 index 00000000..2f603452 --- /dev/null +++ b/exercises/practice/scrabble-score/scrabble-score.el @@ -0,0 +1,11 @@ +;;; scrabble-score.el --- Scrabble Score (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(defun score (word) + (error "Delete this S-Expression and write your own implementation")) + +(provide 'scrabble-score) +;;; scrabble-score.el ends here From 1125f95da06817427c0fb2be72046674e9887322 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Wed, 24 Apr 2024 03:18:24 +1000 Subject: [PATCH 048/162] Add tests.toml for Queen Attack exercise (closes #313) (#316) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add tests.toml for Queen Attack exercise (closes #313) * Empty commit --------- Co-authored-by: András B Nagy <20251272+BNAndras@users.noreply.github.com> --- .../practice/queen-attack/.meta/tests.toml | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 exercises/practice/queen-attack/.meta/tests.toml diff --git a/exercises/practice/queen-attack/.meta/tests.toml b/exercises/practice/queen-attack/.meta/tests.toml new file mode 100644 index 00000000..e0624123 --- /dev/null +++ b/exercises/practice/queen-attack/.meta/tests.toml @@ -0,0 +1,49 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[3ac4f735-d36c-44c4-a3e2-316f79704203] +description = "Test creation of Queens with valid and invalid positions -> queen with a valid position" + +[4e812d5d-b974-4e38-9a6b-8e0492bfa7be] +description = "Test creation of Queens with valid and invalid positions -> queen must have positive row" + +[f07b7536-b66b-4f08-beb9-4d70d891d5c8] +description = "Test creation of Queens with valid and invalid positions -> queen must have row on board" + +[15a10794-36d9-4907-ae6b-e5a0d4c54ebe] +description = "Test creation of Queens with valid and invalid positions -> queen must have positive column" + +[6907762d-0e8a-4c38-87fb-12f2f65f0ce4] +description = "Test creation of Queens with valid and invalid positions -> queen must have column on board" + +[33ae4113-d237-42ee-bac1-e1e699c0c007] +description = "Test the ability of one queen to attack another -> cannot attack" + +[eaa65540-ea7c-4152-8c21-003c7a68c914] +description = "Test the ability of one queen to attack another -> can attack on same row" + +[bae6f609-2c0e-4154-af71-af82b7c31cea] +description = "Test the ability of one queen to attack another -> can attack on same column" + +[0e1b4139-b90d-4562-bd58-dfa04f1746c7] +description = "Test the ability of one queen to attack another -> can attack on first diagonal" + +[ff9b7ed4-e4b6-401b-8d16-bc894d6d3dcd] +description = "Test the ability of one queen to attack another -> can attack on second diagonal" + +[0a71e605-6e28-4cc2-aa47-d20a2e71037a] +description = "Test the ability of one queen to attack another -> can attack on third diagonal" + +[0790b588-ae73-4f1f-a968-dd0b34f45f86] +description = "Test the ability of one queen to attack another -> can attack on fourth diagonal" + +[543f8fd4-2597-4aad-8d77-cbdab63619f8] +description = "Test the ability of one queen to attack another -> cannot attack if falling diagonals are only the same when reflected across the longest falling diagonal" From c711135c821b3c19649e4a6d87addbc920ea0c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:37:24 -0700 Subject: [PATCH 049/162] Update example.el relative path (#349) --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 3a51f988..db3653c4 100644 --- a/config.json +++ b/config.json @@ -21,7 +21,7 @@ "files": { "solution": ["%{kebab_slug}.el"], "test": ["%{kebab_slug}-test.el"], - "example": ["example.el"], + "example": [".meta/example.el"], "exemplar": [".meta/exemplar.el"] }, "exercises": { From 177d2fe98b2d0973f3f4a93f6d1d53687e3ee01b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:38:01 -0700 Subject: [PATCH 050/162] Sync pangram tests and update stub (#358) --- exercises/practice/pangram/pangram-test.el | 57 +++++++++++++--------- exercises/practice/pangram/pangram.el | 7 ++- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/exercises/practice/pangram/pangram-test.el b/exercises/practice/pangram/pangram-test.el index ef03a905..0486a060 100644 --- a/exercises/practice/pangram/pangram-test.el +++ b/exercises/practice/pangram/pangram-test.el @@ -1,42 +1,53 @@ -;;; pagram-test.el --- Tests for Pangram (exercism) -*- lexical-binding: t; -*- +;;; pangram-test.el --- Tests for Pangram (exercism) -*- lexical-binding: t; -*- ;;; Commentary: -;; Common test data version: 1.3.0 d79e13e ;;; Code: + (load-file "pangram.el") (declare-function pangramp "pangram.el" (phrase)) -(ert-deftest sentence-empty () - (should (equal nil (pangramp "")))) -(ert-deftest recognizes-a-perfect-lower-case-pangram () - (should (equal t (pangramp "abcdefghijklmnopqrstuvwxyz")))) +(ert-deftest empty-sentence () + (should-not (pangramp ""))) + + +(ert-deftest perfect-lower-case () + (should (pangramp "abcdefghijklmnopqrstuvwxyz"))) + + +(ert-deftest only-lower-case () + (should (pangramp "the quick brown fox jumps over the lazy dog"))) + + +(ert-deftest missing-the-letter-x () + (should-not (pangramp "a quick movement of the enemy will jeopardize five gunboats"))) + + +(ert-deftest missing-the-letter-h () + (should-not (pangramp "five boxing wizards jump quickly at it"))) + + +(ert-deftest with-underscores () + (should (pangramp "the_quick_brown_fox_jumps_over_the_lazy_dog"))) + -(ert-deftest pangram-with-only-lower-case () - (should (equal t (pangramp "the quick brown fox jumps over the lazy dog")))) +(ert-deftest with-numbers () + (should (pangramp "the 1 quick brown fox jumps over the 2 lazy dogs"))) -(ert-deftest missing-character-x () - (should (equal nil (pangramp "a quick movement of the enemy will jeopardize five gunboats")))) -(ert-deftest missing-another-character-eg-h () - (should (equal nil (pangramp "five boxing wizards jump quickly at it")))) +(ert-deftest missing-letters-replaced-by-numbers () + (should-not (pangramp "7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog"))) -(ert-deftest pangram-with-underscores () - (should (equal t (pangramp "the_quick_brown_fox_jumps_over_the_lazy_dog")))) -(ert-deftest pangram-with-numbers () - (should (equal t (pangramp "the 1 quick brown fox jumps over the 2 lazy dogs")))) +(ert-deftest mixed-case-and-punctuation () + (should (pangramp "\"Five quacking Zephyrs jolt my wax bed.\""))) -(ert-deftest missing-letters-replaced-by-numbers () - (should (equal nil (pangramp "7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog")))) -(ert-deftest pangram-with-mixed-case-and-punctuation () - (should (equal t (pangramp "\"Five quacking Zephyrs jolt my wax bed.\"")))) +(ert-deftest a-m-and-A-M-are-26-different-characters-but-not-a-pangram () + (should-not (pangramp "abcdefghijklm ABCDEFGHIJKLM"))) -(ert-deftest a-m-and-A-M-are-26-different-characters-but-not-a-pangram () - (should (equal nil (pangramp "abcdefghijklm ABCDEFGHIJKLM")))) (provide 'pangram-test) -;;; pagram-test.el ends here +;;; pangram-test.el ends here diff --git a/exercises/practice/pangram/pangram.el b/exercises/practice/pangram/pangram.el index 3ee08adb..333a9ad8 100644 --- a/exercises/practice/pangram/pangram.el +++ b/exercises/practice/pangram/pangram.el @@ -2,9 +2,12 @@ ;;; Commentary: -(defun pangramp (phrase) ;;; Code: -) + + +(defun pangramp (phrase) + (error "Delete this S-Expression and write your own implementation")) + (provide 'pangram) ;;; pangram.el ends here From 155854ee54e1684d0b65b97741437c56ca26ecfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:38:21 -0700 Subject: [PATCH 051/162] Sync nucleotide-count tests (#357) * Swap expected and result order * Add missing author * Format the stub * Revert "Swap expected and result order" This reverts commit 7083f8942c7ed3e04bb78872a80c3a67951c28ef. --- exercises/practice/nucleotide-count/.meta/config.json | 4 +++- exercises/practice/nucleotide-count/nucleotide-count.el | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/exercises/practice/nucleotide-count/.meta/config.json b/exercises/practice/nucleotide-count/.meta/config.json index 8e874d3e..ccbd7a31 100644 --- a/exercises/practice/nucleotide-count/.meta/config.json +++ b/exercises/practice/nucleotide-count/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": [], + "authors": [ + "cpaulbond" + ], "contributors": [ "canweriotnow" ], diff --git a/exercises/practice/nucleotide-count/nucleotide-count.el b/exercises/practice/nucleotide-count/nucleotide-count.el index 2dcb5c4f..bc12a923 100644 --- a/exercises/practice/nucleotide-count/nucleotide-count.el +++ b/exercises/practice/nucleotide-count/nucleotide-count.el @@ -2,9 +2,12 @@ ;;; Commentary: -(defun nucleotide-count (sequence) ;;; Code: -) + + +(defun nucleotide-count (sequence) + (error "Delete this S-Expression and write your own implementation")) + (provide 'nucleotide-count) ;;; nucleotide-count.el ends here From 2c79d076fd5a0d542ad2dd22dc5c16860b104010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:38:50 -0700 Subject: [PATCH 052/162] Sync roman-numerals tests (#356) * Add author from #39 * Sync tests and update stub --- .../practice/roman-numerals/.meta/config.json | 4 +- .../practice/roman-numerals/.meta/tests.toml | 33 +++-- .../roman-numerals/roman-numerals-test.el | 137 +++++++++++------- .../practice/roman-numerals/roman-numerals.el | 7 +- 4 files changed, 112 insertions(+), 69 deletions(-) diff --git a/exercises/practice/roman-numerals/.meta/config.json b/exercises/practice/roman-numerals/.meta/config.json index a775247e..502e22e7 100644 --- a/exercises/practice/roman-numerals/.meta/config.json +++ b/exercises/practice/roman-numerals/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": [], + "authors": [ + "cpaulbond" + ], "contributors": [ "bakhti", "canweriotnow", diff --git a/exercises/practice/roman-numerals/.meta/tests.toml b/exercises/practice/roman-numerals/.meta/tests.toml index ca142e9f..709011b5 100644 --- a/exercises/practice/roman-numerals/.meta/tests.toml +++ b/exercises/practice/roman-numerals/.meta/tests.toml @@ -30,6 +30,9 @@ description = "6 is VI" [ff3fb08c-4917-4aab-9f4e-d663491d083d] description = "9 is IX" +[6d1d82d5-bf3e-48af-9139-87d7165ed509] +description = "16 is XVI" + [2bda64ca-7d28-4c56-b08d-16ce65716cf6] description = "27 is XXVII" @@ -42,6 +45,9 @@ description = "49 is XLIX" [d5b283d4-455d-4e68-aacf-add6c4b51915] description = "59 is LIX" +[4465ffd5-34dc-44f3-ada5-56f5007b6dad] +description = "66 is LXVI" + [46b46e5b-24da-4180-bfe2-2ef30b39d0d0] description = "93 is XCIII" @@ -51,38 +57,35 @@ description = "141 is CXLI" [267f0207-3c55-459a-b81d-67cec7a46ed9] description = "163 is CLXIII" +[902ad132-0b4d-40e3-8597-ba5ed611dd8d] +description = "166 is CLXVI" + [cdb06885-4485-4d71-8bfb-c9d0f496b404] description = "402 is CDII" [6b71841d-13b2-46b4-ba97-dec28133ea80] description = "575 is DLXXV" +[dacb84b9-ea1c-4a61-acbb-ce6b36674906] +description = "666 is DCLXVI" + [432de891-7fd6-4748-a7f6-156082eeca2f] description = "911 is CMXI" [e6de6d24-f668-41c0-88d7-889c0254d173] description = "1024 is MXXIV" -[bb550038-d4eb-4be2-a9ce-f21961ac3bc6] -description = "3000 is MMM" - -[6d1d82d5-bf3e-48af-9139-87d7165ed509] -description = "16 is XVI" - -[4465ffd5-34dc-44f3-ada5-56f5007b6dad] -description = "66 is LXVI" - -[902ad132-0b4d-40e3-8597-ba5ed611dd8d] -description = "166 is CLXVI" - -[dacb84b9-ea1c-4a61-acbb-ce6b36674906] -description = "666 is DCLXVI" - [efbe1d6a-9f98-4eb5-82bc-72753e3ac328] description = "1666 is MDCLXVI" +[bb550038-d4eb-4be2-a9ce-f21961ac3bc6] +description = "3000 is MMM" + [3bc4b41c-c2e6-49d9-9142-420691504336] description = "3001 is MMMI" +[2f89cad7-73f6-4d1b-857b-0ef531f68b7e] +description = "3888 is MMMDCCCLXXXVIII" + [4e18e96b-5fbb-43df-a91b-9cb511fe0856] description = "3999 is MMMCMXCIX" diff --git a/exercises/practice/roman-numerals/roman-numerals-test.el b/exercises/practice/roman-numerals/roman-numerals-test.el index 7ca08586..5e83dc92 100644 --- a/exercises/practice/roman-numerals/roman-numerals-test.el +++ b/exercises/practice/roman-numerals/roman-numerals-test.el @@ -4,83 +4,118 @@ ;;; Code: + (load-file "roman-numerals.el") (declare-function to-roman "roman-numerals.el" (value)) -(ert-deftest to-roman-1 () - (should (equal (to-roman 1) "I"))) -(ert-deftest to-roman-2 () - (should (equal (to-roman 2) "II"))) +(ert-deftest 1-is-I () + (should (string= "I" (to-roman 1)))) + + +(ert-deftest 2-is-II () + (should (string= "II" (to-roman 2)))) + + +(ert-deftest 3-is-III () + (should (string= "III" (to-roman 3)))) + + +(ert-deftest 4-is-IV () + (should (string= "IV" (to-roman 4)))) + + +(ert-deftest 5-is-V () + (should (string= "V" (to-roman 5)))) + + +(ert-deftest 6-is-VI () + (should (string= "VI" (to-roman 6)))) + + +(ert-deftest 9-is-IX () + (should (string= "IX" (to-roman 9)))) + + +(ert-deftest 16-is-XVI () + (should (string= "XVI" (to-roman 16)))) + + +(ert-deftest 27-is-XXVII () + (should (string= "XXVII" (to-roman 27)))) + + +(ert-deftest 48-is-XLVIII () + (should (string= "XLVIII" (to-roman 48)))) + + +(ert-deftest 49-is-XLIX () + (should (string= "XLIX" (to-roman 49)))) + + +(ert-deftest 59-is-LIX () + (should (string= "LIX" (to-roman 59)))) + + +(ert-deftest 66-is-LXVI () + (should (string= "LXVI" (to-roman 66)))) + + +(ert-deftest 93-is-XCIII () + (should (string= "XCIII" (to-roman 93)))) + + +(ert-deftest 141-is-CXLI () + (should (string= "CXLI" (to-roman 141)))) + + +(ert-deftest 163-is-CLXIII () + (should (string= "CLXIII" (to-roman 163)))) -(ert-deftest to-roman-3 () - (should (equal (to-roman 3) "III"))) -(ert-deftest to-roman-4 () - (should (equal (to-roman 4) "IV"))) +(ert-deftest 166-is-CLXVI () + (should (string= (to-roman 166) "CLXVI"))) -(ert-deftest to-roman-5 () - (should (equal (to-roman 5) "V"))) -(ert-deftest to-roman-6 () - (should (equal (to-roman 6) "VI"))) +(ert-deftest 402-is-CDII () + (should (string= "CDII" (to-roman 402)))) -(ert-deftest to-roman-9 () - (should (equal (to-roman 9) "IX"))) -(ert-deftest to-roman-16 () - (should (equal (to-roman 16) "XVI"))) +(ert-deftest 575-is-DLXXV () + (should (string= "DLXXV" (to-roman 575)))) -(ert-deftest to-roman-27 () - (should (equal (to-roman 27) "XXVII"))) -(ert-deftest to-roman-48 () - (should (equal (to-roman 48) "XLVIII"))) +(ert-deftest 666-is-DCLXVI () + (should (string= "DCLXVI" (to-roman 666)))) -(ert-deftest to-roman-59 () - (should (equal (to-roman 59) "LIX"))) -(ert-deftest to-roman-66 () - (should (equal (to-roman 66) "LXVI"))) +(ert-deftest 911-is-CMXI () + (should (string= "CMXI" (to-roman 911)))) -(ert-deftest to-roman-93 () - (should (equal (to-roman 93) "XCIII"))) -(ert-deftest to-roman-141 () - (should (equal (to-roman 141) "CXLI"))) +(ert-deftest 1024-is-MXXIV () + (should (string= "MXXIV" (to-roman 1024)))) -(ert-deftest to-roman-163 () - (should (equal (to-roman 163) "CLXIII"))) -(ert-deftest to-roman-166 () - (should (equal (to-roman 166) "CLXVI"))) +(ert-deftest 1666-is-MDCLXVI () + (should (string= "MDCLXVI" (to-roman 1666)))) -(ert-deftest to-roman-402 () - (should (equal (to-roman 402) "CDII"))) -(ert-deftest to-roman-575 () - (should (equal (to-roman 575) "DLXXV"))) +(ert-deftest 3000-is-MMM () + (should (string= "MMM" (to-roman 3000)))) -(ert-deftest to-roman-666 () - (should (equal (to-roman 666) "DCLXVI"))) -(ert-deftest to-roman-911 () - (should (equal (to-roman 911) "CMXI"))) +(ert-deftest 3001-is-MMMI () + (should (string= "MMMI" (to-roman 3001)))) -(ert-deftest to-roman-1024 () - (should (equal (to-roman 1024) "MXXIV"))) -(ert-deftest to-roman-1666 () - (should (equal (to-roman 1666) "MDCLXVI"))) +(ert-deftest 3888-is-MMMDCCCLXXXVIII () + (should (string= "MMMDCCCLXXXVIII" (to-roman 3888)))) -(ert-deftest to-roman-3000 () - (should (equal (to-roman 3000) "MMM"))) -(ert-deftest to-roman-3001 () - (should (equal (to-roman 3001) "MMMI"))) +(ert-deftest 3999-is-MMMCMXCIX () + (should (string= "MMMCMXCIX" (to-roman 3999 )))) -(ert-deftest to-roman-3999 () - (should (equal (to-roman 3999) "MMMCMXCIX"))) -(provide 'roman-numerals) +(provide 'roman-numerals-test) ;;; roman-numerals-test.el ends here diff --git a/exercises/practice/roman-numerals/roman-numerals.el b/exercises/practice/roman-numerals/roman-numerals.el index 0a6884bb..ccba2def 100644 --- a/exercises/practice/roman-numerals/roman-numerals.el +++ b/exercises/practice/roman-numerals/roman-numerals.el @@ -2,9 +2,12 @@ ;;; Commentary: -(defun to-roman (value) ;;; Code: -) + + +(defun to-roman (value) + (error "Delete this S-Expression and write your own implementation")) + (provide 'roman-numerals) ;;; roman-numerals.el ends here From 32c274c648ea17a8e061dfbc672e22f0be86a667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:39:04 -0700 Subject: [PATCH 053/162] Sync armstrong-number tests (#353) * Sync armstrong-number tests * Update stub formatting --- .../armstrong-numbers-test.el | 38 +++++++++++++------ .../armstrong-numbers/armstrong-numbers.el | 7 +++- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/exercises/practice/armstrong-numbers/armstrong-numbers-test.el b/exercises/practice/armstrong-numbers/armstrong-numbers-test.el index 3e5e7910..e96849dd 100644 --- a/exercises/practice/armstrong-numbers/armstrong-numbers-test.el +++ b/exercises/practice/armstrong-numbers/armstrong-numbers-test.el @@ -7,44 +7,58 @@ (load-file "armstrong-numbers.el") (declare-function armstrong-p "armstrong-numbers.el" (n)) +(ert-deftest armstrong-number-0 () + "Zero is an Armstrong number" + (should (armstrong-p 0))) + (ert-deftest armstrong-number-5 () - "Single digit numbers are Armstrong numbers" + "Single-digit numbers are Armstrong numbers" (should (armstrong-p 5))) + (ert-deftest not-armstrong-number-10 () - "There are no 2 digit Armstrong numbers" - (should (not (armstrong-p 10)))) + "There are no two-digit Armstrong numbers" + (should-not (armstrong-p 10))) + (ert-deftest armstrong-number-153 () - "Three digit number that should an Armstrong number" + "Three-digit number that is an Armstrong number" (should (armstrong-p 153))) + (ert-deftest not-armstrong-number-100 () - "Three digit number that should an Armstrong number" - (should (not (armstrong-p 100)))) + "Three-digit number that is not an Armstrong number" + (should-not (armstrong-p 100))) + (ert-deftest armstrong-number-9474 () - "Four digit number that should an Armstrong number" + "Four-digit number that is an Armstrong number" (should (armstrong-p 9474))) + (ert-deftest not-armstrong-number-9475 () - "Four digit number that should not an Armstrong number" - (should (not (armstrong-p 9476)))) + "Four-digit number that is not an Armstrong number" + (should-not (armstrong-p 9476))) + (ert-deftest armstrong-number-9926315 () - "Seven digit number that should an Armstrong number" + "Seven-digit number that is an Armstrong number" (should (armstrong-p 9926315))) + (ert-deftest not-armstrong-number-9926314 () - "Seven digit number that should not an Armstrong number" - (should (not (armstrong-p 9926314)))) + "Seven-digit number that is not an Armstrong number" + (should-not (armstrong-p 9926314))) + (ert-deftest armstrong-number-186709961001538790100634132976990 () "Armstrong number containing seven zeroes that should be an Armstrong number" (should (armstrong-p 186709961001538790100634132976990))) + (ert-deftest armstrong-number-115132219018763992565095597973971522401 () "The largest and last Armstrong number should be an Armstrong number" (should (armstrong-p 115132219018763992565095597973971522401))) +(provide 'armstrong-numbers-test) ;;; armstrong-numbers-test.el ends here diff --git a/exercises/practice/armstrong-numbers/armstrong-numbers.el b/exercises/practice/armstrong-numbers/armstrong-numbers.el index 69bbb2cf..f9372602 100644 --- a/exercises/practice/armstrong-numbers/armstrong-numbers.el +++ b/exercises/practice/armstrong-numbers/armstrong-numbers.el @@ -2,9 +2,12 @@ ;;; Commentary: -(defun armstrong-p (n) ;;; Code: -) + + +(defun armstrong-p (n) + (error "Delete this S-Expression and write your own implementation")) + (provide 'armstrong-numbers) ;;; armstrong-numbers.el ends here From f4d080fd2ae4df1cbb191d45b5c45a3b80bb3b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:39:26 -0700 Subject: [PATCH 054/162] Sync raindrops tests (#354) * Sync raindrops tests * Revert result vs expected order * Format stub --- .../practice/raindrops/raindrops-test.el | 104 ++++++++++-------- exercises/practice/raindrops/raindrops.el | 8 +- 2 files changed, 64 insertions(+), 48 deletions(-) diff --git a/exercises/practice/raindrops/raindrops-test.el b/exercises/practice/raindrops/raindrops-test.el index b04c71aa..6fb0ccc7 100644 --- a/exercises/practice/raindrops/raindrops-test.el +++ b/exercises/practice/raindrops/raindrops-test.el @@ -4,68 +4,82 @@ ;;; Code: + (load-file "raindrops.el") (declare-function convert "raindrops.el" (n)) -(ert-deftest test-1 () - (should (equal "1" - (convert 1)))) -(ert-deftest test-3 () - (should (equal "Pling" - (convert 3)))) +(ert-deftest the-sound-for-1-is-1 () + (should (string= (convert 1) "1"))) + + +(ert-deftest the-sound-for-3-is-Pling () + (should (string= (convert 3) "Pling"))) + + +(ert-deftest the-sound-for-5-is-Plang () + (should (string= (convert 5) "Plang"))) + + +(ert-deftest the-sound-for-7-is-Plong () + (should (string= (convert 7) "Plong"))) + + +(ert-deftest the-sound-for-6-is-Pling () + (should (string= (convert 6) "Pling" ))) + + +(ert-deftest the-sound-for-8-is-8 () + (should (string= (convert 8) "8"))) + + +(ert-deftest the-sound-for-9-is-Pling () + (should (string= (convert 9) "Pling" ))) + + +(ert-deftest the-sound-for-10-is-Plang () + (should (string= (convert 10) "Plang"))) + + +(ert-deftest the-sound-for-14-is-Plong () + (should (string= (convert 14) "Plong"))) + + +(ert-deftest the-sound-for-15-is-PlingPlong () + (should (string= (convert 15) "PlingPlang"))) + + +(ert-deftest the-sound-for-21-is-PlingPlong () + (should (string= (convert 21) "PlingPlong"))) + + +(ert-deftest the-sound-for-25-is-Plang () + (should (string= (convert 25) "Plang"))) -(ert-deftest test-5 () - (should (equal "Plang" - (convert 5)))) -(ert-deftest test-7 () - (should (equal "Plong" - (convert 7)))) +(ert-deftest the-sound-for-27-is-Pling () + (should (string= (convert 27) "Pling"))) -(ert-deftest test-6 () - (should (equal "Pling" - (convert 6)))) -(ert-deftest test-9 () - (should (equal "Pling" - (convert 9)))) +(ert-deftest the-sound-for-35-is-PlangPlong () + (should (string= (convert 35) "PlangPlong"))) -(ert-deftest test-10 () - (should (equal "Plang" - (convert 10)))) -(ert-deftest test-15 () - (should (equal "PlingPlang" - (convert 15)))) +(ert-deftest the-sound-for-49-is-Plong () + (should (string= (convert 49) "Plong"))) -(ert-deftest test-21 () - (should (equal "PlingPlong" - (convert 21)))) -(ert-deftest test-25 () - (should (equal "Plang" - (convert 25)))) +(ert-deftest the-sound-for-52-is-52 () + (should (string= (convert 52) "52"))) -(ert-deftest test-35 () - (should (equal "PlangPlong" - (convert 35)))) -(ert-deftest test-49 () - (should (equal "Plong" - (convert 49)))) +(ert-deftest the-sound-for-105-is-PlingPlangPlong () + (should (string= (convert 105) "PlingPlangPlong"))) -(ert-deftest test-52 () - (should (equal "52" - (convert 52)))) -(ert-deftest test-105 () - (should (equal "PlingPlangPlong" - (convert 105)))) +(ert-deftest the-sound-for-3125-is-Plang () + (should (string= (convert 3125) "Plang"))) -(ert-deftest test-12121 () - (should (equal "12121" - (convert 12121)))) (provide 'raindrops-test) ;;; raindrops-test.el ends here diff --git a/exercises/practice/raindrops/raindrops.el b/exercises/practice/raindrops/raindrops.el index a8a4e179..73c97951 100644 --- a/exercises/practice/raindrops/raindrops.el +++ b/exercises/practice/raindrops/raindrops.el @@ -2,10 +2,12 @@ ;;; Commentary: -(defun convert (n) - "Convert integer N to its raindrops string." ;;; Code: -) + + +(defun convert (n) + (error "Delete this S-Expression and write your own implementation")) + (provide 'raindrops) ;;; raindrops.el ends here From 88e7e13fad0a83d73e001adbce89a0b63ec6b99e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:39:41 -0700 Subject: [PATCH 055/162] Update generator to use configlet create (#347) --- bin/generate_practice_exercise | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/bin/generate_practice_exercise b/bin/generate_practice_exercise index fabc2646..6bc91fa5 100755 --- a/bin/generate_practice_exercise +++ b/bin/generate_practice_exercise @@ -35,16 +35,7 @@ echo "Fetching latest version of configlet..." # Preparing config.json echo "Adding instructions and configuration files..." -UUID=$(bin/configlet uuid) -jq --arg slug "$SLUG" --arg uuid "$UUID" \ - '.exercises.practice += [{slug: $slug, name: "TODO", uuid: $uuid, practices: [], prerequisites: [], difficulty: 5}]' \ - config.json > config.json.tmp -# jq always rounds whole numbers, but average_run_time needs to be a float -sed -i 's/"average_run_time": \([[:digit:]]\+\)$/"average_run_time": 2.0/' config.json.tmp -mv config.json.tmp config.json - -# Create instructions and config files -./bin/configlet sync --update --yes --docs --filepaths --metadata --exercise "$SLUG" +./bin/configlet create --practice-exercise "$SLUG" pushd tools emacs -batch -l install-packages.el -l practice-exercise-generator.el --eval "(exercism/generate-practice-exercise \"$SLUG\")" From 1a5f8c64237fbc53b5efb6c90d4dc9a476508f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:39:54 -0700 Subject: [PATCH 056/162] Sync anagram tests (#352) * Sync anagram tests * Update stub formatting * Swap expected vs result order --- exercises/practice/anagram/.meta/tests.toml | 5 + exercises/practice/anagram/anagram-test.el | 114 ++++++++++++-------- exercises/practice/anagram/anagram.el | 7 +- 3 files changed, 78 insertions(+), 48 deletions(-) diff --git a/exercises/practice/anagram/.meta/tests.toml b/exercises/practice/anagram/.meta/tests.toml index c271593a..9b6126a3 100644 --- a/exercises/practice/anagram/.meta/tests.toml +++ b/exercises/practice/anagram/.meta/tests.toml @@ -45,6 +45,11 @@ description = "detects anagrams using case-insensitive possible matches" [7cc195ad-e3c7-44ee-9fd2-d3c344806a2c] description = "does not detect an anagram if the original word is repeated" +include = false + +[630abb71-a94e-4715-8395-179ec1df9f91] +description = "does not detect an anagram if the original word is repeated" +reimplements = "7cc195ad-e3c7-44ee-9fd2-d3c344806a2c" [9878a1c9-d6ea-4235-ae51-3ea2befd6842] description = "anagrams must use all letters exactly once" diff --git a/exercises/practice/anagram/anagram-test.el b/exercises/practice/anagram/anagram-test.el index 923616b2..74234aee 100644 --- a/exercises/practice/anagram/anagram-test.el +++ b/exercises/practice/anagram/anagram-test.el @@ -4,69 +4,91 @@ ;;; Code: + (load-file "anagram.el") (declare-function anagrams-for "anagram.el" (subject candidates)) + (ert-deftest no-matches () - (should (equal '() (anagrams-for - "diaper" - '("hello" "world" "zombies" "pants"))))) + (should (equal (anagrams-for "diaper" '("hello" "world" "zombies" "pants")) + '()))) + + +(ert-deftest detects-two-anagrams () + (should (equal (anagrams-for "solemn" '("lemons" "cherry" "melons")) + '("lemons" "melons")))) -(ert-deftest detect-simple-anagram () - (should (equal '("tan") (anagrams-for - "ant" - '("tan" "stand" "at"))))) -(ert-deftest does-not-confuse-different-duplicates () - (should (equal '() (anagrams-for - "galea" - '("eagle"))))) +(ert-deftest does-not-detect-anagram-subsets () + (should (equal (anagrams-for "good" '("dog" "goody")) + '()))) -(ert-deftest eliminate-anagram-subsets () - (should (equal '() (anagrams-for - "good" - '("dog" "goody"))))) (ert-deftest detect-anagram () - (should (equal '("inlets") (anagrams-for - "listen" - '("enlists" "google" "inlets" "banana"))))) - -(ert-deftest multiple-anagrams () - (should (equal '("gallery" "regally" "largely") - (anagrams-for - "allergy" - '("gallery" "ballerina" "regally" "clergy" "largely" "leading"))))) - -(ert-deftest case-insensitive-anagrams () - (should (equal '("Carthorse") - (anagrams-for - "Orchestra" - '("cashregister" "Carthorse" "radishes"))))) + (should (equal (anagrams-for "listen" '("enlists" "google" "inlets" "banana")) + '("inlets")))) + + +(ert-deftest detects-three-anagrams () + (should (equal (anagrams-for "allergy" + '("gallery" "ballerina" "regally" "clergy" "largely" "leading")) + '("gallery" "regally" "largely")))) + + +(ert-deftest detects-multiple-anagrams-with-different-case () + (should (equal (anagrams-for "nose" '("Eons" "ONES")) + '("Eons" "ONES")))) + + +(ert-deftest does-not-detect-non-anagram-with-identical-checksum () + (should (equal (anagrams-for "mass" '("last")) + '()))) + + +(ert-deftest detects-anagrams-case-insensitively () + (should (equal (anagrams-for "Orchestra" '("cashregister" "Carthorse" "radishes")) + '("Carthorse")))) + + +(ert-deftest detects-anagrams-using-case-insensitive-subject () + (should (equal (anagrams-for "Orchestra" '("cashregister" "carthorse" "radishes")) + '("carthorse")))) + + +(ert-deftest detects-anagrams-using-case-insensitive-possible-matches () + (should (equal (anagrams-for "orchestra" '("cashregister" "Carthorse" "radishes")) + '("Carthorse")))) + + +(ert-deftest does-not-detect-anagram-if-original-word-is-repeated () + (should (equal (anagrams-for "go" '("goGoGO")) + '()))) + + +(ert-deftest anagrams-must-use-all-letters-exactly-once () + (should (equal (anagrams-for "tapper" '("patter")) + '()))) + (ert-deftest word-is-not-own-anagram () - (should (equal '() - (anagrams-for - "BANANA" - '("BANANA"))))) + (should (equal (anagrams-for "BANANA" '("BANANA")) + '()))) + (ert-deftest word-is-not-own-anagram-if-letter-case-is-partially-different () - (should (equal '() - (anagrams-for - "BANANA" - '("Banana"))))) + (should (equal (anagrams-for "BANANA" '("Banana")) + '()))) + (ert-deftest word-is-not-own-anagram-if-letter-case-is-completely-different () - (should (equal '() - (anagrams-for - "BANANA" - '("banana"))))) + (should (equal (anagrams-for "BANANA" '("banana")) + '()))) + (ert-deftest words-other-than-themselves-can-be-anagrams () - (should (equal '("Silent") - (anagrams-for - "LISTEN" - '("Listen" "Silent" "LISTEN"))))) + (should (equal (anagrams-for "LISTEN" '("LISTEN" "Silent")) + '("Silent")))) + (provide 'anagram-test) ;;; anagram-test.el ends here diff --git a/exercises/practice/anagram/anagram.el b/exercises/practice/anagram/anagram.el index dfd94bf5..b13f44f4 100644 --- a/exercises/practice/anagram/anagram.el +++ b/exercises/practice/anagram/anagram.el @@ -2,9 +2,12 @@ ;;; Commentary: -(defun anagrams-for (subject candidates) ;;; Code: -) + + +(defun anagrams-for (subject candidates) + (error "Delete this S-Expression and write your own implementation")) + (provide 'anagram) ;;; anagram.el ends here From 00af9da5524829365acf70dbb88a1730d66bfe00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:40:08 -0700 Subject: [PATCH 057/162] Sync allergies tests (#351) * Sync allergies tests * Update stub formatting * Swap result vs. expected --- .../practice/allergies/allergies-test.el | 236 +++++++++++++++--- exercises/practice/allergies/allergies.el | 13 +- 2 files changed, 211 insertions(+), 38 deletions(-) diff --git a/exercises/practice/allergies/allergies-test.el b/exercises/practice/allergies/allergies-test.el index 834728cb..219be04c 100644 --- a/exercises/practice/allergies/allergies-test.el +++ b/exercises/practice/allergies/allergies-test.el @@ -4,55 +4,227 @@ ;;; Code: + (load-file "allergies.el") (declare-function allergen-list "allergies.el" (score)) (declare-function allergic-to-p "allergies.el" (score allergen)) -(ert-deftest no-allergies-at-all () - (should (equal '() (allergen-list 0)))) -(ert-deftest allergic-to-just-eggs () - (should (equal '("eggs") (allergen-list 1)))) +(ert-deftest eggs-not-allergic-to-anything () + (should-not (allergic-to-p 0 "eggs"))) + + +(ert-deftest eggs-allergic-only-to-eggs () + (should (allergic-to-p 1 "eggs"))) + + +(ert-deftest eggs-allergic-to-eggs-and-something-else () + (should (allergic-to-p 3 "eggs"))) + + +(ert-deftest eggs-allergic-to-something-but-not-eggs () + (should-not (allergic-to-p 2 "eggs"))) + + +(ert-deftest eggs-allergic-to-everything () + (should (allergic-to-p 255 "eggs"))) + + +(ert-deftest peanuts-not-allergic-to-anything () + (should-not (allergic-to-p 0 "peanuts"))) + + +(ert-deftest peanuts-allergic-only-to-peanuts () + (should (allergic-to-p 2 "peanuts"))) + + +(ert-deftest peanuts-allergic-to-peanuts-and-something-else () + (should (allergic-to-p 7 "peanuts"))) + + +(ert-deftest peanuts-allergic-to-something-but-not-peanuts () + (should-not (allergic-to-p 5 "peanuts"))) + + +(ert-deftest peanuts-allergic-to-everything () + (should (allergic-to-p 255 "peanuts"))) + + +(ert-deftest shellfish-not-allergic-to-anything () + (should-not (allergic-to-p 0 "shellfish"))) + -(ert-deftest allergic-to-just-peanuts () - (should (equal '("peanuts") (allergen-list 2)))) +(ert-deftest shellfish-allergic-only-to-shellfish () + (should (allergic-to-p 4 "shellfish"))) -(ert-deftest allergic-to-just-strawberries () - (should (equal '("strawberries") (allergen-list 8)))) -(ert-deftest allergic-to-eggs-and-peanuts () - (should (equal '("eggs" "peanuts") (allergen-list 3)))) +(ert-deftest shellfish-allergic-to-shellfish-and-something-else () + (should (allergic-to-p 14 "shellfish"))) -(ert-deftest allergic-to-more-than-eggs-but-not-peanuts () - (should (equal '("eggs" "shellfish") (allergen-list 5)))) -(ert-deftest allergic-to-lots-of-stuff () - (should (equal '("strawberries" "tomatoes" "chocolate" "pollen" "cats") - (allergen-list 248)))) +(ert-deftest shellfish-allergic-to-something-but-not-shellfish () + (should-not (allergic-to-p 10 "shellfish"))) -(ert-deftest allergic-to-everything () - (should (equal '("eggs" "peanuts" "shellfish" "strawberries" "tomatoes" - "chocolate" "pollen" "cats") - (allergen-list 255)))) -(ert-deftest no-allergies-means-not-allergic () - (should-not (allergic-to-p 0 "peanuts")) - (should-not (allergic-to-p 0 "cats")) +(ert-deftest shellfish-allergic-to-everything () + (should (allergic-to-p 255 "shellfish"))) + + +(ert-deftest strawberries-not-allergic-to-anything () (should-not (allergic-to-p 0 "strawberries"))) -(ert-deftest is-allergic-to-eggs () - (should (allergic-to-p 1 "eggs"))) -(ert-deftest allergic-to-eggs-and-other-stuff () - (should (allergic-to-p 5 "eggs"))) +(ert-deftest strawberries-allergic-only-to-strawberries () + (should (allergic-to-p 8 "strawberries"))) + + +(ert-deftest strawberries-allergic-to-strawberries-and-something-else () + (should (allergic-to-p 28 "strawberries"))) + + +(ert-deftest strawberries-allergic-to-something-but-not-strawberries () + (should-not (allergic-to-p 20 "strawberries"))) + + +(ert-deftest strawberries-allergic-to-everything () + (should (allergic-to-p 255 "strawberries"))) + + +(ert-deftest tomatoes-not-allergic-to-anything () + (should-not (allergic-to-p 0 "tomatoes"))) + + +(ert-deftest tomatoes-allergic-only-to-tomatoes () + (should (allergic-to-p 16 "tomatoes"))) + + +(ert-deftest tomatoes-allergic-to-tomatoes-and-something-else () + (should (allergic-to-p 56 "tomatoes"))) + + +(ert-deftest tomatoes-allergic-to-something-but-not-tomatoes () + (should-not (allergic-to-p 40 "tomatoes"))) + + +(ert-deftest tomatoes-allergic-to-everything () + (should (allergic-to-p 255 "tomatoes"))) + + +(ert-deftest chocolate-not-allergic-to-anything () + (should-not (allergic-to-p 0 "chocolate"))) + + +(ert-deftest chocolate-allergic-only-to-chocolate () + (should (allergic-to-p 32 "chocolate"))) + + +(ert-deftest chocolate-allergic-to-chocolate-and-something-else () + (should (allergic-to-p 112 "chocolate"))) + + +(ert-deftest chocolate-allergic-to-something-but-not-chocolate () + (should-not (allergic-to-p 80 "chocolate"))) + + +(ert-deftest chocolate-allergic-to-everything () + (should (allergic-to-p 255 "chocolate"))) + + +(ert-deftest pollen-not-allergic-to-anything () + (should-not (allergic-to-p 0 "pollen"))) + + +(ert-deftest pollen-allergic-only-to-pollen () + (should (allergic-to-p 64 "pollen"))) + + +(ert-deftest pollen-allergic-to-pollen-and-something-else () + (should (allergic-to-p 224 "pollen"))) + + +(ert-deftest pollen-allergic-to-something-but-not-pollen () + (should-not (allergic-to-p 160 "pollen"))) + + +(ert-deftest pollen-allergic-to-everything () + (should (allergic-to-p 255 "pollen"))) + + +(ert-deftest cats-not-allergic-to-anything () + (should-not (allergic-to-p 0 "cats"))) + + +(ert-deftest cats-allergic-only-to-cats () + (should (allergic-to-p 128 "cats"))) + + +(ert-deftest cats-allergic-to-cats-and-something-else () + (should (allergic-to-p 192 "cats"))) + + +(ert-deftest cats-allergic-to-something-but-not-cats () + (should-not (allergic-to-p 64 "cats"))) + + +(ert-deftest cats-allergic-to-everything () + (should (allergic-to-p 255 "cats"))) + + +(ert-deftest list-when-no-allergies-at-all () + (should (equal (allergen-list 0) '()))) + + +(ert-deftest list-when-allergic-to-just-eggs () + (should (equal (allergen-list 1) '("eggs")))) + + +(ert-deftest list-when-allergic-to-just-peanuts () + (should (equal (allergen-list 2) '("peanuts")))) + + +(ert-deftest list-when-allergic-to-just-strawberries () + (should (equal (allergen-list 8) '("strawberries")))) + + +(ert-deftest list-when-allergic-to-eggs-and-peanuts () + (should (equal (allergen-list 3) '("eggs" "peanuts")))) + + +(ert-deftest list-when-allergic-to-more-than-eggs-but-not-peanuts () + (should (equal (allergen-list 5) '("eggs" "shellfish")))) + + +(ert-deftest list-when-allergic-to-lots-of-stuff () + (should (equal (allergen-list 248) + '("strawberries" "tomatoes" "chocolate" "pollen" "cats")))) + + +(ert-deftest list-when-allergic-to-everything () + (should (equal (allergen-list 255) + '("eggs" + "peanuts" + "shellfish" + "strawberries" + "tomatoes" + "chocolate" + "pollen" + "cats")))) + (ert-deftest ignore-non-allergen-score-parts () - (should (equal '("eggs" "shellfish" "strawberries" "tomatoes" - "chocolate" "pollen" "cats") - (allergen-list 509)))) + (should (equal (allergen-list 509) + '("eggs" + "shellfish" + "strawberries" + "tomatoes" + "chocolate" + "pollen" + "cats")))) + + +(ert-deftest list-when-no-allergen-score-parts-without-highest-valid-score () + (should (equal (allergen-list 257) '("eggs")))) -(ert-deftest no-allergen-score-parts-without-highest-valid-score () - (should (equal '("eggs") (allergen-list 257)))) -(provide 'allergies) +(provide 'allergies-tests) ;;; allergies-test.el ends here diff --git a/exercises/practice/allergies/allergies.el b/exercises/practice/allergies/allergies.el index 7d42a6e8..4de88fa9 100644 --- a/exercises/practice/allergies/allergies.el +++ b/exercises/practice/allergies/allergies.el @@ -2,15 +2,16 @@ ;;; Commentary: -(defun allergen-list (score) -"List all allergens with a given SCORE." ;;; Code: -) + + +(defun allergen-list (score) + (error "Delete this S-Expression and write your own implementation")) + (defun allergic-to-p (score allergen) -"Check if Allergic to allergen based on SCORE and ALLERGEN." -;;; Code: -) + (error "Delete this S-Expression and write your own implementation")) + (provide 'allergies) ;;; allergies.el ends here From e856aa2f760ed59cfbcc5c08bfa8676ff893f004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:40:22 -0700 Subject: [PATCH 058/162] Sync acronym tests (#350) * Sync acronym tests * Apply consistent formatting and string= * Apply formatting to stub and tests * Swap result vs. expected --- exercises/practice/acronym/.meta/example.el | 2 +- exercises/practice/acronym/acronym-test.el | 45 ++++++++++++++++----- exercises/practice/acronym/acronym.el | 6 ++- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/exercises/practice/acronym/.meta/example.el b/exercises/practice/acronym/.meta/example.el index b38cf7b3..83241be0 100644 --- a/exercises/practice/acronym/.meta/example.el +++ b/exercises/practice/acronym/.meta/example.el @@ -7,7 +7,7 @@ (require 'cl-lib) (defun acronym (input) - (let ((words (split-string input "\\W+"))) + (let ((words (split-string (string-replace "'" "" input) "\\W+"))) (mapconcat (lambda (word) (upcase (substring word 0 1))) words ""))) (provide 'acronym) diff --git a/exercises/practice/acronym/acronym-test.el b/exercises/practice/acronym/acronym-test.el index aa9678bc..b9b98b7e 100644 --- a/exercises/practice/acronym/acronym-test.el +++ b/exercises/practice/acronym/acronym-test.el @@ -4,26 +4,53 @@ ;;; Code + (load-file "acronym.el") (declare-function acronym "acronym.el" (phrase)) + (ert-deftest basic () - (should (equal "PNG" (acronym "Portable Network Graphics")))) + (should (string= (acronym "Portable Network Graphics") + "PNG"))) + (ert-deftest lowercase-words () - (should (equal "ROR" (acronym "Ruby on Rails")))) + (should (string= (acronym "Ruby on Rails") + "ROR"))) + (ert-deftest punctuation () - (should (equal "FIFO" (acronym "First In, First Out")))) + (should (string= (acronym "First In, First Out") + "FIFO"))) + + +(ert-deftest all-caps-word () + (should (string= (acronym "GNU Image Manipulation Program") + "GIMP"))) + + +(ert-deftest punctuation-without-white-space () + (should (string= (acronym "Complementary metal-oxide semiconductor") + "CMOS"))) + + +(ert-deftest very-long-abbreviation () + (should (string= (acronym "Rolling On The Floor Laughing So Hard That My Dogs Came Over And Licked Me") + "ROTFLSHTMDCOALM"))) + + +(ert-deftest consecutive-delimiters () + (should (string= (acronym "Something - I made up from thin air") + "SIMUFTA"))) + + +(ert-deftest apostrophes () + (should (string= (acronym "Halley's Comet") "HC"))) -(ert-deftest all-caps-words () - (should (equal "PHP" (acronym "PHP: Hypertext Preprocessor")))) -(ert-deftest non-acronym-all-caps-word () - (should (equal "GIMP" (acronym "GNU Image Manipulation Program")))) +(ert-deftest underscore-emphasis () + (should (string= (acronym "The Road _Not_ Taken") "TRNT"))) -(ert-deftest hyphenated () - (should (equal "CMOS" (acronym "Complementary metal-oxide semiconductor")))) (provide 'acronym-test) ;;; acronym-test.el ends here diff --git a/exercises/practice/acronym/acronym.el b/exercises/practice/acronym/acronym.el index d6216c4f..f04d7115 100644 --- a/exercises/practice/acronym/acronym.el +++ b/exercises/practice/acronym/acronym.el @@ -2,9 +2,11 @@ ;;; Commentary: -(defun acronym (phrase) ;;; Code: -) + + +(defun acronym (phrase) + (error "Delete this S-Expression and write your own implementation")) (provide 'acronym) ;;; acronym.el ends here From fb4a9dd35ce2e1649933593728aa643cc705becb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:40:40 -0700 Subject: [PATCH 059/162] Sync exercise docs (#326) * Sync exercise docs * Sync additional docs * Sync additional docs --- .../practice/acronym/.docs/instructions.md | 10 ++-- .../affine-cipher/.docs/instructions.md | 4 +- .../practice/allergies/.docs/instructions.md | 2 +- .../armstrong-numbers/.docs/instructions.md | 4 +- .../binary-search/.docs/instructions.md | 2 +- .../practice/darts/.docs/instructions.md | 12 ++++- exercises/practice/darts/.meta/config.json | 2 +- .../flatten-array/.docs/instructions.md | 2 +- .../practice/hello-world/.meta/config.json | 2 +- .../practice/list-ops/.docs/instructions.md | 18 ++++--- .../matching-brackets/.docs/instructions.md | 3 +- .../matching-brackets/.docs/introduction.md | 8 +++ .../perfect-numbers/.docs/instructions.md | 53 ++++++++++++------- .../phone-number/.docs/instructions.md | 10 ++-- .../queen-attack/.docs/instructions.md | 20 +++---- .../practice/raindrops/.meta/config.json | 2 +- .../rotational-cipher/.docs/instructions.md | 4 +- 17 files changed, 95 insertions(+), 63 deletions(-) create mode 100644 exercises/practice/matching-brackets/.docs/introduction.md diff --git a/exercises/practice/acronym/.docs/instructions.md b/exercises/practice/acronym/.docs/instructions.md index c62fc3e8..133bd2cb 100644 --- a/exercises/practice/acronym/.docs/instructions.md +++ b/exercises/practice/acronym/.docs/instructions.md @@ -10,8 +10,8 @@ Punctuation is handled as follows: hyphens are word separators (like whitespace) For example: -|Input|Output| -|-|-| -|As Soon As Possible|ASAP| -|Liquid-crystal display|LCD| -|Thank George It's Friday!|TGIF| +| Input | Output | +| ------------------------- | ------ | +| As Soon As Possible | ASAP | +| Liquid-crystal display | LCD | +| Thank George It's Friday! | TGIF | diff --git a/exercises/practice/affine-cipher/.docs/instructions.md b/exercises/practice/affine-cipher/.docs/instructions.md index 2ad6d152..26ce1534 100644 --- a/exercises/practice/affine-cipher/.docs/instructions.md +++ b/exercises/practice/affine-cipher/.docs/instructions.md @@ -6,7 +6,7 @@ The affine cipher is a type of monoalphabetic substitution cipher. Each character is mapped to its numeric equivalent, encrypted with a mathematical function and then converted to the letter relating to its new numeric value. Although all monoalphabetic ciphers are weak, the affine cipher is much stronger than the atbash cipher, because it has many more keys. -[//]: # ( monoalphabetic as spelled by Merriam-Webster, compare to polyalphabetic ) +[//]: # " monoalphabetic as spelled by Merriam-Webster, compare to polyalphabetic " ## Encryption @@ -23,7 +23,7 @@ Where: For the Roman alphabet `m` is `26`. - `a` and `b` are integers which make the encryption key -Values `a` and `m` must be *coprime* (or, *relatively prime*) for automatic decryption to succeed, i.e., they have number `1` as their only common factor (more information can be found in the [Wikipedia article about coprime integers][coprime-integers]). +Values `a` and `m` must be _coprime_ (or, _relatively prime_) for automatic decryption to succeed, i.e., they have number `1` as their only common factor (more information can be found in the [Wikipedia article about coprime integers][coprime-integers]). In case `a` is not coprime to `m`, your program should indicate that this is an error. Otherwise it should encrypt or decrypt with the provided key. diff --git a/exercises/practice/allergies/.docs/instructions.md b/exercises/practice/allergies/.docs/instructions.md index a1394920..daf8cfde 100644 --- a/exercises/practice/allergies/.docs/instructions.md +++ b/exercises/practice/allergies/.docs/instructions.md @@ -22,6 +22,6 @@ Now, given just that score of 34, your program should be able to say: - Whether Tom is allergic to any one of those allergens listed above. - All the allergens Tom is allergic to. -Note: a given score may include allergens **not** listed above (i.e. allergens that score 256, 512, 1024, etc.). +Note: a given score may include allergens **not** listed above (i.e. allergens that score 256, 512, 1024, etc.). Your program should ignore those components of the score. For example, if the allergy score is 257, your program should only report the eggs (1) allergy. diff --git a/exercises/practice/armstrong-numbers/.docs/instructions.md b/exercises/practice/armstrong-numbers/.docs/instructions.md index 744cfbe7..5e56bbe4 100644 --- a/exercises/practice/armstrong-numbers/.docs/instructions.md +++ b/exercises/practice/armstrong-numbers/.docs/instructions.md @@ -5,9 +5,9 @@ An [Armstrong number][armstrong-number] is a number that is the sum of its own d For example: - 9 is an Armstrong number, because `9 = 9^1 = 9` -- 10 is *not* an Armstrong number, because `10 != 1^2 + 0^2 = 1` +- 10 is _not_ an Armstrong number, because `10 != 1^2 + 0^2 = 1` - 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153` -- 154 is *not* an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190` +- 154 is _not_ an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190` Write some code to determine whether a number is an Armstrong number. diff --git a/exercises/practice/binary-search/.docs/instructions.md b/exercises/practice/binary-search/.docs/instructions.md index aa1946cf..12f4358e 100644 --- a/exercises/practice/binary-search/.docs/instructions.md +++ b/exercises/practice/binary-search/.docs/instructions.md @@ -11,7 +11,7 @@ Binary search only works when a list has been sorted. The algorithm looks like this: -- Find the middle element of a *sorted* list and compare it with the item we're looking for. +- Find the middle element of a _sorted_ list and compare it with the item we're looking for. - If the middle element is our item, then we're done! - If the middle element is greater than our item, we can eliminate that element and all the elements **after** it. - If the middle element is less than our item, we can eliminate that element and all the elements **before** it. diff --git a/exercises/practice/darts/.docs/instructions.md b/exercises/practice/darts/.docs/instructions.md index 70f0e53d..6518201c 100644 --- a/exercises/practice/darts/.docs/instructions.md +++ b/exercises/practice/darts/.docs/instructions.md @@ -1,11 +1,13 @@ # Instructions -Write a function that returns the earned points in a single toss of a Darts game. +Calculate the points scored in a single toss of a Darts game. [Darts][darts] is a game where players throw darts at a [target][darts-target]. In our particular instance of the game, the target rewards 4 different amounts of points, depending on where the dart lands: +![Our dart scoreboard with values from a complete miss to a bullseye](https://assets.exercism.org/images/exercises/darts/darts-scoreboard.svg) + - If the dart lands outside the target, player earns no points (0 points). - If the dart lands in the outer circle of the target, player earns 1 point. - If the dart lands in the middle circle of the target, player earns 5 points. @@ -14,10 +16,16 @@ In our particular instance of the game, the target rewards 4 different amounts o The outer circle has a radius of 10 units (this is equivalent to the total radius for the entire target), the middle circle a radius of 5 units, and the inner circle a radius of 1. Of course, they are all centered at the same point — that is, the circles are [concentric][] defined by the coordinates (0, 0). -Write a function that given a point in the target (defined by its [Cartesian coordinates][cartesian-coordinates] `x` and `y`, where `x` and `y` are [real][real-numbers]), returns the correct amount earned by a dart landing at that point. +Given a point in the target (defined by its [Cartesian coordinates][cartesian-coordinates] `x` and `y`, where `x` and `y` are [real][real-numbers]), calculate the correct score earned by a dart landing at that point. + +## Credit + +The scoreboard image was created by [habere-et-dispertire][habere-et-dispertire] using [Inkscape][inkscape]. [darts]: https://en.wikipedia.org/wiki/Darts [darts-target]: https://en.wikipedia.org/wiki/Darts#/media/File:Darts_in_a_dartboard.jpg [concentric]: https://mathworld.wolfram.com/ConcentricCircles.html [cartesian-coordinates]: https://www.mathsisfun.com/data/cartesian-coordinates.html [real-numbers]: https://www.mathsisfun.com/numbers/real-numbers.html +[habere-et-dispertire]: https://exercism.org/profiles/habere-et-dispertire +[inkscape]: https://en.wikipedia.org/wiki/Inkscape diff --git a/exercises/practice/darts/.meta/config.json b/exercises/practice/darts/.meta/config.json index bc583451..20df9b93 100644 --- a/exercises/practice/darts/.meta/config.json +++ b/exercises/practice/darts/.meta/config.json @@ -13,6 +13,6 @@ ".meta/example.el" ] }, - "blurb": "Write a function that returns the earned points in a single toss of a Darts game.", + "blurb": "Calculate the points scored in a single toss of a Darts game.", "source": "Inspired by an exercise created by a professor Della Paolera in Argentina" } diff --git a/exercises/practice/flatten-array/.docs/instructions.md b/exercises/practice/flatten-array/.docs/instructions.md index 51bea679..89dacfa3 100644 --- a/exercises/practice/flatten-array/.docs/instructions.md +++ b/exercises/practice/flatten-array/.docs/instructions.md @@ -2,7 +2,7 @@ Take a nested list and return a single flattened list with all values except nil/null. -The challenge is to write a function that accepts an arbitrarily-deep nested list-like structure and returns a flattened structure without any nil/null values. +The challenge is to take an arbitrarily-deep nested list-like structure and produce a flattened structure without any nil/null values. For example: diff --git a/exercises/practice/hello-world/.meta/config.json b/exercises/practice/hello-world/.meta/config.json index 1f39c965..606e41a4 100644 --- a/exercises/practice/hello-world/.meta/config.json +++ b/exercises/practice/hello-world/.meta/config.json @@ -19,7 +19,7 @@ ".meta/example.el" ] }, - "blurb": "The classical introductory exercise. Just say \"Hello, World!\".", + "blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".", "source": "This is an exercise to introduce users to using Exercism", "source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program" } diff --git a/exercises/practice/list-ops/.docs/instructions.md b/exercises/practice/list-ops/.docs/instructions.md index d3453338..ebc5dffe 100644 --- a/exercises/practice/list-ops/.docs/instructions.md +++ b/exercises/practice/list-ops/.docs/instructions.md @@ -7,11 +7,13 @@ Implement a series of basic list operations, without using existing functions. The precise number and names of the operations to be implemented will be track dependent to avoid conflicts with existing names, but the general operations you will implement include: -- `append` (*given two lists, add all items in the second list to the end of the first list*); -- `concatenate` (*given a series of lists, combine all items in all lists into one flattened list*); -- `filter` (*given a predicate and a list, return the list of all items for which `predicate(item)` is True*); -- `length` (*given a list, return the total number of items within it*); -- `map` (*given a function and a list, return the list of the results of applying `function(item)` on all items*); -- `foldl` (*given a function, a list, and initial accumulator, fold (reduce) each item into the accumulator from the left using `function(accumulator, item)`*); -- `foldr` (*given a function, a list, and an initial accumulator, fold (reduce) each item into the accumulator from the right using `function(item, accumulator)`*); -- `reverse` (*given a list, return a list with all the original items, but in reversed order*); +- `append` (_given two lists, add all items in the second list to the end of the first list_); +- `concatenate` (_given a series of lists, combine all items in all lists into one flattened list_); +- `filter` (_given a predicate and a list, return the list of all items for which `predicate(item)` is True_); +- `length` (_given a list, return the total number of items within it_); +- `map` (_given a function and a list, return the list of the results of applying `function(item)` on all items_); +- `foldl` (_given a function, a list, and initial accumulator, fold (reduce) each item into the accumulator from the left_); +- `foldr` (_given a function, a list, and an initial accumulator, fold (reduce) each item into the accumulator from the right_); +- `reverse` (_given a list, return a list with all the original items, but in reversed order_). + +Note, the ordering in which arguments are passed to the fold functions (`foldl`, `foldr`) is significant. diff --git a/exercises/practice/matching-brackets/.docs/instructions.md b/exercises/practice/matching-brackets/.docs/instructions.md index 544daa96..ea170842 100644 --- a/exercises/practice/matching-brackets/.docs/instructions.md +++ b/exercises/practice/matching-brackets/.docs/instructions.md @@ -1,4 +1,5 @@ # Instructions Given a string containing brackets `[]`, braces `{}`, parentheses `()`, or any combination thereof, verify that any and all pairs are matched and nested correctly. -The string may also contain other characters, which for the purposes of this exercise should be ignored. +Any other characters should be ignored. +For example, `"{what is (42)}?"` is balanced and `"[text}"` is not. diff --git a/exercises/practice/matching-brackets/.docs/introduction.md b/exercises/practice/matching-brackets/.docs/introduction.md new file mode 100644 index 00000000..0618221b --- /dev/null +++ b/exercises/practice/matching-brackets/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +You're given the opportunity to write software for the Bracketeer™, an ancient but powerful mainframe. +The software that runs on it is written in a proprietary language. +Much of its syntax is familiar, but you notice _lots_ of brackets, braces and parentheses. +Despite the Bracketeer™ being powerful, it lacks flexibility. +If the source code has any unbalanced brackets, braces or parentheses, the Bracketeer™ crashes and must be rebooted. +To avoid such a scenario, you start writing code that can verify that brackets, braces, and parentheses are balanced before attempting to run it on the Bracketeer™. diff --git a/exercises/practice/perfect-numbers/.docs/instructions.md b/exercises/practice/perfect-numbers/.docs/instructions.md index 0dae8867..b2bc82ca 100644 --- a/exercises/practice/perfect-numbers/.docs/instructions.md +++ b/exercises/practice/perfect-numbers/.docs/instructions.md @@ -1,24 +1,39 @@ # Instructions -Determine if a number is perfect, abundant, or deficient based on -Nicomachus' (60 - 120 CE) classification scheme for positive integers. - -The Greek mathematician [Nicomachus][nicomachus] devised a classification scheme for positive integers, identifying each as belonging uniquely to the categories of **perfect**, **abundant**, or **deficient** based on their [aliquot sum][aliquot-sum]. -The aliquot sum is defined as the sum of the factors of a number not including the number itself. -For example, the aliquot sum of 15 is (1 + 3 + 5) = 9 - -- **Perfect**: aliquot sum = number - - 6 is a perfect number because (1 + 2 + 3) = 6 - - 28 is a perfect number because (1 + 2 + 4 + 7 + 14) = 28 -- **Abundant**: aliquot sum > number - - 12 is an abundant number because (1 + 2 + 3 + 4 + 6) = 16 - - 24 is an abundant number because (1 + 2 + 3 + 4 + 6 + 8 + 12) = 36 -- **Deficient**: aliquot sum < number - - 8 is a deficient number because (1 + 2 + 4) = 7 - - Prime numbers are deficient - -Implement a way to determine whether a given number is **perfect**. -Depending on your language track, you may also need to implement a way to determine whether a given number is **abundant** or **deficient**. +Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers. + +The Greek mathematician [Nicomachus][nicomachus] devised a classification scheme for positive integers, identifying each as belonging uniquely to the categories of [perfect](#perfect), [abundant](#abundant), or [deficient](#deficient) based on their [aliquot sum][aliquot-sum]. +The _aliquot sum_ is defined as the sum of the factors of a number not including the number itself. +For example, the aliquot sum of `15` is `1 + 3 + 5 = 9`. + +## Perfect + +A number is perfect when it equals its aliquot sum. +For example: + +- `6` is a perfect number because `1 + 2 + 3 = 6` +- `28` is a perfect number because `1 + 2 + 4 + 7 + 14 = 28` + +## Abundant + +A number is abundant when it is less than its aliquot sum. +For example: + +- `12` is an abundant number because `1 + 2 + 3 + 4 + 6 = 16` +- `24` is an abundant number because `1 + 2 + 3 + 4 + 6 + 8 + 12 = 36` + +## Deficient + +A number is deficient when it is greater than its aliquot sum. +For example: + +- `8` is a deficient number because `1 + 2 + 4 = 7` +- Prime numbers are deficient + +## Task + +Implement a way to determine whether a given number is [perfect](#perfect). +Depending on your language track, you may also need to implement a way to determine whether a given number is [abundant](#abundant) or [deficient](#deficient). [nicomachus]: https://en.wikipedia.org/wiki/Nicomachus [aliquot-sum]: https://en.wikipedia.org/wiki/Aliquot_sum diff --git a/exercises/practice/phone-number/.docs/instructions.md b/exercises/practice/phone-number/.docs/instructions.md index 6d3275cd..62ba48e9 100644 --- a/exercises/practice/phone-number/.docs/instructions.md +++ b/exercises/practice/phone-number/.docs/instructions.md @@ -5,18 +5,20 @@ Clean up user-entered phone numbers so that they can be sent SMS messages. The **North American Numbering Plan (NANP)** is a telephone numbering system used by many countries in North America like the United States, Canada or Bermuda. All NANP-countries share the same international country code: `1`. -NANP numbers are ten-digit numbers consisting of a three-digit Numbering Plan Area code, commonly known as *area code*, followed by a seven-digit local number. -The first three digits of the local number represent the *exchange code*, followed by the unique four-digit number which is the *subscriber number*. +NANP numbers are ten-digit numbers consisting of a three-digit Numbering Plan Area code, commonly known as _area code_, followed by a seven-digit local number. +The first three digits of the local number represent the _exchange code_, followed by the unique four-digit number which is the _subscriber number_. The format is usually represented as ```text -(NXX)-NXX-XXXX +NXX NXX-XXXX ``` where `N` is any digit from 2 through 9 and `X` is any digit from 0 through 9. -Your task is to clean up differently formatted telephone numbers by removing punctuation and the country code (1) if present. +Sometimes they also have the country code (represented as `1` or `+1`) prefixed. + +Your task is to clean up differently formatted telephone numbers by removing punctuation and the country code if present. For example, the inputs diff --git a/exercises/practice/queen-attack/.docs/instructions.md b/exercises/practice/queen-attack/.docs/instructions.md index ad7ea954..97f22a0a 100644 --- a/exercises/practice/queen-attack/.docs/instructions.md +++ b/exercises/practice/queen-attack/.docs/instructions.md @@ -8,18 +8,14 @@ A chessboard can be represented by an 8 by 8 array. So if you are told the white queen is at `c5` (zero-indexed at column 2, row 3) and the black queen at `f2` (zero-indexed at column 5, row 6), then you know that the set-up is like so: -```text - a b c d e f g h -8 _ _ _ _ _ _ _ _ 8 -7 _ _ _ _ _ _ _ _ 7 -6 _ _ _ _ _ _ _ _ 6 -5 _ _ W _ _ _ _ _ 5 -4 _ _ _ _ _ _ _ _ 4 -3 _ _ _ _ _ _ _ _ 3 -2 _ _ _ _ _ B _ _ 2 -1 _ _ _ _ _ _ _ _ 1 - a b c d e f g h -``` +![A chess board with two queens. Arrows emanating from the queen at c5 indicate possible directions of capture along file, rank and diagonal.](https://assets.exercism.org/images/exercises/queen-attack/queen-capture.svg) You are also able to answer whether the queens can attack each other. In this case, that answer would be yes, they can, because both pieces share a diagonal. + +## Credit + +The chessboard image was made by [habere-et-dispertire][habere-et-dispertire] using LaTeX and the [chessboard package][chessboard-package] by Ulrike Fischer. + +[habere-et-dispertire]: https://exercism.org/profiles/habere-et-dispertire +[chessboard-package]: https://github.com/u-fischer/chessboard diff --git a/exercises/practice/raindrops/.meta/config.json b/exercises/practice/raindrops/.meta/config.json index 95c82dd3..d47b14f0 100644 --- a/exercises/practice/raindrops/.meta/config.json +++ b/exercises/practice/raindrops/.meta/config.json @@ -16,7 +16,7 @@ ".meta/example.el" ] }, - "blurb": "Convert a number to a string, the content of which depends on the number's factors.", + "blurb": "Convert a number into its corresponding raindrop sounds - Pling, Plang and Plong.", "source": "A variation on FizzBuzz, a famous technical interview question that is intended to weed out potential candidates. That question is itself derived from Fizz Buzz, a popular children's game for teaching division.", "source_url": "https://en.wikipedia.org/wiki/Fizz_buzz" } diff --git a/exercises/practice/rotational-cipher/.docs/instructions.md b/exercises/practice/rotational-cipher/.docs/instructions.md index 4dee51b3..4bf64ca1 100644 --- a/exercises/practice/rotational-cipher/.docs/instructions.md +++ b/exercises/practice/rotational-cipher/.docs/instructions.md @@ -22,8 +22,8 @@ Ciphertext is written out in the same formatting as the input including spaces a ## Examples -- ROT5 `omg` gives `trl` -- ROT0 `c` gives `c` +- ROT5 `omg` gives `trl` +- ROT0 `c` gives `c` - ROT26 `Cool` gives `Cool` - ROT13 `The quick brown fox jumps over the lazy dog.` gives `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` - ROT13 `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` gives `The quick brown fox jumps over the lazy dog.` From 1d9e30fc1e394a1e3ee36ace7f0f7a6c58c6ed74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:47:25 -0700 Subject: [PATCH 060/162] Add resistor-color-duo exercise (#348) * Add resistor-color-duo exercise * Update example.el location --- config.json | 152 ++++++++++++++---- .../resistor-color-duo/.docs/instructions.md | 33 ++++ .../resistor-color-duo/.meta/config.json | 19 +++ .../resistor-color-duo/.meta/example.el | 27 ++++ .../resistor-color-duo/.meta/tests.toml | 31 ++++ .../resistor-color-duo-test.el | 41 +++++ .../resistor-color-duo/resistor-color-duo.el | 13 ++ 7 files changed, 282 insertions(+), 34 deletions(-) create mode 100644 exercises/practice/resistor-color-duo/.docs/instructions.md create mode 100644 exercises/practice/resistor-color-duo/.meta/config.json create mode 100644 exercises/practice/resistor-color-duo/.meta/example.el create mode 100644 exercises/practice/resistor-color-duo/.meta/tests.toml create mode 100644 exercises/practice/resistor-color-duo/resistor-color-duo-test.el create mode 100644 exercises/practice/resistor-color-duo/resistor-color-duo.el diff --git a/config.json b/config.json index db3653c4..06648ff8 100644 --- a/config.json +++ b/config.json @@ -19,13 +19,20 @@ "average_run_time": 2 }, "files": { - "solution": ["%{kebab_slug}.el"], - "test": ["%{kebab_slug}-test.el"], - "example": [".meta/example.el"], - "exemplar": [".meta/exemplar.el"] + "solution": [ + "%{kebab_slug}.el" + ], + "test": [ + "%{kebab_slug}-test.el" + ], + "example": [ + ".meta/example.el" + ], + "exemplar": [ + ".meta/exemplar.el" + ] }, "exercises": { - "concept": [], "practice": [ { "slug": "hello-world", @@ -34,7 +41,9 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["strings"] + "topics": [ + "strings" + ] }, { "slug": "two-fer", @@ -43,7 +52,9 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["strings"] + "topics": [ + "strings" + ] }, { "slug": "leap", @@ -52,7 +63,12 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["control_flow_conditionals", "equality", "integers", "logic"] + "topics": [ + "control_flow_conditionals", + "equality", + "integers", + "logic" + ] }, { "slug": "anagram", @@ -61,7 +77,19 @@ "practices": [], "prerequisites": [], "difficulty": 2, - "topics": ["equality", "filtering", "strings"] + "topics": [ + "equality", + "filtering", + "strings" + ] + }, + { + "slug": "resistor-color-duo", + "name": "Resistor Color Duo", + "uuid": "1c55189e-2c58-48b4-92f1-9a05a9b9c6d6", + "practices": [], + "prerequisites": [], + "difficulty": 2 }, { "slug": "roman-numerals", @@ -100,7 +128,11 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["control_flow_conditionals", "strings", "transforming"] + "topics": [ + "control_flow_conditionals", + "strings", + "transforming" + ] }, { "slug": "bob", @@ -109,7 +141,11 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["control_flow_conditionals", "parsing", "strings"] + "topics": [ + "control_flow_conditionals", + "parsing", + "strings" + ] }, { "slug": "word-count", @@ -132,7 +168,10 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["strings", "transforming"] + "topics": [ + "strings", + "transforming" + ] }, { "slug": "allergies", @@ -155,7 +194,9 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["math"] + "topics": [ + "math" + ] }, { "slug": "binary", @@ -164,7 +205,6 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": null, "status": "deprecated" }, { @@ -202,7 +242,11 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["control_flow_loops", "maps", "transforming"] + "topics": [ + "control_flow_loops", + "maps", + "transforming" + ] }, { "slug": "gigasecond", @@ -211,7 +255,13 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["date", "integers", "time", "transforming", "variables"] + "topics": [ + "date", + "integers", + "time", + "transforming", + "variables" + ] }, { "slug": "grains", @@ -220,7 +270,10 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["integers", "variables"] + "topics": [ + "integers", + "variables" + ] }, { "slug": "nucleotide-count", @@ -229,7 +282,12 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["control_flow_loops", "maps", "sorting", "strings"] + "topics": [ + "control_flow_loops", + "maps", + "sorting", + "strings" + ] }, { "slug": "pangram", @@ -238,7 +296,10 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["control_flow_loops", "strings"] + "topics": [ + "control_flow_loops", + "strings" + ] }, { "slug": "perfect-numbers", @@ -247,7 +308,10 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["math", "number_theory"] + "topics": [ + "math", + "number_theory" + ] }, { "slug": "raindrops", @@ -256,7 +320,11 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["control_flow_conditionals", "filtering", "integers"] + "topics": [ + "control_flow_conditionals", + "filtering", + "integers" + ] }, { "slug": "trinary", @@ -265,7 +333,9 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": ["math"] + "topics": [ + "math" + ] }, { "slug": "atbash-cipher", @@ -288,7 +358,11 @@ "practices": [], "prerequisites": [], "difficulty": 2, - "topics": ["cryptograpy", "strings", "transforming"] + "topics": [ + "cryptograpy", + "strings", + "transforming" + ] }, { "slug": "phone-number", @@ -297,7 +371,11 @@ "practices": [], "prerequisites": [], "difficulty": 2, - "topics": ["interfaces", "parsing", "strings"] + "topics": [ + "interfaces", + "parsing", + "strings" + ] }, { "slug": "robot-name", @@ -306,7 +384,11 @@ "practices": [], "prerequisites": [], "difficulty": 2, - "topics": ["randomness", "strings", "variables"] + "topics": [ + "randomness", + "strings", + "variables" + ] }, { "slug": "run-length-encoding", @@ -314,8 +396,7 @@ "uuid": "9e8f98f0-6fff-4389-a9a2-9ae43edefa21", "practices": [], "prerequisites": [], - "difficulty": 2, - "topics": null + "difficulty": 2 }, { "slug": "luhn", @@ -324,7 +405,11 @@ "practices": [], "prerequisites": [], "difficulty": 3, - "topics": ["checksums", "list_operations", "strings"] + "topics": [ + "checksums", + "list_operations", + "strings" + ] }, { "slug": "list-ops", @@ -452,7 +537,6 @@ } ] }, - "concepts": [], "key_features": [ { "title": "Simple syntax", @@ -486,14 +570,14 @@ } ], "tags": [ - "paradigm/functional", - "typing/dynamic", - "typing/strong", "execution_mode/interpreted", - "platform/windows", - "platform/mac", + "paradigm/functional", "platform/linux", + "platform/mac", + "platform/windows", "runtime/language_specific", + "typing/dynamic", + "typing/strong", "used_for/scripts" ] } diff --git a/exercises/practice/resistor-color-duo/.docs/instructions.md b/exercises/practice/resistor-color-duo/.docs/instructions.md new file mode 100644 index 00000000..bdcd549b --- /dev/null +++ b/exercises/practice/resistor-color-duo/.docs/instructions.md @@ -0,0 +1,33 @@ +# Instructions + +If you want to build something using a Raspberry Pi, you'll probably use _resistors_. +For this exercise, you need to know two things about them: + +- Each resistor has a resistance value. +- Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. + +To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. +Each band has a position and a numeric value. + +The first 2 bands of a resistor have a simple encoding scheme: each color maps to a single number. +For example, if they printed a brown band (value 1) followed by a green band (value 5), it would translate to the number 15. + +In this exercise you are going to create a helpful program so that you don't have to remember the values of the bands. +The program will take color names as input and output a two digit number, even if the input is more than two colors! + +The band colors are encoded as follows: + +- Black: 0 +- Brown: 1 +- Red: 2 +- Orange: 3 +- Yellow: 4 +- Green: 5 +- Blue: 6 +- Violet: 7 +- Grey: 8 +- White: 9 + +From the example above: +brown-green should return 15 +brown-green-violet should return 15 too, ignoring the third color. diff --git a/exercises/practice/resistor-color-duo/.meta/config.json b/exercises/practice/resistor-color-duo/.meta/config.json new file mode 100644 index 00000000..fe85c3ab --- /dev/null +++ b/exercises/practice/resistor-color-duo/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "resistor-color-duo.el" + ], + "test": [ + "resistor-color-duo-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Convert color codes, as used on resistors, to a numeric value.", + "source": "Maud de Vries, Erik Schierboom", + "source_url": "https://github.com/exercism/problem-specifications/issues/1464" +} diff --git a/exercises/practice/resistor-color-duo/.meta/example.el b/exercises/practice/resistor-color-duo/.meta/example.el new file mode 100644 index 00000000..3d8a98a4 --- /dev/null +++ b/exercises/practice/resistor-color-duo/.meta/example.el @@ -0,0 +1,27 @@ +;;; resistor-color-duo.el --- Resistor Color Duo (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(setq band-values +'(("black" . 0) + ("brown" . 1) + ("red" . 2) + ("orange" . 3) + ("yellow" . 4) + ("green" . 5) + ("blue" . 6) + ("violet" . 7) + ("grey" . 8) + ("white" . 9))) + +(defun value (colors) + (+ (* (get-value (nth 0 colors)) 10) + (get-value (nth 1 colors)))) + +(defun get-value (color) + (cdr (assoc color band-values))) + +(provide 'resistor-color-duo) +;;; resistor-color-duo.el ends here diff --git a/exercises/practice/resistor-color-duo/.meta/tests.toml b/exercises/practice/resistor-color-duo/.meta/tests.toml new file mode 100644 index 00000000..9036fc78 --- /dev/null +++ b/exercises/practice/resistor-color-duo/.meta/tests.toml @@ -0,0 +1,31 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[ce11995a-5b93-4950-a5e9-93423693b2fc] +description = "Brown and black" + +[7bf82f7a-af23-48ba-a97d-38d59406a920] +description = "Blue and grey" + +[f1886361-fdfd-4693-acf8-46726fe24e0c] +description = "Yellow and violet" + +[b7a6cbd2-ae3c-470a-93eb-56670b305640] +description = "White and red" + +[77a8293d-2a83-4016-b1af-991acc12b9fe] +description = "Orange and orange" + +[0c4fb44f-db7c-4d03-afa8-054350f156a8] +description = "Ignore additional colors" + +[4a8ceec5-0ab4-4904-88a4-daf953a5e818] +description = "Black and brown, one-digit" diff --git a/exercises/practice/resistor-color-duo/resistor-color-duo-test.el b/exercises/practice/resistor-color-duo/resistor-color-duo-test.el new file mode 100644 index 00000000..fa60d529 --- /dev/null +++ b/exercises/practice/resistor-color-duo/resistor-color-duo-test.el @@ -0,0 +1,41 @@ +;;; resistor-color-duo-test.el --- Resistor Color Duo (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "resistor-color-duo.el") +(declare-function value "resistor-color-duo.el" (colors)) + + +(ert-deftest brown-and-black () + (should (equal (value '("brown" "black")) 10))) + + +(ert-deftest blue-and-grey () + (should (equal (value '("blue" "grey")) 68))) + + +(ert-deftest yellow-and-violet () + (should (equal (value '("yellow" "violet")) 47))) + + +(ert-deftest white-and-red () + (should (equal (value '("white" "red")) 92))) + + +(ert-deftest orange-and-orange () + (should (equal (value '("orange" "orange")) 33))) + + +(ert-deftest ignore-additional-colors () + (should (equal (value '("green" "brown" "orange")) 51))) + + +(ert-deftest black-and-brown-one-digit () + (should (equal (value '("black" "brown")) 1))) + + +(provide 'resistor-color-duo-test) +;;; resistor-color-duo-test.el ends here diff --git a/exercises/practice/resistor-color-duo/resistor-color-duo.el b/exercises/practice/resistor-color-duo/resistor-color-duo.el new file mode 100644 index 00000000..2641c2df --- /dev/null +++ b/exercises/practice/resistor-color-duo/resistor-color-duo.el @@ -0,0 +1,13 @@ +;;; resistor-color-duo.el --- Resistor Color Duo (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun value (colors) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'resistor-color-duo) +;;; resistor-color-duo.el ends here From d977d6fe315c94ea5a487cbc32e3d35346bbdf7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Wed, 24 Apr 2024 00:10:33 -0700 Subject: [PATCH 061/162] Update difficulty levels and sort exercises (#355) * Assign difficulty levels * Sort exercises by difficulty and then name --- config.json | 524 ++++++++++++++++++++++++++-------------------------- 1 file changed, 262 insertions(+), 262 deletions(-) diff --git a/config.json b/config.json index 06648ff8..b651c5dc 100644 --- a/config.json +++ b/config.json @@ -34,140 +34,13 @@ }, "exercises": { "practice": [ - { - "slug": "hello-world", - "name": "Hello World", - "uuid": "c4fdc935-885b-44bd-84e4-fae4a09e8c39", - "practices": [], - "prerequisites": [], - "difficulty": 1, - "topics": [ - "strings" - ] - }, - { - "slug": "two-fer", - "name": "Two Fer", - "uuid": "36e5dc3a-2122-484a-ae82-beb7b813e2cd", - "practices": [], - "prerequisites": [], - "difficulty": 1, - "topics": [ - "strings" - ] - }, - { - "slug": "leap", - "name": "Leap", - "uuid": "84eaff19-cb25-46af-a34e-1379e692e57b", - "practices": [], - "prerequisites": [], - "difficulty": 1, - "topics": [ - "control_flow_conditionals", - "equality", - "integers", - "logic" - ] - }, - { - "slug": "anagram", - "name": "Anagram", - "uuid": "d8906a7e-9d7e-4e8e-aff0-da877291d8dc", - "practices": [], - "prerequisites": [], - "difficulty": 2, - "topics": [ - "equality", - "filtering", - "strings" - ] - }, - { - "slug": "resistor-color-duo", - "name": "Resistor Color Duo", - "uuid": "1c55189e-2c58-48b4-92f1-9a05a9b9c6d6", - "practices": [], - "prerequisites": [], - "difficulty": 2 - }, - { - "slug": "roman-numerals", - "name": "Roman Numerals", - "uuid": "c4875bc5-e295-4782-99c7-cb3370ac8e08", - "practices": [], - "prerequisites": [], - "difficulty": 1, - "topics": [ - "control_flow_conditionals", - "control_flow_loops", - "integers", - "strings", - "text_formatting" - ] - }, - { - "slug": "hamming", - "name": "Hamming", - "uuid": "2bfb508e-7ceb-4ae1-8316-1e2daf771807", - "practices": [], - "prerequisites": [], - "difficulty": 1, - "topics": [ - "control_flow_conditionals", - "control_flow_loops", - "equality", - "filtering", - "strings" - ] - }, - { - "slug": "rna-transcription", - "name": "RNA Transcription", - "uuid": "7b6767b9-2efc-414d-83f7-def9c371d63d", - "practices": [], - "prerequisites": [], - "difficulty": 1, - "topics": [ - "control_flow_conditionals", - "strings", - "transforming" - ] - }, - { - "slug": "bob", - "name": "Bob", - "uuid": "c02c7392-9478-4cfd-81eb-0cb8ebe78fe5", - "practices": [], - "prerequisites": [], - "difficulty": 1, - "topics": [ - "control_flow_conditionals", - "parsing", - "strings" - ] - }, - { - "slug": "word-count", - "name": "Word Count", - "uuid": "1a3c64b1-8447-451f-985d-f7bd6d42bdb6", - "practices": [], - "prerequisites": [], - "difficulty": 2, - "topics": [ - "control_flow_conditionals", - "control_flow_loops", - "filtering", - "strings" - ] - }, { "slug": "acronym", "name": "Acronym", "uuid": "a252e137-8a63-4f26-b119-7264f12a257a", "practices": [], "prerequisites": [], - "difficulty": 1, + "difficulty": 2, "topics": [ "strings", "transforming" @@ -179,7 +52,7 @@ "uuid": "e0d7220f-5d3a-4f10-842e-3d49df714cac", "practices": [], "prerequisites": [], - "difficulty": 1, + "difficulty": 2, "topics": [ "bitwise_operations", "control_flow_conditionals", @@ -193,7 +66,7 @@ "uuid": "059141f0-f28d-4d10-a03a-7852dbfc2d2e", "practices": [], "prerequisites": [], - "difficulty": 1, + "difficulty": 2, "topics": [ "math" ] @@ -204,30 +77,45 @@ "uuid": "7307e13e-7a18-4654-8df4-96951d4dccc6", "practices": [], "prerequisites": [], - "difficulty": 1, + "difficulty": 2, "status": "deprecated" }, { - "slug": "all-your-base", - "name": "All Your Base", - "uuid": "a101dd85-fe8b-4f3f-bece-bbd899a08ee7", + "slug": "binary-search", + "name": "Binary Search", + "uuid": "fb36c27f-0ad5-42d1-90c0-6718f01e61a4", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, + { + "slug": "bob", + "name": "Bob", + "uuid": "c02c7392-9478-4cfd-81eb-0cb8ebe78fe5", "practices": [], "prerequisites": [], - "difficulty": 3, + "difficulty": 2, "topics": [ - "bitwise_operations", "control_flow_conditionals", - "integers", - "math" + "parsing", + "strings" ] }, + { + "slug": "darts", + "name": "Darts", + "uuid": "ca189b4e-713d-4722-b21e-c07d1b975b58", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "difference-of-squares", "name": "Difference of Squares", "uuid": "7b421b14-c33c-41a6-9e7e-4f9b6fbe6fcc", "practices": [], "prerequisites": [], - "difficulty": 1, + "difficulty": 2, "topics": [ "control_flow_loops", "floating_point_numbers", @@ -235,26 +123,13 @@ "math" ] }, - { - "slug": "etl", - "name": "ETL", - "uuid": "d8f4c530-02f0-44d3-b5b8-858fec4b6a9d", - "practices": [], - "prerequisites": [], - "difficulty": 1, - "topics": [ - "control_flow_loops", - "maps", - "transforming" - ] - }, { "slug": "gigasecond", "name": "Gigasecond", "uuid": "e9e27a75-143a-439f-98d0-a604724a7af2", "practices": [], "prerequisites": [], - "difficulty": 1, + "difficulty": 2, "topics": [ "date", "integers", @@ -269,99 +144,97 @@ "uuid": "d219aab6-11ec-4e0c-b041-f06c8d523946", "practices": [], "prerequisites": [], - "difficulty": 1, + "difficulty": 2, "topics": [ "integers", "variables" ] }, { - "slug": "nucleotide-count", - "name": "Nucleotide Count", - "uuid": "aaff28dd-718b-48d4-b507-a0b9b01bb6ad", + "slug": "hamming", + "name": "Hamming", + "uuid": "2bfb508e-7ceb-4ae1-8316-1e2daf771807", "practices": [], "prerequisites": [], - "difficulty": 1, + "difficulty": 2, "topics": [ + "control_flow_conditionals", "control_flow_loops", - "maps", - "sorting", + "equality", + "filtering", "strings" ] }, { - "slug": "pangram", - "name": "Pangram", - "uuid": "42222c98-e8d2-41bd-9d95-2ace63864359", + "slug": "hello-world", + "name": "Hello World", + "uuid": "c4fdc935-885b-44bd-84e4-fae4a09e8c39", "practices": [], "prerequisites": [], - "difficulty": 1, + "difficulty": 2, "topics": [ - "control_flow_loops", "strings" ] }, { - "slug": "perfect-numbers", - "name": "Perfect Numbers", - "uuid": "30971b02-79fc-40a1-aa70-ada3fec85548", + "slug": "leap", + "name": "Leap", + "uuid": "84eaff19-cb25-46af-a34e-1379e692e57b", "practices": [], "prerequisites": [], - "difficulty": 1, + "difficulty": 2, "topics": [ - "math", - "number_theory" + "control_flow_conditionals", + "equality", + "integers", + "logic" ] }, { - "slug": "raindrops", - "name": "Raindrops", - "uuid": "9a97c992-3da0-4f6d-b2f6-1f2683417e3b", + "slug": "list-ops", + "name": "List Ops", + "uuid": "883fdbef-ad97-4f08-8d51-d65bd91fc864", "practices": [], "prerequisites": [], - "difficulty": 1, + "difficulty": 2, "topics": [ - "control_flow_conditionals", "filtering", - "integers" + "functional_programming", + "generics", + "lists", + "loops" ] }, { - "slug": "trinary", - "name": "Trinary", - "uuid": "c5239cf6-c5a3-4d81-a4d9-504c292ff11e", + "slug": "matching-brackets", + "name": "Matching Brackets", + "uuid": "c000a3e1-3488-41ba-9d4c-6f06a96bc892", "practices": [], "prerequisites": [], - "difficulty": 1, - "topics": [ - "math" - ] + "difficulty": 2 }, { - "slug": "atbash-cipher", - "name": "Atbash Cipher", - "uuid": "89125ff6-f94b-46a4-9a5d-84539674238d", + "slug": "pangram", + "name": "Pangram", + "uuid": "42222c98-e8d2-41bd-9d95-2ace63864359", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ - "control_flow_conditionals", "control_flow_loops", - "sequences", - "transforming" + "strings" ] }, { - "slug": "crypto-square", - "name": "Crypto Square", - "uuid": "884cd761-e764-4c1e-8240-bb4454b43ea9", + "slug": "perfect-numbers", + "name": "Perfect Numbers", + "uuid": "30971b02-79fc-40a1-aa70-ada3fec85548", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ - "cryptograpy", - "strings", - "transforming" + "math", + "number_theory" ] }, { @@ -378,54 +251,98 @@ ] }, { - "slug": "robot-name", - "name": "Robot Name", - "uuid": "55bc8c2a-1db3-4d26-b7c6-a778b61bf46b", + "slug": "queen-attack", + "name": "Queen Attack", + "uuid": "bfa1d997-f0bd-432b-aa29-7018607d772d", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, + { + "slug": "rna-transcription", + "name": "RNA Transcription", + "uuid": "7b6767b9-2efc-414d-83f7-def9c371d63d", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ - "randomness", + "control_flow_conditionals", "strings", - "variables" + "transforming" ] }, { - "slug": "run-length-encoding", - "name": "Run-Length Encoding", - "uuid": "9e8f98f0-6fff-4389-a9a2-9ae43edefa21", + "slug": "raindrops", + "name": "Raindrops", + "uuid": "9a97c992-3da0-4f6d-b2f6-1f2683417e3b", + "practices": [], + "prerequisites": [], + "difficulty": 2, + "topics": [ + "control_flow_conditionals", + "filtering", + "integers" + ] + }, + { + "slug": "resistor-color-duo", + "name": "Resistor Color Duo", + "uuid": "1c55189e-2c58-48b4-92f1-9a05a9b9c6d6", "practices": [], "prerequisites": [], "difficulty": 2 }, { - "slug": "luhn", - "name": "Luhn", - "uuid": "bb10d7e4-6006-4dfd-81ae-45062a0ec999", + "slug": "reverse-string", + "name": "Reverse String", + "uuid": "59c6319b-2799-4e4c-bef1-e28626878446", "practices": [], "prerequisites": [], - "difficulty": 3, + "difficulty": 2 + }, + { + "slug": "roman-numerals", + "name": "Roman Numerals", + "uuid": "c4875bc5-e295-4782-99c7-cb3370ac8e08", + "practices": [], + "prerequisites": [], + "difficulty": 2, "topics": [ - "checksums", - "list_operations", - "strings" + "control_flow_conditionals", + "control_flow_loops", + "integers", + "strings", + "text_formatting" ] }, { - "slug": "list-ops", - "name": "List Ops", - "uuid": "883fdbef-ad97-4f08-8d51-d65bd91fc864", + "slug": "rotational-cipher", + "name": "Rotational Cipher", + "uuid": "4faa2bae-ecda-4c16-9f6d-148793117995", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, + { + "slug": "scrabble-score", + "name": "Scrabble Score", + "uuid": "fb45c509-d83d-4f71-a8ef-f218c5426838", "practices": [], "prerequisites": [], - "difficulty": 3, + "difficulty": 2, "topics": [ - "filtering", - "functional_programming", - "generics", "lists", - "loops" + "strings" ] }, + { + "slug": "simple-cipher", + "name": "Simple Cipher", + "uuid": "c3cc6d91-b633-44d6-b7e1-04abb33e712c", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "sublist", "name": "Sublist", @@ -444,28 +361,26 @@ ] }, { - "slug": "darts", - "name": "Darts", - "uuid": "ca189b4e-713d-4722-b21e-c07d1b975b58", - "practices": [], - "prerequisites": [], - "difficulty": 1 - }, - { - "slug": "rotational-cipher", - "name": "Rotational Cipher", - "uuid": "4faa2bae-ecda-4c16-9f6d-148793117995", + "slug": "trinary", + "name": "Trinary", + "uuid": "c5239cf6-c5a3-4d81-a4d9-504c292ff11e", "practices": [], "prerequisites": [], - "difficulty": 2 + "difficulty": 2, + "topics": [ + "math" + ] }, { - "slug": "simple-cipher", - "name": "Simple Cipher", - "uuid": "c3cc6d91-b633-44d6-b7e1-04abb33e712c", + "slug": "two-fer", + "name": "Two Fer", + "uuid": "36e5dc3a-2122-484a-ae82-beb7b813e2cd", "practices": [], "prerequisites": [], - "difficulty": 2 + "difficulty": 2, + "topics": [ + "strings" + ] }, { "slug": "affine-cipher", @@ -473,47 +388,74 @@ "uuid": "7d966a40-3cf7-422a-99b1-c0bf05e151b2", "practices": [], "prerequisites": [], - "difficulty": 4 + "difficulty": 5 }, { - "slug": "rail-fence-cipher", - "name": "Rail Fence Cipher", - "uuid": "bcd4671e-4fb9-4abb-af98-315fc83daa52", + "slug": "all-your-base", + "name": "All Your Base", + "uuid": "a101dd85-fe8b-4f3f-bece-bbd899a08ee7", "practices": [], "prerequisites": [], - "difficulty": 4 + "difficulty": 5, + "topics": [ + "bitwise_operations", + "control_flow_conditionals", + "integers", + "math" + ] }, { - "slug": "matching-brackets", - "name": "Matching Brackets", - "uuid": "c000a3e1-3488-41ba-9d4c-6f06a96bc892", + "slug": "anagram", + "name": "Anagram", + "uuid": "d8906a7e-9d7e-4e8e-aff0-da877291d8dc", "practices": [], "prerequisites": [], - "difficulty": 3 + "difficulty": 5, + "topics": [ + "equality", + "filtering", + "strings" + ] }, { - "slug": "queen-attack", - "name": "Queen Attack", - "uuid": "bfa1d997-f0bd-432b-aa29-7018607d772d", + "slug": "atbash-cipher", + "name": "Atbash Cipher", + "uuid": "89125ff6-f94b-46a4-9a5d-84539674238d", "practices": [], "prerequisites": [], - "difficulty": 2 + "difficulty": 5, + "topics": [ + "control_flow_conditionals", + "control_flow_loops", + "sequences", + "transforming" + ] }, { - "slug": "reverse-string", - "name": "Reverse String", - "uuid": "59c6319b-2799-4e4c-bef1-e28626878446", + "slug": "crypto-square", + "name": "Crypto Square", + "uuid": "884cd761-e764-4c1e-8240-bb4454b43ea9", "practices": [], "prerequisites": [], - "difficulty": 1 + "difficulty": 5, + "topics": [ + "cryptograpy", + "strings", + "transforming" + ] }, { - "slug": "binary-search", - "name": "Binary Search", - "uuid": "fb36c27f-0ad5-42d1-90c0-6718f01e61a4", + "slug": "etl", + "name": "ETL", + "uuid": "d8f4c530-02f0-44d3-b5b8-858fec4b6a9d", "practices": [], "prerequisites": [], - "difficulty": 3 + "difficulty": 5, + "topics": [ + "control_flow_loops", + "maps", + "transforming" + ] }, { "slug": "flatten-array", @@ -521,17 +463,75 @@ "uuid": "66f266a8-9c5c-4aad-8a27-92810b288a2b", "practices": [], "prerequisites": [], - "difficulty": 6 + "difficulty": 5 }, { - "slug": "scrabble-score", - "name": "Scrabble Score", - "uuid": "fb45c509-d83d-4f71-a8ef-f218c5426838", + "slug": "luhn", + "name": "Luhn", + "uuid": "bb10d7e4-6006-4dfd-81ae-45062a0ec999", "practices": [], "prerequisites": [], - "difficulty": 3, + "difficulty": 5, "topics": [ - "lists", + "checksums", + "list_operations", + "strings" + ] + }, + { + "slug": "nucleotide-count", + "name": "Nucleotide Count", + "uuid": "aaff28dd-718b-48d4-b507-a0b9b01bb6ad", + "practices": [], + "prerequisites": [], + "difficulty": 5, + "topics": [ + "control_flow_loops", + "maps", + "sorting", + "strings" + ] + }, + { + "slug": "rail-fence-cipher", + "name": "Rail Fence Cipher", + "uuid": "bcd4671e-4fb9-4abb-af98-315fc83daa52", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, + { + "slug": "robot-name", + "name": "Robot Name", + "uuid": "55bc8c2a-1db3-4d26-b7c6-a778b61bf46b", + "practices": [], + "prerequisites": [], + "difficulty": 5, + "topics": [ + "randomness", + "strings", + "variables" + ] + }, + { + "slug": "run-length-encoding", + "name": "Run-Length Encoding", + "uuid": "9e8f98f0-6fff-4389-a9a2-9ae43edefa21", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, + { + "slug": "word-count", + "name": "Word Count", + "uuid": "1a3c64b1-8447-451f-985d-f7bd6d42bdb6", + "practices": [], + "prerequisites": [], + "difficulty": 5, + "topics": [ + "control_flow_conditionals", + "control_flow_loops", + "filtering", "strings" ] } From ccf484515405a8af33e3dbaa086e47b61f581c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Wed, 24 Apr 2024 00:32:14 -0700 Subject: [PATCH 062/162] Add missing authors to exercise configs (#360) * Add ETL author from #42 * Add perfect-numbers author from #41 * Add phone-number author from #44 * Add run-length-encoding author from #85 * Add word-count author from #43 --- exercises/practice/etl/.meta/config.json | 4 +++- exercises/practice/perfect-numbers/.meta/config.json | 4 +++- exercises/practice/phone-number/.meta/config.json | 4 +++- exercises/practice/run-length-encoding/.meta/config.json | 4 +++- exercises/practice/word-count/.meta/config.json | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/exercises/practice/etl/.meta/config.json b/exercises/practice/etl/.meta/config.json index f8ba576e..99011a7f 100644 --- a/exercises/practice/etl/.meta/config.json +++ b/exercises/practice/etl/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": [], + "authors": [ + "cpaulbond" + ], "contributors": [ "canweriotnow", "vermiculus" diff --git a/exercises/practice/perfect-numbers/.meta/config.json b/exercises/practice/perfect-numbers/.meta/config.json index cd62fae3..a30cdfdd 100644 --- a/exercises/practice/perfect-numbers/.meta/config.json +++ b/exercises/practice/perfect-numbers/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": [], + "authors": [ + "cpaulbond" + ], "contributors": [ "canweriotnow", "guygastineau", diff --git a/exercises/practice/phone-number/.meta/config.json b/exercises/practice/phone-number/.meta/config.json index d91424ec..c475338c 100644 --- a/exercises/practice/phone-number/.meta/config.json +++ b/exercises/practice/phone-number/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": [], + "authors": [ + "cpaulbond" + ], "contributors": [ "yurrriq" ], diff --git a/exercises/practice/run-length-encoding/.meta/config.json b/exercises/practice/run-length-encoding/.meta/config.json index 99c946d9..ea4711b8 100644 --- a/exercises/practice/run-length-encoding/.meta/config.json +++ b/exercises/practice/run-length-encoding/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": [], + "authors": [ + "cpaulbond" + ], "contributors": [ "benreyn" ], diff --git a/exercises/practice/word-count/.meta/config.json b/exercises/practice/word-count/.meta/config.json index b66c3c7c..30ec95ec 100644 --- a/exercises/practice/word-count/.meta/config.json +++ b/exercises/practice/word-count/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": [], + "authors": [ + "cpaulbond" + ], "contributors": [ "canweriotnow", "npostavs", From 1a1fe8aa7670a77ccfb3dc738909ce44dbd38f7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Apr 2024 18:05:34 -0700 Subject: [PATCH 063/162] Bump actions/checkout from 4.1.3 to 4.1.4 (#361) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.3 to 4.1.4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/1d96c772d19495a3b5c517cd2bc0cb401ea0529f...0ad4b8fadaa221de15dcec353f45205ec38ea70b) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/configlet-sync.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 910d3311..a855db46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: with: version: 28.2 - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.0.0 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.0.0 - name: Run exercism/emacs-lisp ci (runs tests) for all exercises run: | diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index 61dbad3d..807d079e 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.0.0 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.0.0 - name: Fetch configlet uses: exercism/github-actions/configlet-ci@main From 5aea2aa7d97876fdd70d33d1a222a944df404067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Wed, 24 Apr 2024 22:05:12 -0700 Subject: [PATCH 064/162] Add eliud's eggs (#362) --- config.json | 8 ++++ .../eliuds-eggs/.docs/instructions.md | 8 ++++ .../eliuds-eggs/.docs/introduction.md | 47 +++++++++++++++++++ .../practice/eliuds-eggs/.meta/config.json | 19 ++++++++ .../practice/eliuds-eggs/.meta/example.el | 18 +++++++ .../practice/eliuds-eggs/.meta/tests.toml | 22 +++++++++ .../practice/eliuds-eggs/eliuds-eggs-test.el | 29 ++++++++++++ exercises/practice/eliuds-eggs/eliuds-eggs.el | 14 ++++++ 8 files changed, 165 insertions(+) create mode 100644 exercises/practice/eliuds-eggs/.docs/instructions.md create mode 100644 exercises/practice/eliuds-eggs/.docs/introduction.md create mode 100644 exercises/practice/eliuds-eggs/.meta/config.json create mode 100644 exercises/practice/eliuds-eggs/.meta/example.el create mode 100644 exercises/practice/eliuds-eggs/.meta/tests.toml create mode 100644 exercises/practice/eliuds-eggs/eliuds-eggs-test.el create mode 100644 exercises/practice/eliuds-eggs/eliuds-eggs.el diff --git a/config.json b/config.json index b651c5dc..766628f4 100644 --- a/config.json +++ b/config.json @@ -123,6 +123,14 @@ "math" ] }, + { + "slug": "eliuds-eggs", + "name": "Eliud's Eggs", + "uuid": "9e10bc23-bd92-4b67-9921-6ff7555d3774", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "gigasecond", "name": "Gigasecond", diff --git a/exercises/practice/eliuds-eggs/.docs/instructions.md b/exercises/practice/eliuds-eggs/.docs/instructions.md new file mode 100644 index 00000000..b0c2df59 --- /dev/null +++ b/exercises/practice/eliuds-eggs/.docs/instructions.md @@ -0,0 +1,8 @@ +# Instructions + +Your task is to count the number of 1 bits in the binary representation of a number. + +## Restrictions + +Keep your hands off that bit-count functionality provided by your standard library! +Solve this one yourself using other basic tools instead. diff --git a/exercises/practice/eliuds-eggs/.docs/introduction.md b/exercises/practice/eliuds-eggs/.docs/introduction.md new file mode 100644 index 00000000..49eaffd8 --- /dev/null +++ b/exercises/practice/eliuds-eggs/.docs/introduction.md @@ -0,0 +1,47 @@ +# Introduction + +Your friend Eliud inherited a farm from her grandma Tigist. +Her granny was an inventor and had a tendency to build things in an overly complicated manner. +The chicken coop has a digital display showing an encoded number representing the positions of all eggs that could be picked up. + +Eliud is asking you to write a program that shows the actual number of eggs in the coop. + +The position information encoding is calculated as follows: + +1. Scan the potential egg-laying spots and mark down a `1` for an existing egg or a `0` for an empty spot. +2. Convert the number from binary to decimal. +3. Show the result on the display. + +Example 1: + +```text +Chicken Coop: + _ _ _ _ _ _ _ +|E| |E|E| | |E| + +Resulting Binary: + 1 0 1 1 0 0 1 + +Decimal number on the display: +89 + +Actual eggs in the coop: +4 +``` + +Example 2: + +```text +Chicken Coop: + _ _ _ _ _ _ _ _ +| | | |E| | | | | + +Resulting Binary: + 0 0 0 1 0 0 0 0 + +Decimal number on the display: +16 + +Actual eggs in the coop: +1 +``` diff --git a/exercises/practice/eliuds-eggs/.meta/config.json b/exercises/practice/eliuds-eggs/.meta/config.json new file mode 100644 index 00000000..a718d4de --- /dev/null +++ b/exercises/practice/eliuds-eggs/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "eliuds-eggs.el" + ], + "test": [ + "eliuds-eggs-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Help Eliud count the number of eggs in her chicken coop by counting the number of 1 bits in a binary representation.", + "source": "Christian Willner, Eric Willigers", + "source_url": "https://forum.exercism.org/t/new-exercise-suggestion-pop-count/7632/5" +} diff --git a/exercises/practice/eliuds-eggs/.meta/example.el b/exercises/practice/eliuds-eggs/.meta/example.el new file mode 100644 index 00000000..b2c34603 --- /dev/null +++ b/exercises/practice/eliuds-eggs/.meta/example.el @@ -0,0 +1,18 @@ +;;; eliuds-eggs.el --- Eliud's Eggs (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun egg-count (number) + (let ((eggs 0)) + (while (> number 0) + (setq eggs (+ eggs (% number 2)) + number (truncate number 2))) + eggs)) + + +(provide 'eliuds-eggs) +;;; eliuds-eggs.el ends here + diff --git a/exercises/practice/eliuds-eggs/.meta/tests.toml b/exercises/practice/eliuds-eggs/.meta/tests.toml new file mode 100644 index 00000000..e11683c2 --- /dev/null +++ b/exercises/practice/eliuds-eggs/.meta/tests.toml @@ -0,0 +1,22 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[559e789d-07d1-4422-9004-3b699f83bca3] +description = "0 eggs" + +[97223282-f71e-490c-92f0-b3ec9e275aba] +description = "1 egg" + +[1f8fd18f-26e9-4144-9a0e-57cdfc4f4ff5] +description = "4 eggs" + +[0c18be92-a498-4ef2-bcbb-28ac4b06cb81] +description = "13 eggs" diff --git a/exercises/practice/eliuds-eggs/eliuds-eggs-test.el b/exercises/practice/eliuds-eggs/eliuds-eggs-test.el new file mode 100644 index 00000000..1d36041c --- /dev/null +++ b/exercises/practice/eliuds-eggs/eliuds-eggs-test.el @@ -0,0 +1,29 @@ +;;; eliuds-eggs-test.el --- Eliud's Eggs (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "eliuds-eggs.el") +(declare-function egg-count "eliuds-eggs.el" (number)) + + +(ert-deftest 0-eggs () + (should (= 0 (egg-count 0)))) + +(ert-deftest 1-egg () + (should (= 1 (egg-count 16)))) + + +(ert-deftest 4-eggs () + (should (= 4 (egg-count 89)))) + + +(ert-deftest 13-eggs () + (should (= 13 (egg-count 2000000000)))) + + +(provide 'eliuds-eggs-test) +;;; eliuds-eggs-test.el ends here + diff --git a/exercises/practice/eliuds-eggs/eliuds-eggs.el b/exercises/practice/eliuds-eggs/eliuds-eggs.el new file mode 100644 index 00000000..73e76022 --- /dev/null +++ b/exercises/practice/eliuds-eggs/eliuds-eggs.el @@ -0,0 +1,14 @@ +;;; eliuds-eggs.el --- Eliud's Eggs (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun egg-count (number) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'eliuds-eggs) +;;; eliuds-eggs.el ends here + From 9db080c707cb12b0d284aeeec45a0afadaec6435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Wed, 24 Apr 2024 22:25:42 -0700 Subject: [PATCH 065/162] Add resistor-color (#363) --- config.json | 8 ++++ .../resistor-color/.docs/instructions.md | 39 +++++++++++++++++++ .../practice/resistor-color/.meta/config.json | 19 +++++++++ .../practice/resistor-color/.meta/example.el | 29 ++++++++++++++ .../practice/resistor-color/.meta/tests.toml | 22 +++++++++++ .../resistor-color/resistor-color-test.el | 32 +++++++++++++++ .../practice/resistor-color/resistor-color.el | 17 ++++++++ 7 files changed, 166 insertions(+) create mode 100644 exercises/practice/resistor-color/.docs/instructions.md create mode 100644 exercises/practice/resistor-color/.meta/config.json create mode 100644 exercises/practice/resistor-color/.meta/example.el create mode 100644 exercises/practice/resistor-color/.meta/tests.toml create mode 100644 exercises/practice/resistor-color/resistor-color-test.el create mode 100644 exercises/practice/resistor-color/resistor-color.el diff --git a/config.json b/config.json index 766628f4..1da7be65 100644 --- a/config.json +++ b/config.json @@ -292,6 +292,14 @@ "integers" ] }, + { + "slug": "resistor-color", + "name": "Resistor Color", + "uuid": "dfc38e27-4c5f-416a-804e-d229e94a15b5", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "resistor-color-duo", "name": "Resistor Color Duo", diff --git a/exercises/practice/resistor-color/.docs/instructions.md b/exercises/practice/resistor-color/.docs/instructions.md new file mode 100644 index 00000000..646c1439 --- /dev/null +++ b/exercises/practice/resistor-color/.docs/instructions.md @@ -0,0 +1,39 @@ +# Instructions + +If you want to build something using a Raspberry Pi, you'll probably use _resistors_. +For this exercise, you need to know two things about them: + +- Each resistor has a resistance value. +- Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. + +To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. +Each band has a position and a numeric value. + +The first 2 bands of a resistor have a simple encoding scheme: each color maps to a single number. + +In this exercise you are going to create a helpful program so that you don't have to remember the values of the bands. + +These colors are encoded as follows: + +- Black: 0 +- Brown: 1 +- Red: 2 +- Orange: 3 +- Yellow: 4 +- Green: 5 +- Blue: 6 +- Violet: 7 +- Grey: 8 +- White: 9 + +The goal of this exercise is to create a way: + +- to look up the numerical value associated with a particular color band +- to list the different band colors + +Mnemonics map the colors to the numbers, that, when stored as an array, happen to map to their index in the array: +Better Be Right Or Your Great Big Values Go Wrong. + +More information on the color encoding of resistors can be found in the [Electronic color code Wikipedia article][e-color-code]. + +[e-color-code]: https://en.wikipedia.org/wiki/Electronic_color_code diff --git a/exercises/practice/resistor-color/.meta/config.json b/exercises/practice/resistor-color/.meta/config.json new file mode 100644 index 00000000..d6bb98cb --- /dev/null +++ b/exercises/practice/resistor-color/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "resistor-color.el" + ], + "test": [ + "resistor-color-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Convert a resistor band's color to its numeric representation.", + "source": "Maud de Vries, Erik Schierboom", + "source_url": "https://github.com/exercism/problem-specifications/issues/1458" +} diff --git a/exercises/practice/resistor-color/.meta/example.el b/exercises/practice/resistor-color/.meta/example.el new file mode 100644 index 00000000..15236b26 --- /dev/null +++ b/exercises/practice/resistor-color/.meta/example.el @@ -0,0 +1,29 @@ +;;; resistor-color.el --- Resistor Color (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(setq band-values + '(("black" . 0) + ("brown" . 1) + ("red" . 2) + ("orange" . 3) + ("yellow" . 4) + ("green" . 5) + ("blue" . 6) + ("violet" . 7) + ("grey" . 8) + ("white" . 9))) + +(defun color-code (color) + (cdr (assoc color band-values))) + +(defun colors () + (mapcar #'car band-values)) + + +(provide 'resistor-color) +;;; resistor-color.el ends here + diff --git a/exercises/practice/resistor-color/.meta/tests.toml b/exercises/practice/resistor-color/.meta/tests.toml new file mode 100644 index 00000000..9d4ee973 --- /dev/null +++ b/exercises/practice/resistor-color/.meta/tests.toml @@ -0,0 +1,22 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[49eb31c5-10a8-4180-9f7f-fea632ab87ef] +description = "Color codes -> Black" + +[0a4df94b-92da-4579-a907-65040ce0b3fc] +description = "Color codes -> White" + +[5f81608d-f36f-4190-8084-f45116b6f380] +description = "Color codes -> Orange" + +[581d68fa-f968-4be2-9f9d-880f2fb73cf7] +description = "Colors" diff --git a/exercises/practice/resistor-color/resistor-color-test.el b/exercises/practice/resistor-color/resistor-color-test.el new file mode 100644 index 00000000..6ee31443 --- /dev/null +++ b/exercises/practice/resistor-color/resistor-color-test.el @@ -0,0 +1,32 @@ +;;; resistor-color-test.el --- Resistor Color (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "resistor-color.el") +(declare-function color-code "resistor-color.el" (color)) +(declare-function colors "resistor-color.el" ()) + + +(ert-deftest black () + (should (= 0 (color-code "black")))) + + +(ert-deftest white () + (should (= 9 (color-code "white")))) + + +(ert-deftest orange () + (should (= 3 (color-code "orange")))) + + +(ert-deftest colors () + (should (equal '("black" "brown" "red" "orange" "yellow" "green" "blue" "violet" "grey" "white") + (colors)))) + + +(provide 'resistor-color-test) +;;; resistor-color-test.el ends here + diff --git a/exercises/practice/resistor-color/resistor-color.el b/exercises/practice/resistor-color/resistor-color.el new file mode 100644 index 00000000..05895c14 --- /dev/null +++ b/exercises/practice/resistor-color/resistor-color.el @@ -0,0 +1,17 @@ +;;; resistor-color.el --- Resistor Color (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun color-code (color) + (error "Delete this S-Expression and write your own implementation")) + +(defun colors () + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'resistor-color) +;;; resistor-color.el ends here + From 071c8cd0318d33045b1663aa3a845f967ab39b3d Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Sun, 5 May 2024 07:11:25 +1000 Subject: [PATCH 066/162] feat: Add exercise Triangle (closes #312) (#317) * feat: Add exercise Triangle (closes #312) * should-not --- config.json | 11 +++ .../practice/triangle/.docs/instructions.md | 29 ++++++ exercises/practice/triangle/.meta/config.json | 19 ++++ exercises/practice/triangle/.meta/example.el | 50 ++++++++++ exercises/practice/triangle/.meta/tests.toml | 73 ++++++++++++++ exercises/practice/triangle/triangle-test.el | 97 +++++++++++++++++++ exercises/practice/triangle/triangle.el | 18 ++++ 7 files changed, 297 insertions(+) create mode 100644 exercises/practice/triangle/.docs/instructions.md create mode 100644 exercises/practice/triangle/.meta/config.json create mode 100644 exercises/practice/triangle/.meta/example.el create mode 100644 exercises/practice/triangle/.meta/tests.toml create mode 100644 exercises/practice/triangle/triangle-test.el create mode 100644 exercises/practice/triangle/triangle.el diff --git a/config.json b/config.json index 1da7be65..6bd239c7 100644 --- a/config.json +++ b/config.json @@ -376,6 +376,17 @@ "recursion" ] }, + { + "slug": "triangle", + "name": "Triangle", + "uuid": "df52be2e-8709-4da5-a8c2-03a2fd137993", + "practices": [], + "prerequisites": [], + "difficulty": 2, + "topics": [ + "control_flow_conditionals" + ] + }, { "slug": "trinary", "name": "Trinary", diff --git a/exercises/practice/triangle/.docs/instructions.md b/exercises/practice/triangle/.docs/instructions.md new file mode 100644 index 00000000..ac390087 --- /dev/null +++ b/exercises/practice/triangle/.docs/instructions.md @@ -0,0 +1,29 @@ +# Instructions + +Determine if a triangle is equilateral, isosceles, or scalene. + +An _equilateral_ triangle has all three sides the same length. + +An _isosceles_ triangle has at least two sides the same length. +(It is sometimes specified as having exactly two sides the same length, but for the purposes of this exercise we'll say at least two.) + +A _scalene_ triangle has all sides of different lengths. + +## Note + +For a shape to be a triangle at all, all sides have to be of length > 0, and the sum of the lengths of any two sides must be greater than or equal to the length of the third side. + +In equations: + +Let `a`, `b`, and `c` be sides of the triangle. +Then all three of the following expressions must be true: + +```text +a + b ≥ c +b + c ≥ a +a + c ≥ b +``` + +See [Triangle Inequality][triangle-inequality] + +[triangle-inequality]: https://en.wikipedia.org/wiki/Triangle_inequality diff --git a/exercises/practice/triangle/.meta/config.json b/exercises/practice/triangle/.meta/config.json new file mode 100644 index 00000000..d402d560 --- /dev/null +++ b/exercises/practice/triangle/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "triangle.el" + ], + "test": [ + "triangle-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Determine if a triangle is equilateral, isosceles, or scalene.", + "source": "The Ruby Koans triangle project, parts 1 & 2", + "source_url": "https://web.archive.org/web/20220831105330/http://rubykoans.com" +} diff --git a/exercises/practice/triangle/.meta/example.el b/exercises/practice/triangle/.meta/example.el new file mode 100644 index 00000000..4b114b0b --- /dev/null +++ b/exercises/practice/triangle/.meta/example.el @@ -0,0 +1,50 @@ +;;; triangle.el --- Triangle (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun validp (sides) + "Return non-nil if sides are positive and triangle inequality is satisfied" + (let ((a (car sides)) + (b (cadr sides)) + (c (caddr sides))) + (and + (< 0 a) + (< 0 b) + (< 0 c) + (<= a (+ b c)) + (<= b (+ a c)) + (<= c (+ a b))))) + +(defun equilateralp (sides) + "Return non-nil if sides represent a valid equilateral triangle" + (let ((a (car sides)) + (b (cadr sides)) + (c (caddr sides))) + (and + (validp sides) + (= a b) + (= a c)))) + +(defun isoscelesp (sides) + "Return non-nil if sides represent a valid isosceles triangle" + (let ((a (car sides)) + (b (cadr sides)) + (c (caddr sides))) + (and + (validp sides) + (or + (= a b) + (= a c) + (= b c))))) + +(defun scalenep (sides) + "Return non-nil if sides represent a valid scalene triangle" + (and + (validp sides) + (not (isoscelesp sides)))) + +(provide 'triangle) +;;; triangle.el ends here diff --git a/exercises/practice/triangle/.meta/tests.toml b/exercises/practice/triangle/.meta/tests.toml new file mode 100644 index 00000000..7db09164 --- /dev/null +++ b/exercises/practice/triangle/.meta/tests.toml @@ -0,0 +1,73 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[8b2c43ac-7257-43f9-b552-7631a91988af] +description = "equilateral triangle -> all sides are equal" + +[33eb6f87-0498-4ccf-9573-7f8c3ce92b7b] +description = "equilateral triangle -> any side is unequal" + +[c6585b7d-a8c0-4ad8-8a34-e21d36f7ad87] +description = "equilateral triangle -> no sides are equal" + +[16e8ceb0-eadb-46d1-b892-c50327479251] +description = "equilateral triangle -> all zero sides is not a triangle" + +[3022f537-b8e5-4cc1-8f12-fd775827a00c] +description = "equilateral triangle -> sides may be floats" + +[cbc612dc-d75a-4c1c-87fc-e2d5edd70b71] +description = "isosceles triangle -> last two sides are equal" + +[e388ce93-f25e-4daf-b977-4b7ede992217] +description = "isosceles triangle -> first two sides are equal" + +[d2080b79-4523-4c3f-9d42-2da6e81ab30f] +description = "isosceles triangle -> first and last sides are equal" + +[8d71e185-2bd7-4841-b7e1-71689a5491d8] +description = "isosceles triangle -> equilateral triangles are also isosceles" + +[840ed5f8-366f-43c5-ac69-8f05e6f10bbb] +description = "isosceles triangle -> no sides are equal" + +[2eba0cfb-6c65-4c40-8146-30b608905eae] +description = "isosceles triangle -> first triangle inequality violation" + +[278469cb-ac6b-41f0-81d4-66d9b828f8ac] +description = "isosceles triangle -> second triangle inequality violation" + +[90efb0c7-72bb-4514-b320-3a3892e278ff] +description = "isosceles triangle -> third triangle inequality violation" + +[adb4ee20-532f-43dc-8d31-e9271b7ef2bc] +description = "isosceles triangle -> sides may be floats" + +[e8b5f09c-ec2e-47c1-abec-f35095733afb] +description = "scalene triangle -> no sides are equal" + +[2510001f-b44d-4d18-9872-2303e7977dc1] +description = "scalene triangle -> all sides are equal" + +[c6e15a92-90d9-4fb3-90a2-eef64f8d3e1e] +description = "scalene triangle -> first and second sides are equal" + +[3da23a91-a166-419a-9abf-baf4868fd985] +description = "scalene triangle -> first and third sides are equal" + +[b6a75d98-1fef-4c42-8e9a-9db854ba0a4d] +description = "scalene triangle -> second and third sides are equal" + +[70ad5154-0033-48b7-af2c-b8d739cd9fdc] +description = "scalene triangle -> may not violate triangle inequality" + +[26d9d59d-f8f1-40d3-ad58-ae4d54123d7d] +description = "scalene triangle -> sides may be floats" diff --git a/exercises/practice/triangle/triangle-test.el b/exercises/practice/triangle/triangle-test.el new file mode 100644 index 00000000..550ac12b --- /dev/null +++ b/exercises/practice/triangle/triangle-test.el @@ -0,0 +1,97 @@ +;;; triangle-test.el --- Tests for Triangle (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(load-file "triangle.el") +(declare-function equilateralp "triangle.el" (sides)) +(declare-function isoscelesp "triangle.el" (sides)) +(declare-function scalenep "triangle.el" (sides)) + + +(ert-deftest all-sides-are-equal () + (should (equilateralp '(2 2 2)))) + + +(ert-deftest any-side-is-unequal () + (should-not (equilateralp '(2 3 2)))) + + +(ert-deftest no-sides-are-equal () + (should-not (equilateralp '(5 4 6)))) + + +(ert-deftest all-zero-sides-is-not-a-triangle () + (should-not (equilateralp '(0 0 0)))) + + +(ert-deftest sides-may-be-floats () + (should (equilateralp '(0.5 0.5 0.5)))) + + +(ert-deftest last-two-sides-are-equal () + (should (isoscelesp '(3 4 4)))) + + +(ert-deftest first-two-sides-are-equal () + (should (isoscelesp '(4 4 3)))) + + +(ert-deftest first-and-last-sides-are-equal () + (should (isoscelesp '(4 3 4)))) + + +(ert-deftest equilateral-triangles-are-also-isosceles () + (should (isoscelesp '(4 4 4)))) + + +(ert-deftest no-sides-are-equal () + (should-not (isoscelesp '(2 3 4)))) + + +(ert-deftest first-triangle-inequality-violation () + (should-not (isoscelesp '(1 1 3)))) + + +(ert-deftest second-triangle-inequality-violation () + (should-not (isoscelesp '(1 3 1)))) + + +(ert-deftest third-triangle-inequality-violation () + (should-not (isoscelesp '(3 1 1)))) + + +(ert-deftest sides-may-be-floats () + (should (isoscelesp '(0.5 0.4 0.5)))) + + +(ert-deftest no-sides-are-equal () + (should (scalenep '(5 4 6)))) + + +(ert-deftest all-sides-are-equal () + (should-not (scalenep '(4 4 4)))) + + +(ert-deftest first-and-second-sides-are-equal () + (should-not (scalenep '(4 4 3)))) + + +(ert-deftest first-and-third-sides-are-equal () + (should-not (scalenep '(3 4 3)))) + + +(ert-deftest second-and-third-sides-are-equal () + (should-not (scalenep '(4 3 3)))) + + +(ert-deftest may-not-violate-triangle-inequality () + (should-not (scalenep '(7 3 2)))) + + +(ert-deftest sides-may-be-floats () + (should (scalenep '(0.5 0.4 0.6)))) + +(provide 'triangle-test) +;;; triangle-test.el ends here diff --git a/exercises/practice/triangle/triangle.el b/exercises/practice/triangle/triangle.el new file mode 100644 index 00000000..f07ec335 --- /dev/null +++ b/exercises/practice/triangle/triangle.el @@ -0,0 +1,18 @@ +;;; triangle.el --- Triangle (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun equilateralp (sides) + (error "Delete this S-Expression and write your own implementation")) + +(defun isoscelesp (sides) + (error "Delete this S-Expression and write your own implementation")) + +(defun scalenep (sides) + (error "Delete this S-Expression and write your own implementation")) + +(provide 'triangle) +;;; triangle.el ends here From 640397382b1133bc702bb5d573177113863ecb35 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Sun, 5 May 2024 07:13:08 +1000 Subject: [PATCH 067/162] feat: Add exercise Collatz Conjecture (closes #310) (#314) * feat: Add exercise Collatz Conjecture (closes #310) * error message is not checked --- config.json | 11 ++++++ .../collatz-conjecture/.docs/instructions.md | 29 ++++++++++++++ .../collatz-conjecture/.meta/config.json | 19 ++++++++++ .../collatz-conjecture/.meta/example.el | 21 ++++++++++ .../collatz-conjecture/.meta/tests.toml | 38 +++++++++++++++++++ .../collatz-conjecture-test.el | 35 +++++++++++++++++ .../collatz-conjecture/collatz-conjecture.el | 12 ++++++ 7 files changed, 165 insertions(+) create mode 100644 exercises/practice/collatz-conjecture/.docs/instructions.md create mode 100644 exercises/practice/collatz-conjecture/.meta/config.json create mode 100644 exercises/practice/collatz-conjecture/.meta/example.el create mode 100644 exercises/practice/collatz-conjecture/.meta/tests.toml create mode 100644 exercises/practice/collatz-conjecture/collatz-conjecture-test.el create mode 100644 exercises/practice/collatz-conjecture/collatz-conjecture.el diff --git a/config.json b/config.json index 6bd239c7..7129c01e 100644 --- a/config.json +++ b/config.json @@ -101,6 +101,17 @@ "strings" ] }, + { + "slug": "collatz-conjecture", + "name": "Collatz Conjecture", + "uuid": "1eadc0d0-2086-4ab4-a53c-386933bf30f8", + "practices": [], + "prerequisites": [], + "difficulty": 2, + "topics": [ + "math" + ] + }, { "slug": "darts", "name": "Darts", diff --git a/exercises/practice/collatz-conjecture/.docs/instructions.md b/exercises/practice/collatz-conjecture/.docs/instructions.md new file mode 100644 index 00000000..ba060483 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.docs/instructions.md @@ -0,0 +1,29 @@ +# Instructions + +The Collatz Conjecture or 3x+1 problem can be summarized as follows: + +Take any positive integer n. +If n is even, divide n by 2 to get n / 2. +If n is odd, multiply n by 3 and add 1 to get 3n + 1. +Repeat the process indefinitely. +The conjecture states that no matter which number you start with, you will always reach 1 eventually. + +Given a number n, return the number of steps required to reach 1. + +## Examples + +Starting with n = 12, the steps would be as follows: + +0. 12 +1. 6 +2. 3 +3. 10 +4. 5 +5. 16 +6. 8 +7. 4 +8. 2 +9. 1 + +Resulting in 9 steps. +So for input n = 12, the return value would be 9. diff --git a/exercises/practice/collatz-conjecture/.meta/config.json b/exercises/practice/collatz-conjecture/.meta/config.json new file mode 100644 index 00000000..bcbe5f22 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "collatz-conjecture.el" + ], + "test": [ + "collatz-conjecture-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Calculate the number of steps to reach 1 using the Collatz conjecture.", + "source": "An unsolved problem in mathematics named after mathematician Lothar Collatz", + "source_url": "https://en.wikipedia.org/wiki/3x_%2B_1_problem" +} diff --git a/exercises/practice/collatz-conjecture/.meta/example.el b/exercises/practice/collatz-conjecture/.meta/example.el new file mode 100644 index 00000000..391f47c0 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.meta/example.el @@ -0,0 +1,21 @@ +;;; collatz-conjecture.el --- Collatz Conjecture (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun steps (number) + "Count the steps to reach 1 using the Collatz conjecture." + (unless (< 0 number) (error "Only positive integers are allowed")) + (cl-labels + ((recur (n count) + (cond + ((= 0 (mod n 2)) (funcall #'recur (/ n 2) (+ 1 count))) + ((< 1 n) (funcall #'recur (+ 1 (* 3 n)) (+ 1 count))) + (t count)))) + (funcall #'recur number 0))) + +(provide 'collatz-conjecture) +;;; collatz-conjecture.el ends here diff --git a/exercises/practice/collatz-conjecture/.meta/tests.toml b/exercises/practice/collatz-conjecture/.meta/tests.toml new file mode 100644 index 00000000..cc34e168 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.meta/tests.toml @@ -0,0 +1,38 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[540a3d51-e7a6-47a5-92a3-4ad1838f0bfd] +description = "zero steps for one" + +[3d76a0a6-ea84-444a-821a-f7857c2c1859] +description = "divide if even" + +[754dea81-123c-429e-b8bc-db20b05a87b9] +description = "even and odd steps" + +[ecfd0210-6f85-44f6-8280-f65534892ff6] +description = "large number of even and odd steps" + +[7d4750e6-def9-4b86-aec7-9f7eb44f95a3] +description = "zero is an error" +include = false + +[2187673d-77d6-4543-975e-66df6c50e2da] +description = "zero is an error" +reimplements = "7d4750e6-def9-4b86-aec7-9f7eb44f95a3" + +[c6c795bf-a288-45e9-86a1-841359ad426d] +description = "negative value is an error" +include = false + +[ec11f479-56bc-47fd-a434-bcd7a31a7a2e] +description = "negative value is an error" +reimplements = "c6c795bf-a288-45e9-86a1-841359ad426d" diff --git a/exercises/practice/collatz-conjecture/collatz-conjecture-test.el b/exercises/practice/collatz-conjecture/collatz-conjecture-test.el new file mode 100644 index 00000000..3c8197da --- /dev/null +++ b/exercises/practice/collatz-conjecture/collatz-conjecture-test.el @@ -0,0 +1,35 @@ +;;; collatz-conjecture-test.el --- Tests for Collatz Conjecture (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(load-file "collatz-conjecture.el") +(declare-function steps "collatz-conjecture.el" (number)) + + +(ert-deftest zero-steps-for-one () + (should (equal 0 (steps 1)))) + + +(ert-deftest divide-if-even () + (should (equal 4 (steps 16)))) + + +(ert-deftest even-and-odd-steps () + (should (equal 9 (steps 12)))) + + +(ert-deftest large-number-of-even-and-odd-steps () + (should (equal 152 (steps 1000000)))) + + +(ert-deftest zero-is-an-error () + (should-error (steps 0))) + + +(ert-deftest negative-value-is-an-error () + (should-error (steps -15))) + +(provide 'collatz-conjecture-test) +;;; collatz-conjecture-test.el ends here diff --git a/exercises/practice/collatz-conjecture/collatz-conjecture.el b/exercises/practice/collatz-conjecture/collatz-conjecture.el new file mode 100644 index 00000000..6d2b56df --- /dev/null +++ b/exercises/practice/collatz-conjecture/collatz-conjecture.el @@ -0,0 +1,12 @@ +;;; collatz-conjecture.el --- Collatz Conjecture (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(defun steps (number) + "Count the steps to reach 1 using the Collatz conjecture." + (error "Delete this S-Expression and write your own implementation")) + +(provide 'collatz-conjecture) +;;; collatz-conjecture.el ends here From 883678717a92873e8ac90176c55267b1322507f2 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Mon, 6 May 2024 05:09:45 +1000 Subject: [PATCH 068/162] Add largest-series-product exercise (#365) --- config.json | 12 ++++ .../.docs/instructions.md | 26 +++++++ .../.docs/introduction.md | 5 ++ .../largest-series-product/.meta/config.json | 19 +++++ .../largest-series-product/.meta/example.el | 26 +++++++ .../largest-series-product/.meta/tests.toml | 60 ++++++++++++++++ .../largest-series-product-test.el | 72 +++++++++++++++++++ .../largest-series-product.el | 13 ++++ 8 files changed, 233 insertions(+) create mode 100644 exercises/practice/largest-series-product/.docs/instructions.md create mode 100644 exercises/practice/largest-series-product/.docs/introduction.md create mode 100644 exercises/practice/largest-series-product/.meta/config.json create mode 100644 exercises/practice/largest-series-product/.meta/example.el create mode 100644 exercises/practice/largest-series-product/.meta/tests.toml create mode 100644 exercises/practice/largest-series-product/largest-series-product-test.el create mode 100644 exercises/practice/largest-series-product/largest-series-product.el diff --git a/config.json b/config.json index 7129c01e..1711d0aa 100644 --- a/config.json +++ b/config.json @@ -420,6 +420,18 @@ "strings" ] }, + { + "slug": "largest-series-product", + "name": "Largest Series Product", + "uuid": "91b2ba1a-8995-4c5c-9682-1ef462cbcbf5", + "practices": [], + "prerequisites": [], + "difficulty": 4, + "topics": [ + "control_flow_loops", + "strings" + ] + }, { "slug": "affine-cipher", "name": "Affine Cipher", diff --git a/exercises/practice/largest-series-product/.docs/instructions.md b/exercises/practice/largest-series-product/.docs/instructions.md new file mode 100644 index 00000000..f297b57f --- /dev/null +++ b/exercises/practice/largest-series-product/.docs/instructions.md @@ -0,0 +1,26 @@ +# Instructions + +Your task is to look for patterns in the long sequence of digits in the encrypted signal. + +The technique you're going to use here is called the largest series product. + +Let's define a few terms, first. + +- **input**: the sequence of digits that you need to analyze +- **series**: a sequence of adjacent digits (those that are next to each other) that is contained within the input +- **span**: how many digits long each series is +- **product**: what you get when you multiply numbers together + +Let's work through an example, with the input `"63915"`. + +- To form a series, take adjacent digits in the original input. +- If you are working with a span of `3`, there will be three possible series: + - `"639"` + - `"391"` + - `"915"` +- Then we need to calculate the product of each series: + - The product of the series `"639"` is 162 (`6 × 3 × 9 = 162`) + - The product of the series `"391"` is 27 (`3 × 9 × 1 = 27`) + - The product of the series `"915"` is 45 (`9 × 1 × 5 = 45`) +- 162 is bigger than both 27 and 45, so the largest series product of `"63915"` is from the series `"639"`. + So the answer is **162**. diff --git a/exercises/practice/largest-series-product/.docs/introduction.md b/exercises/practice/largest-series-product/.docs/introduction.md new file mode 100644 index 00000000..597bb5fa --- /dev/null +++ b/exercises/practice/largest-series-product/.docs/introduction.md @@ -0,0 +1,5 @@ +# Introduction + +You work for a government agency that has intercepted a series of encrypted communication signals from a group of bank robbers. +The signals contain a long sequence of digits. +Your team needs to use various digital signal processing techniques to analyze the signals and identify any patterns that may indicate the planning of a heist. diff --git a/exercises/practice/largest-series-product/.meta/config.json b/exercises/practice/largest-series-product/.meta/config.json new file mode 100644 index 00000000..71fd6a42 --- /dev/null +++ b/exercises/practice/largest-series-product/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "largest-series-product.el" + ], + "test": [ + "largest-series-product-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given a string of digits, calculate the largest product for a contiguous substring of digits of length n.", + "source": "A variation on Problem 8 at Project Euler", + "source_url": "https://projecteuler.net/problem=8" +} diff --git a/exercises/practice/largest-series-product/.meta/example.el b/exercises/practice/largest-series-product/.meta/example.el new file mode 100644 index 00000000..b7ec9bba --- /dev/null +++ b/exercises/practice/largest-series-product/.meta/example.el @@ -0,0 +1,26 @@ +;;; largest-series-product.el --- Largest Series Product (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun largest-product (digits span) + (when (< span 0) + (error "span must not be negative")) + (when (> span (length digits)) + (error "span must be smaller than string length")) + (unless (cl-every 'cl-digit-char-p (cl-coerce digits 'list)) + (error "digits input must only contain digits")) + (let ((largest 0)) + (dotimes (i (+ 1 (- (length digits) span))) + (let ((product 1)) + (dotimes (j span) + (setq product (* product (cl-digit-char-p (aref digits (+ i j)))))) + (when (< largest product) + (setq largest product)))) + largest)) + +(provide 'largest-series-product) +;;; largest-series-product.el ends here diff --git a/exercises/practice/largest-series-product/.meta/tests.toml b/exercises/practice/largest-series-product/.meta/tests.toml new file mode 100644 index 00000000..6c111adf --- /dev/null +++ b/exercises/practice/largest-series-product/.meta/tests.toml @@ -0,0 +1,60 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[7c82f8b7-e347-48ee-8a22-f672323324d4] +description = "finds the largest product if span equals length" + +[88523f65-21ba-4458-a76a-b4aaf6e4cb5e] +description = "can find the largest product of 2 with numbers in order" + +[f1376b48-1157-419d-92c2-1d7e36a70b8a] +description = "can find the largest product of 2" + +[46356a67-7e02-489e-8fea-321c2fa7b4a4] +description = "can find the largest product of 3 with numbers in order" + +[a2dcb54b-2b8f-4993-92dd-5ce56dece64a] +description = "can find the largest product of 3" + +[673210a3-33cd-4708-940b-c482d7a88f9d] +description = "can find the largest product of 5 with numbers in order" + +[02acd5a6-3bbf-46df-8282-8b313a80a7c9] +description = "can get the largest product of a big number" + +[76dcc407-21e9-424c-a98e-609f269622b5] +description = "reports zero if the only digits are zero" + +[6ef0df9f-52d4-4a5d-b210-f6fae5f20e19] +description = "reports zero if all spans include zero" + +[5d81aaf7-4f67-4125-bf33-11493cc7eab7] +description = "rejects span longer than string length" + +[06bc8b90-0c51-4c54-ac22-3ec3893a079e] +description = "reports 1 for empty string and empty product (0 span)" + +[3ec0d92e-f2e2-4090-a380-70afee02f4c0] +description = "reports 1 for nonempty string and empty product (0 span)" + +[6d96c691-4374-4404-80ee-2ea8f3613dd4] +description = "rejects empty string and nonzero span" + +[7a38f2d6-3c35-45f6-8d6f-12e6e32d4d74] +description = "rejects invalid character in digits" + +[5fe3c0e5-a945-49f2-b584-f0814b4dd1ef] +description = "rejects negative span" +include = false + +[c859f34a-9bfe-4897-9c2f-6d7f8598e7f0] +description = "rejects negative span" +reimplements = "5fe3c0e5-a945-49f2-b584-f0814b4dd1ef" diff --git a/exercises/practice/largest-series-product/largest-series-product-test.el b/exercises/practice/largest-series-product/largest-series-product-test.el new file mode 100644 index 00000000..ef629bbb --- /dev/null +++ b/exercises/practice/largest-series-product/largest-series-product-test.el @@ -0,0 +1,72 @@ +;;; largest-series-product-test.el --- Tests for Largest Series Product (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(load-file "largest-series-product.el") +(declare-function largest-product "largest-series-product.el" (digits span)) + + +(ert-deftest finds-the-largest-product-if-span-equals-length () + (should (equal 18 (largest-product "29" 2)))) + + +(ert-deftest can-find-the-largest-product-of-2-with-numbers-in-order () + (should (equal 72 (largest-product "0123456789" 2)))) + + +(ert-deftest can-find-the-largest-product-of-2 () + (should (equal 48 (largest-product "576802143" 2)))) + + +(ert-deftest can-find-the-largest-product-of-3-with-numbers-in-order () + (should (equal 504 (largest-product "0123456789" 3)))) + + +(ert-deftest can-find-the-largest-product-of-3 () + (should (equal 270 (largest-product "1027839564" 3)))) + + +(ert-deftest can-find-the-largest-product-of-5-with-numbers-in-order () + (should (equal 15120 (largest-product "0123456789" 5)))) + + +(ert-deftest can-get-the-largest-product-of-a-big-number () + (should (equal 23520 (largest-product "73167176531330624919225119674426574742355349194934" 6)))) + + +(ert-deftest reports-zero-if-the-only-digits-are-zero () + (should (equal 0 (largest-product "0000" 2)))) + + +(ert-deftest reports-zero-if-all-spans-include-zero () + (should (equal 0 (largest-product "99099" 3)))) + + +(ert-deftest rejects-span-longer-than-string-length () + (should-error (largest-product "123" 4))) + + +(ert-deftest reports-1-for-empty-string-and-empty-product-zero-span () + (should (equal 1 (largest-product "" 0)))) + + +(ert-deftest reports-1-for-nonempty-string-and-empty-product-zero-span () + (should (equal 1 (largest-product "123" 0)))) + + +(ert-deftest rejects-empty-string-and-nonzero-span () + (should-error (largest-product "" 1))) + + +(ert-deftest rejects-invalid-character-in-digits () + (should-error (largest-product "1234a5" 2))) + + +(ert-deftest rejects-negative-span () + (should-error (largest-product "12345" -1))) + + +(provide 'largest-series-product-test) +;;; largest-series-product-test.el ends here diff --git a/exercises/practice/largest-series-product/largest-series-product.el b/exercises/practice/largest-series-product/largest-series-product.el new file mode 100644 index 00000000..0d422755 --- /dev/null +++ b/exercises/practice/largest-series-product/largest-series-product.el @@ -0,0 +1,13 @@ +;;; largest-series-product.el --- Largest Series Product (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun largest-product (digits span) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'largest-series-product) +;;; largest-series-product.el ends here From 122c82ee981be487630d67ce69f22068aa290030 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Mon, 6 May 2024 09:12:42 +1000 Subject: [PATCH 069/162] Add isogram exercise (#366) --- config.json | 12 ++++ .../practice/isogram/.docs/instructions.md | 14 ++++ exercises/practice/isogram/.meta/config.json | 19 ++++++ exercises/practice/isogram/.meta/example.el | 27 ++++++++ exercises/practice/isogram/.meta/tests.toml | 52 ++++++++++++++ exercises/practice/isogram/isogram-test.el | 68 +++++++++++++++++++ exercises/practice/isogram/isogram.el | 13 ++++ 7 files changed, 205 insertions(+) create mode 100644 exercises/practice/isogram/.docs/instructions.md create mode 100644 exercises/practice/isogram/.meta/config.json create mode 100644 exercises/practice/isogram/.meta/example.el create mode 100644 exercises/practice/isogram/.meta/tests.toml create mode 100644 exercises/practice/isogram/isogram-test.el create mode 100644 exercises/practice/isogram/isogram.el diff --git a/config.json b/config.json index 1711d0aa..8152e58c 100644 --- a/config.json +++ b/config.json @@ -195,6 +195,18 @@ "strings" ] }, + { + "slug": "isogram", + "name": "Isogram", + "uuid": "63fc7e59-2448-487b-9b66-06c72ab8d6b0", + "practices": [], + "prerequisites": [], + "difficulty": 2, + "topics": [ + "control_flow_loops", + "strings" + ] + }, { "slug": "leap", "name": "Leap", diff --git a/exercises/practice/isogram/.docs/instructions.md b/exercises/practice/isogram/.docs/instructions.md new file mode 100644 index 00000000..2e8df851 --- /dev/null +++ b/exercises/practice/isogram/.docs/instructions.md @@ -0,0 +1,14 @@ +# Instructions + +Determine if a word or phrase is an isogram. + +An isogram (also known as a "non-pattern word") is a word or phrase without a repeating letter, however spaces and hyphens are allowed to appear multiple times. + +Examples of isograms: + +- lumberjacks +- background +- downstream +- six-year-old + +The word _isograms_, however, is not an isogram, because the s repeats. diff --git a/exercises/practice/isogram/.meta/config.json b/exercises/practice/isogram/.meta/config.json new file mode 100644 index 00000000..0a57ef77 --- /dev/null +++ b/exercises/practice/isogram/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "isogram.el" + ], + "test": [ + "isogram-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Determine if a word or phrase is an isogram.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Isogram" +} diff --git a/exercises/practice/isogram/.meta/example.el b/exercises/practice/isogram/.meta/example.el new file mode 100644 index 00000000..d63dd40f --- /dev/null +++ b/exercises/practice/isogram/.meta/example.el @@ -0,0 +1,27 @@ +;;; isogram.el --- isogram (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun upper-char-p (c) + "Determine if char C is alphabetic and upper case." + (and + (>= c ?A) + (<= c ?Z))) + +(defun isogramp (phrase) + "Determine if a given phrase is an isogram." + (let* ((bitset 0) + (updated 0) + (characters (cl-coerce (upcase phrase) 'list)) + (letters (cl-remove-if-not 'upper-char-p characters))) + (cl-loop for c in letters + do (setq updated (logior bitset (lsh 1 (- c ?A)))) + always (> updated bitset) + do (setq bitset updated)))) + +(provide 'isogram) +;;; isogram.el ends here diff --git a/exercises/practice/isogram/.meta/tests.toml b/exercises/practice/isogram/.meta/tests.toml new file mode 100644 index 00000000..ba04c664 --- /dev/null +++ b/exercises/practice/isogram/.meta/tests.toml @@ -0,0 +1,52 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[a0e97d2d-669e-47c7-8134-518a1e2c4555] +description = "empty string" + +[9a001b50-f194-4143-bc29-2af5ec1ef652] +description = "isogram with only lower case characters" + +[8ddb0ca3-276e-4f8b-89da-d95d5bae78a4] +description = "word with one duplicated character" + +[6450b333-cbc2-4b24-a723-0b459b34fe18] +description = "word with one duplicated character from the end of the alphabet" + +[a15ff557-dd04-4764-99e7-02cc1a385863] +description = "longest reported english isogram" + +[f1a7f6c7-a42f-4915-91d7-35b2ea11c92e] +description = "word with duplicated character in mixed case" + +[14a4f3c1-3b47-4695-b645-53d328298942] +description = "word with duplicated character in mixed case, lowercase first" + +[423b850c-7090-4a8a-b057-97f1cadd7c42] +description = "hypothetical isogrammic word with hyphen" + +[93dbeaa0-3c5a-45c2-8b25-428b8eacd4f2] +description = "hypothetical word with duplicated character following hyphen" + +[36b30e5c-173f-49c6-a515-93a3e825553f] +description = "isogram with duplicated hyphen" + +[cdabafa0-c9f4-4c1f-b142-689c6ee17d93] +description = "made-up name that is an isogram" + +[5fc61048-d74e-48fd-bc34-abfc21552d4d] +description = "duplicated character in the middle" + +[310ac53d-8932-47bc-bbb4-b2b94f25a83e] +description = "same first and last characters" + +[0d0b8644-0a1e-4a31-a432-2b3ee270d847] +description = "word with duplicated character and with two hyphens" diff --git a/exercises/practice/isogram/isogram-test.el b/exercises/practice/isogram/isogram-test.el new file mode 100644 index 00000000..6fbdbd51 --- /dev/null +++ b/exercises/practice/isogram/isogram-test.el @@ -0,0 +1,68 @@ +;;; isogram-test.el --- Tests for Isogram (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(load-file "isogram.el") +(declare-function isogramp "isogram.el" (phrase)) + + +(ert-deftest empty-string () + (should (isogramp ""))) + + +(ert-deftest isogram-with-only-lower-case-characters () + (should (isogramp "isogram"))) + + +(ert-deftest word-with-one-duplicated-character () + (should-not (isogramp "eleven"))) + + +(ert-deftest word-with-one-duplicated-character-from-the-end-of-the-alphabet () + (should-not (isogramp "zzyzx"))) + + +(ert-deftest longest-reported-english-isogram () + (should (isogramp "subdermatoglyphic"))) + + +(ert-deftest word-with-duplicated-character-in-mixed-case () + (should-not (isogramp "Alphabet"))) + + +(ert-deftest word-with-duplicated-character-in-mixed-case-lowercase-first () + (should-not (isogramp "alphAbet"))) + + +(ert-deftest hypothetical-isogrammic-word-with-hyphen () + (should (isogramp "thumbscrew-japingly"))) + + +(ert-deftest hypothetical-word-with-duplicated-character-following-hyphen () + (should-not (isogramp "thumbscrew-jappingly"))) + + +(ert-deftest isogram-with-duplicated-hyphen () + (should (isogramp "six-year-old"))) + + +(ert-deftest made-up-name-that-is-an-isogram () + (should (isogramp "Emily Jung Schwartzkopf"))) + + +(ert-deftest duplicated-character-in-the-middle () + (should-not (isogramp "accentor"))) + + +(ert-deftest same-first-and-last-characters () + (should-not (isogramp "angola"))) + + +(ert-deftest word-with-duplicated-character-and-with-two-hyphens () + (should-not (isogramp "up-to-date"))) + + +(provide 'isogram-test) +;;; isogram-test.el ends here diff --git a/exercises/practice/isogram/isogram.el b/exercises/practice/isogram/isogram.el new file mode 100644 index 00000000..699f0685 --- /dev/null +++ b/exercises/practice/isogram/isogram.el @@ -0,0 +1,13 @@ +;;; isogram.el --- isogram (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun isogramp (phrase) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'isogram) +;;; isogram.el ends here From ba48526ef2c5410d5aaf43cb883db8c8b44d6d7d Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Mon, 6 May 2024 23:51:20 +1000 Subject: [PATCH 070/162] Add kindergarten-garden exercise (#369) --- config.json | 11 +++ .../kindergarten-garden/.docs/instructions.md | 58 ++++++++++++++ .../kindergarten-garden/.meta/config.json | 19 +++++ .../kindergarten-garden/.meta/example.el | 25 ++++++ .../kindergarten-garden/.meta/tests.toml | 61 ++++++++++++++ .../kindergarten-garden-test.el | 80 +++++++++++++++++++ .../kindergarten-garden.el | 13 +++ 7 files changed, 267 insertions(+) create mode 100644 exercises/practice/kindergarten-garden/.docs/instructions.md create mode 100644 exercises/practice/kindergarten-garden/.meta/config.json create mode 100644 exercises/practice/kindergarten-garden/.meta/example.el create mode 100644 exercises/practice/kindergarten-garden/.meta/tests.toml create mode 100644 exercises/practice/kindergarten-garden/kindergarten-garden-test.el create mode 100644 exercises/practice/kindergarten-garden/kindergarten-garden.el diff --git a/config.json b/config.json index 8152e58c..826c2c29 100644 --- a/config.json +++ b/config.json @@ -207,6 +207,17 @@ "strings" ] }, + { + "slug": "kindergarten-garden", + "name": "Kindergarten Garden", + "uuid": "798056fc-11df-4705-b783-6eee56e6a1e2", + "practices": [], + "prerequisites": [], + "difficulty": 2, + "topics": [ + "strings" + ] + }, { "slug": "leap", "name": "Leap", diff --git a/exercises/practice/kindergarten-garden/.docs/instructions.md b/exercises/practice/kindergarten-garden/.docs/instructions.md new file mode 100644 index 00000000..472ee26f --- /dev/null +++ b/exercises/practice/kindergarten-garden/.docs/instructions.md @@ -0,0 +1,58 @@ +# Instructions + +Given a diagram, determine which plants each child in the kindergarten class is +responsible for. + +The kindergarten class is learning about growing plants. +The teacher thought it would be a good idea to give them actual seeds, plant them in actual dirt, and grow actual plants. + +They've chosen to grow grass, clover, radishes, and violets. + +To this end, the children have put little cups along the window sills, and +planted one type of plant in each cup, choosing randomly from the available +types of seeds. + +```text +[window][window][window] +........................ # each dot represents a cup +........................ +``` + +There are 12 children in the class: + +- Alice, Bob, Charlie, David, +- Eve, Fred, Ginny, Harriet, +- Ileana, Joseph, Kincaid, and Larry. + +Each child gets 4 cups, two on each row. +Their teacher assigns cups to the children alphabetically by their names. + +The following diagram represents Alice's plants: + +```text +[window][window][window] +VR...................... +RG...................... +``` + +In the first row, nearest the windows, she has a violet and a radish. +In the second row she has a radish and some grass. + +Your program will be given the plants from left-to-right starting with the row nearest the windows. +From this, it should be able to determine which plants belong to each student. + +For example, if it's told that the garden looks like so: + +```text +[window][window][window] +VRCGVVRVCGGCCGVRGCVCGCGV +VRCCCGCRRGVCGCRVVCVGCGCV +``` + +Then if asked for Alice's plants, it should provide: + +- Violets, radishes, violets, radishes + +While asking for Bob's plants would yield: + +- Clover, grass, clover, clover diff --git a/exercises/practice/kindergarten-garden/.meta/config.json b/exercises/practice/kindergarten-garden/.meta/config.json new file mode 100644 index 00000000..3c33e492 --- /dev/null +++ b/exercises/practice/kindergarten-garden/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "kindergarten-garden.el" + ], + "test": [ + "kindergarten-garden-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given a diagram, determine which plants each child in the kindergarten class is responsible for.", + "source": "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/kindergarten-garden/.meta/example.el b/exercises/practice/kindergarten-garden/.meta/example.el new file mode 100644 index 00000000..0dc8de8e --- /dev/null +++ b/exercises/practice/kindergarten-garden/.meta/example.el @@ -0,0 +1,25 @@ +;;; kindergarten-garden.el --- Kindergarten Garden (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun plants (diagram student) + (cl-flet ((plant (index) + (cl-case (aref diagram index) + (?G "grass") + (?C "clover") + (?R "radishes") + (?V "violets")))) + (let* ((midpoint (/ (1+ (length diagram)) 2)) + (student_index (- (aref student 0) ?A)) + (first (* 2 student_index)) + (second (1+ first)) + (third (+ midpoint first)) + (fourth (1+ third))) + (mapcar #'plant (list first second third fourth))))) + +(provide 'plants) +;;; kindergarten-garden.el ends here diff --git a/exercises/practice/kindergarten-garden/.meta/tests.toml b/exercises/practice/kindergarten-garden/.meta/tests.toml new file mode 100644 index 00000000..0cdd9ad6 --- /dev/null +++ b/exercises/practice/kindergarten-garden/.meta/tests.toml @@ -0,0 +1,61 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[1fc316ed-17ab-4fba-88ef-3ae78296b692] +description = "partial garden -> garden with single student" + +[acd19dc1-2200-4317-bc2a-08f021276b40] +description = "partial garden -> different garden with single student" + +[c376fcc8-349c-446c-94b0-903947315757] +description = "partial garden -> garden with two students" + +[2d620f45-9617-4924-9d27-751c80d17db9] +description = "partial garden -> multiple students for the same garden with three students -> second student's garden" + +[57712331-4896-4364-89f8-576421d69c44] +description = "partial garden -> multiple students for the same garden with three students -> third student's garden" + +[149b4290-58e1-40f2-8ae4-8b87c46e765b] +description = "full garden -> for Alice, first student's garden" + +[ba25dbbc-10bd-4a37-b18e-f89ecd098a5e] +description = "full garden -> for Bob, second student's garden" + +[566b621b-f18e-4c5f-873e-be30544b838c] +description = "full garden -> for Charlie" + +[3ad3df57-dd98-46fc-9269-1877abf612aa] +description = "full garden -> for David" + +[0f0a55d1-9710-46ed-a0eb-399ba8c72db2] +description = "full garden -> for Eve" + +[a7e80c90-b140-4ea1-aee3-f4625365c9a4] +description = "full garden -> for Fred" + +[9d94b273-2933-471b-86e8-dba68694c615] +description = "full garden -> for Ginny" + +[f55bc6c2-ade8-4844-87c4-87196f1b7258] +description = "full garden -> for Harriet" + +[759070a3-1bb1-4dd4-be2c-7cce1d7679ae] +description = "full garden -> for Ileana" + +[78578123-2755-4d4a-9c7d-e985b8dda1c6] +description = "full garden -> for Joseph" + +[6bb66df7-f433-41ab-aec2-3ead6e99f65b] +description = "full garden -> for Kincaid, second to last student's garden" + +[d7edec11-6488-418a-94e6-ed509e0fa7eb] +description = "full garden -> for Larry, last student's garden" diff --git a/exercises/practice/kindergarten-garden/kindergarten-garden-test.el b/exercises/practice/kindergarten-garden/kindergarten-garden-test.el new file mode 100644 index 00000000..6755de71 --- /dev/null +++ b/exercises/practice/kindergarten-garden/kindergarten-garden-test.el @@ -0,0 +1,80 @@ +;;; kindergarten-garden-test.el --- Tests for Kindergarten Garden (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(load-file "kindergarten-garden.el") +(declare-function plants "kindergarten-garden.el" (diagram student)) + + +(ert-deftest partial-garden-with-single-student () + (should (equal '("radishes" "clover" "grass" "grass") (plants "RC\nGG" "Alice")))) + + +(ert-deftest partial-garden-different-garden-with-single-student () + (should (equal '("violets" "clover" "radishes" "clover") (plants "VC\nRC" "Alice")))) + + +(ert-deftest partial-garden-with-two-students () + (should (equal '("clover" "grass" "radishes" "clover") (plants "VVCG\nVVRC" "Bob")))) + + +(ert-deftest partial-garden-multiple-students-for-the-same-garden-with-three-students-second-students-garden () + (should (equal '("clover" "clover" "clover" "clover") (plants "VVCCGG\nVVCCGG" "Bob")))) + + +(ert-deftest partial-garden-multiple-students-for-the-same-garden-with-three-students-third-students-garden () + (should (equal '("grass" "grass" "grass" "grass") (plants "VVCCGG\nVVCCGG" "Charlie")))) + + +(ert-deftest full-garden-for-alice-first-students-garden () + (should (equal '("violets" "radishes" "violets" "radishes") (plants "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" "Alice")))) + + +(ert-deftest full-garden-for-bob-second-students-garden () + (should (equal '("clover" "grass" "clover" "clover") (plants "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" "Bob")))) + + +(ert-deftest full-garden-for-charlie () + (should (equal '("violets" "violets" "clover" "grass") (plants "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" "Charlie")))) + + +(ert-deftest full-garden-for-david () + (should (equal '("radishes" "violets" "clover" "radishes") (plants "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" "David")))) + + +(ert-deftest full-garden-for-eve () + (should (equal '("clover" "grass" "radishes" "grass") (plants "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" "Eve")))) + + +(ert-deftest full-garden-for-fred () + (should (equal '("grass" "clover" "violets" "clover") (plants "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" "Fred")))) + + +(ert-deftest full-garden-for-ginny () + (should (equal '("clover" "grass" "grass" "clover") (plants "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" "Ginny")))) + + +(ert-deftest full-garden-for-harriet () + (should (equal '("violets" "radishes" "radishes" "violets") (plants "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" "Harriet")))) + + +(ert-deftest full-garden-for-ileana () + (should (equal '("grass" "clover" "violets" "clover") (plants "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" "Ileana")))) + + +(ert-deftest full-garden-for-joseph () + (should (equal '("violets" "clover" "violets" "grass") (plants "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" "Joseph")))) + + +(ert-deftest full-garden-for-kincaid-second-to-last-students-garden () + (should (equal '("grass" "clover" "clover" "grass") (plants "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" "Kincaid")))) + + +(ert-deftest full-garden-for-larry-last-students-garden () + (should (equal '("grass" "violets" "clover" "violets") (plants "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" "Larry")))) + + +(provide 'kindergarten-garden-test) +;;; kindergarten-garden-test.el ends here diff --git a/exercises/practice/kindergarten-garden/kindergarten-garden.el b/exercises/practice/kindergarten-garden/kindergarten-garden.el new file mode 100644 index 00000000..575dc4fc --- /dev/null +++ b/exercises/practice/kindergarten-garden/kindergarten-garden.el @@ -0,0 +1,13 @@ +;;; kindergarten-garden.el --- Kindergarten Garden (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun plants (diagram student) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'plants) +;;; kindergarten-garden.el ends here From 4be6cce04d8c7574a31d43a7a63e75e9a9923f77 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Mon, 6 May 2024 23:52:48 +1000 Subject: [PATCH 071/162] Add isbn-verifier exercise (#370) --- config.json | 8 ++ .../isbn-verifier/.docs/instructions.md | 42 +++++++++ .../practice/isbn-verifier/.meta/config.json | 19 ++++ .../practice/isbn-verifier/.meta/example.el | 23 +++++ .../practice/isbn-verifier/.meta/tests.toml | 67 ++++++++++++++ .../isbn-verifier/isbn-verifier-test.el | 88 +++++++++++++++++++ .../practice/isbn-verifier/isbn-verifier.el | 13 +++ 7 files changed, 260 insertions(+) create mode 100644 exercises/practice/isbn-verifier/.docs/instructions.md create mode 100644 exercises/practice/isbn-verifier/.meta/config.json create mode 100644 exercises/practice/isbn-verifier/.meta/example.el create mode 100644 exercises/practice/isbn-verifier/.meta/tests.toml create mode 100644 exercises/practice/isbn-verifier/isbn-verifier-test.el create mode 100644 exercises/practice/isbn-verifier/isbn-verifier.el diff --git a/config.json b/config.json index 826c2c29..d46f9db4 100644 --- a/config.json +++ b/config.json @@ -607,6 +607,14 @@ "filtering", "strings" ] + }, + { + "slug": "isbn-verifier", + "name": "Isbn Verifier", + "uuid": "b0cbc3b5-1d6c-40b8-bdd1-5ba9089024aa", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, diff --git a/exercises/practice/isbn-verifier/.docs/instructions.md b/exercises/practice/isbn-verifier/.docs/instructions.md new file mode 100644 index 00000000..4a0244e5 --- /dev/null +++ b/exercises/practice/isbn-verifier/.docs/instructions.md @@ -0,0 +1,42 @@ +# Instructions + +The [ISBN-10 verification process][isbn-verification] 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 +(d₁ * 10 + d₂ * 9 + d₃ * 8 + d₄ * 7 + d₅ * 6 + d₆ * 5 + d₇ * 4 + d₈ * 3 + d₉ * 2 + d₁₀ * 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. + +[isbn-verification]: https://en.wikipedia.org/wiki/International_Standard_Book_Number diff --git a/exercises/practice/isbn-verifier/.meta/config.json b/exercises/practice/isbn-verifier/.meta/config.json new file mode 100644 index 00000000..c013be1e --- /dev/null +++ b/exercises/practice/isbn-verifier/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "isbn-verifier.el" + ], + "test": [ + "isbn-verifier-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Check if a given string is a valid ISBN-10 number.", + "source": "Converting a string into a number and some basic processing utilizing a relatable real world example.", + "source_url": "https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation" +} diff --git a/exercises/practice/isbn-verifier/.meta/example.el b/exercises/practice/isbn-verifier/.meta/example.el new file mode 100644 index 00000000..c0adb88d --- /dev/null +++ b/exercises/practice/isbn-verifier/.meta/example.el @@ -0,0 +1,23 @@ +;;; isbn-verifier.el --- ISBN Verifier (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun digit-value (c) + (if (= ?X c) 10 (- c ?0))) + +(defun validp (isbn) + (let ((total 0) + (weight 10) + (characters (remq ?- (cl-coerce isbn 'list)))) + (cl-loop for c in characters + always (or (cl-digit-char-p c) (and (= ?X c) (= weight 1))) + do (setq total (+ total (* weight (digit-value c)))) + do (setq weight (- weight 1)) + finally return (and (= 0 weight) (= 0 (% total 11)))))) + +(provide 'isbn-verifier) +;;; isbn-verifier.el ends here diff --git a/exercises/practice/isbn-verifier/.meta/tests.toml b/exercises/practice/isbn-verifier/.meta/tests.toml new file mode 100644 index 00000000..6d5a8459 --- /dev/null +++ b/exercises/practice/isbn-verifier/.meta/tests.toml @@ -0,0 +1,67 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[0caa3eac-d2e3-4c29-8df8-b188bc8c9292] +description = "valid isbn" + +[19f76b53-7c24-45f8-87b8-4604d0ccd248] +description = "invalid isbn check digit" + +[4164bfee-fb0a-4a1c-9f70-64c6a1903dcd] +description = "valid isbn with a check digit of 10" + +[3ed50db1-8982-4423-a993-93174a20825c] +description = "check digit is a character other than X" + +[9416f4a5-fe01-4b61-a07b-eb75892ef562] +description = "invalid check digit in isbn is not treated as zero" + +[c19ba0c4-014f-4dc3-a63f-ff9aefc9b5ec] +description = "invalid character in isbn is not treated as zero" + +[28025280-2c39-4092-9719-f3234b89c627] +description = "X is only valid as a check digit" + +[f6294e61-7e79-46b3-977b-f48789a4945b] +description = "valid isbn without separating dashes" + +[185ab99b-3a1b-45f3-aeec-b80d80b07f0b] +description = "isbn without separating dashes and X as check digit" + +[7725a837-ec8e-4528-a92a-d981dd8cf3e2] +description = "isbn without check digit and dashes" + +[47e4dfba-9c20-46ed-9958-4d3190630bdf] +description = "too long isbn and no dashes" + +[737f4e91-cbba-4175-95bf-ae630b41fb60] +description = "too short isbn" + +[5458a128-a9b6-4ff8-8afb-674e74567cef] +description = "isbn without check digit" + +[70b6ad83-d0a2-4ca7-a4d5-a9ab731800f7] +description = "check digit of X should not be used for 0" + +[94610459-55ab-4c35-9b93-ff6ea1a8e562] +description = "empty isbn" + +[7bff28d4-d770-48cc-80d6-b20b3a0fb46c] +description = "input is 9 characters" + +[ed6e8d1b-382c-4081-8326-8b772c581fec] +description = "invalid characters are not ignored after checking length" + +[daad3e58-ce00-4395-8a8e-e3eded1cdc86] +description = "invalid characters are not ignored before checking length" + +[fb5e48d8-7c03-4bfb-a088-b101df16fdc3] +description = "input is too long but contains a valid isbn" diff --git a/exercises/practice/isbn-verifier/isbn-verifier-test.el b/exercises/practice/isbn-verifier/isbn-verifier-test.el new file mode 100644 index 00000000..c11efa47 --- /dev/null +++ b/exercises/practice/isbn-verifier/isbn-verifier-test.el @@ -0,0 +1,88 @@ +;;; isbn-verifier-test.el --- Tests for Isbn Verifier (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(load-file "isbn-verifier.el") +(declare-function validp "isbn-verifier.el" (isbn)) + + +(ert-deftest valid-isbn () + (should (validp "3-598-21508-8"))) + + +(ert-deftest invalid-isbn-check-digit () + (should-not (validp "3-598-21508-9"))) + + +(ert-deftest valid-isbn-with-a-check-digit-of-10 () + (should (validp "3-598-21507-X"))) + + +(ert-deftest check-digit-is-a-character-other-than-x () + (should-not (validp "3-598-21507-A"))) + + +(ert-deftest invalid-check-digit-in-isbn-is-not-treated-as-zero () + (should-not (validp "4-598-21507-B"))) + + +(ert-deftest invalid-character-in-isbn-is-not-treated-as-zero () + (should-not (validp "3-598-P1581-X"))) + + +(ert-deftest x-is-only-valid-as-a-check-digit () + (should-not (validp "3-598-2X507-9"))) + + +(ert-deftest valid-isbn-without-separating-dashes () + (should (validp "3598215088"))) + + +(ert-deftest isbn-without-separating-dashes-and-x-as-check-digit () + (should (validp "359821507X"))) + + +(ert-deftest isbn-without-check-digit-and-dashes () + (should-not (validp "359821507"))) + + +(ert-deftest too-long-isbn-and-no-dashes () + (should-not (validp "3598215078X"))) + + +(ert-deftest too-short-isbn () + (should-not (validp "00"))) + + +(ert-deftest isbn-without-check-digit () + (should-not (validp "3-598-21507"))) + + +(ert-deftest check-digit-of-x-should-not-be-used-for-0 () + (should-not (validp "3-598-21515-X"))) + + +(ert-deftest empty-isbn () + (should-not (validp ""))) + + +(ert-deftest input-is-9-characters () + (should-not (validp "134456729"))) + + +(ert-deftest invalid-characters-are-not-ignored-after-checking-length () + (should-not (validp "3132P34035"))) + + +(ert-deftest invalid-characters-are-not-ignored-before-checking-length () + (should-not (validp "3598P215088"))) + + +(ert-deftest input-is-too-long-but-contains-a-valid-isbn () + (should-not (validp "98245726788"))) + + +(provide 'isbn-verifier-test) +;;; isbn-verifier-test.el ends here diff --git a/exercises/practice/isbn-verifier/isbn-verifier.el b/exercises/practice/isbn-verifier/isbn-verifier.el new file mode 100644 index 00000000..18e0f85a --- /dev/null +++ b/exercises/practice/isbn-verifier/isbn-verifier.el @@ -0,0 +1,13 @@ +;;; isbn-verifier.el --- ISBN Verifier (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun validp (isbn) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'isbn-verifier) +;;; isbn-verifier.el ends here From 4e3c4a5df1170b3b01acccf95625a0bdccc8a22f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 17:49:44 -0700 Subject: [PATCH 072/162] Bump actions/checkout from 4.1.4 to 4.1.5 (#371) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.4 to 4.1.5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/0ad4b8fadaa221de15dcec353f45205ec38ea70b...44c2b7a8a4ea60a981eaca3cf939b5f4305c123b) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/configlet-sync.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a855db46..8ab34cc2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: with: version: 28.2 - - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.0.0 + - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.0.0 - name: Run exercism/emacs-lisp ci (runs tests) for all exercises run: | diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index 807d079e..19301c78 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.0.0 + - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.0.0 - name: Fetch configlet uses: exercism/github-actions/configlet-ci@main From d4032e1af6b775beb14d9b5fa01c68c739e942b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Mon, 6 May 2024 23:20:34 -0700 Subject: [PATCH 073/162] Sync gigasecond tests and stub (#367) --- .../practice/gigasecond/.meta/example.el | 7 +-- .../practice/gigasecond/gigasecond-test.el | 47 +++++++------------ exercises/practice/gigasecond/gigasecond.el | 15 +++--- 3 files changed, 26 insertions(+), 43 deletions(-) diff --git a/exercises/practice/gigasecond/.meta/example.el b/exercises/practice/gigasecond/.meta/example.el index 57072a5c..7e905732 100644 --- a/exercises/practice/gigasecond/.meta/example.el +++ b/exercises/practice/gigasecond/.meta/example.el @@ -1,4 +1,4 @@ -;;; gigasecond.el --- Gigasecond exercise (exercism) -*- lexical-binding: t; -*- +;;; gigasecond.el --- Gigasecond (exercism) -*- lexical-binding: t; -*- ;;; Commentary: ;; Calculate the date one gigasecond (10^9 seconds) from the @@ -9,7 +9,7 @@ ;;; Code: -(defun from (second minute hour day month year) +(defun add (second minute hour day month year) "Calculate gigasecond from date given. Params are SECOND, MINUTE, HOUR, DAY, MONTH, and YEAR." (let ((gigasecond (seconds-to-time (expt 10 9))) @@ -19,8 +19,5 @@ Params are SECOND, MINUTE, HOUR, DAY, MONTH, and YEAR." (butlast end-date (- (length end-date) 6))))) - - - (provide 'gigasecond) ;;; gigasecond.el ends here diff --git a/exercises/practice/gigasecond/gigasecond-test.el b/exercises/practice/gigasecond/gigasecond-test.el index 6ca401a5..5d8e398b 100644 --- a/exercises/practice/gigasecond/gigasecond-test.el +++ b/exercises/practice/gigasecond/gigasecond-test.el @@ -1,47 +1,34 @@ -;;; gigasecond-test.el --- ERT tests for gigasecond (exercism) -*- lexical-binding: t; -*- +;;; gigasecond-test.el --- Gigasecond (exercism) -*- lexical-binding: t; -*- ;;; Commentary: -;; -;; Tests ported from Common Lisp gigasecond: -;; https://github.com/exercism/xlisp/blob/master/gigasecond/gigasecond-test.lisp -;; -;; To run tests individually: M-x eval-buffer RET, M-x ert RET test-name. -;; If you're using helm or something similar, you should get a menu of test names. -;; -;; To run tests in batch mode, from the command line run: -;; emacs -batch -l ert -l gigasecond-test.el -f ert-run-tests-batch-and-exit ;;; Code: + (load-file "gigasecond.el") -(declare-function from "gigasecond.el" (second minute hour day month year)) +(declare-function add "gigasecond.el" (moment)) + + +(ert-deftest date-only-specification-of-time () + (should (equal '(40 46 1 1 1 2043) (add 0 0 0 25 4 2011)))) -(ert-deftest from-lisp-epoch () - (should - (equal '(40 46 1 10 9 1931) (from 0 0 0 1 1 1900)))) -(ert-deftest from-unix-epoch () - (should - (equal '(40 46 1 9 9 2001) (from 0 0 0 1 1 1970)))) +(ert-deftest second-test-for-date-only-specification-of-time () + (should (equal '(40 46 1 19 2 2009) (add 0 0 0 13 6 1977)))) -(ert-deftest from-20110425T120000Z () - (should - (equal '(40 46 13 1 1 2043) (from 0 0 12 25 4 2011)))) -(ert-deftest from-19770613T235959Z () - (should - (equal '(39 46 1 20 2 2009) (from 59 59 23 13 6 1977)))) +(ert-deftest third-test-for-date-only-specification-of-time () + (should (equal '(40 46 1 27 3 1991) (add 0 0 0 19 7 1959)))) -(ert-deftest from-19590719T123030Z () - (should - (equal '(10 17 14 27 3 1991) (from 30 30 12 19 7 1959)))) -; customize this test to test your birthday and find your gigasecond date: -; (ert-deftest your-birthday () -; (should -; (equal '(0 0 0 day2 month2 year2) (from 0 0 0 day1 month1 year1)))) +(ert-deftest full-time-specified () + (should (equal '(40 46 23 2 10 2046) (add 0 0 22 24 1 2015)))) +(ert-deftest full-time-with-day-roll-over () + (should (equal '(39 46 1 3 10 2046) (add 59 59 23 24 1 2015)))) + (provide 'gigasecond-test) ;;; gigasecond-test.el ends here + diff --git a/exercises/practice/gigasecond/gigasecond.el b/exercises/practice/gigasecond/gigasecond.el index ba92a10f..62978cdc 100644 --- a/exercises/practice/gigasecond/gigasecond.el +++ b/exercises/practice/gigasecond/gigasecond.el @@ -1,15 +1,14 @@ -;;; gigasecond.el --- Gigasecond exercise (exercism) -*- lexical-binding: t; -*- +;;; gigasecond.el --- Gigasecond (exercism) -*- lexical-binding: t; -*- ;;; Commentary: -;; Calculate the date one gigasecond (10^9 seconds) from the -;; given date. -;; -;; NB: Pay attention to Emacs' handling of time zones and dst -;; in the encode-time and decode-time functions. -(defun from (second minute hour day month year) ;;; Code: -) + + +(defun add (second minute hour day month year) + (error "Delete this S-Expression and write your own implementation")) + (provide 'gigasecond) ;;; gigasecond.el ends here + From d650c6d7558154d7f6f24740eeb8a5257749c229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Mon, 6 May 2024 23:20:50 -0700 Subject: [PATCH 074/162] Sync hamming tests and update stub (#368) --- exercises/practice/hamming/hamming-test.el | 48 ++++++++++------------ exercises/practice/hamming/hamming.el | 7 +++- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/exercises/practice/hamming/hamming-test.el b/exercises/practice/hamming/hamming-test.el index 0cac98e6..9fb22e67 100644 --- a/exercises/practice/hamming/hamming-test.el +++ b/exercises/practice/hamming/hamming-test.el @@ -1,54 +1,50 @@ -;;; hamming-test.el --- Tests for hamming (exercism) -*- lexical-binding: t; -*- +;;; hamming-test.el --- Hamming (exercism) -*- lexical-binding: t; -*- ;;; Commentary: -;; Common test data version: 2.0.1 f79dfd7 ;;; Code: + (load-file "hamming.el") (declare-function hamming-distance "hamming.el" (dna1 dna2)) + (ert-deftest empty-strands () (should (= 0 (hamming-distance "" "")))) -(ert-deftest identical-strands () + +(ert-deftest single-letter-identical-strands () (should (= 0 (hamming-distance "A" "A")))) + +(ert-deftest single-letter-different-strands () + (should (= 1 (hamming-distance "G" "T")))) + + (ert-deftest long-identical-strands () - (should (= 0 (hamming-distance "GGACTGA" "GGACTGA")))) + (should (= 0 (hamming-distance "GGACTGAAATCTG" "GGACTGAAATCTG")))) -(ert-deftest complete-distance-in-single-nucleotide-strands () - (should (= 1 (hamming-distance "A" "G")))) +(ert-deftest long-different-strands () + (should (= 9 (hamming-distance "GGACGGATTCTG" "AGGACGGATTCT")))) -(ert-deftest complete-distance-in-small-strands () - (should (= 2 (hamming-distance "AG" "CT")))) -(ert-deftest small-distance-in-small-strands () - (should (= 1 (hamming-distance "AT" "CT")))) +(ert-deftest disallow-first-strand-longer () + (should-error (hamming-distance "AATG" "AAA"))) -(ert-deftest small-distance () - (should (= 1 (hamming-distance "GGACG" "GGTCG")))) -(ert-deftest small-distance-in-long-strands () - (should (= 2 (hamming-distance "ACCAGGG" "ACTATGG")))) +(ert-deftest disallow-second-strand-longer () + (should-error (hamming-distance "ATA" "AGTG"))) -(ert-deftest non-unique-character-in-first-strand () - (should (= 1 (hamming-distance "AAA" "AAG")))) -(ert-deftest same-nucleotides-in-different-positions () - (should (= 2 (hamming-distance "TAG" "GAT")))) +(ert-deftest disallow-empty-first-strand () + (should-error (hamming-distance "" "G"))) -(ert-deftest large-distance () - (should (= 4 (hamming-distance "GATACA" "GCATAA")))) -(ert-deftest large-distance-in-off-by-one-strand () - (should (= 9 (hamming-distance "GGACGGATTCTG" "AGGACGGATTCT")))) -(ert-deftest disallow-first-strand-longer () - (should-error (hamming-distance "AATG" "AAA"))) +(ert-deftest disallow-empty-second-strand () + (should-error (hamming-distance "G" ""))) -(ert-deftest disallow-second-strand-longer () - (should-error (hamming-distance "ATA" "AGTG"))) (provide 'hamming-test) ;;; hamming-test.el ends here + diff --git a/exercises/practice/hamming/hamming.el b/exercises/practice/hamming/hamming.el index 6a0bc5d1..c14a52fe 100644 --- a/exercises/practice/hamming/hamming.el +++ b/exercises/practice/hamming/hamming.el @@ -2,9 +2,12 @@ ;;; Commentary: +;;; Code: + + (defun hamming-distance (dna1 dna2) -;;; Code: -) + (error "Delete this S-Expression and write your own implementation")) + (provide 'hamming) ;;; hamming.el ends here From 379da66cb9e1fb9a0b684b3dd64bc7e10b403282 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Wed, 8 May 2024 11:18:05 +1000 Subject: [PATCH 075/162] Add square-root exercise (#374) * Add square-root exercise * Compare numbers using = --- config.json | 11 ++++++ .../square-root/.docs/instructions.md | 13 +++++++ .../practice/square-root/.meta/config.json | 19 ++++++++++ .../practice/square-root/.meta/example.el | 15 ++++++++ .../practice/square-root/.meta/tests.toml | 28 +++++++++++++++ .../practice/square-root/square-root-test.el | 36 +++++++++++++++++++ exercises/practice/square-root/square-root.el | 13 +++++++ 7 files changed, 135 insertions(+) create mode 100644 exercises/practice/square-root/.docs/instructions.md create mode 100644 exercises/practice/square-root/.meta/config.json create mode 100644 exercises/practice/square-root/.meta/example.el create mode 100644 exercises/practice/square-root/.meta/tests.toml create mode 100644 exercises/practice/square-root/square-root-test.el create mode 100644 exercises/practice/square-root/square-root.el diff --git a/config.json b/config.json index d46f9db4..019ea7ac 100644 --- a/config.json +++ b/config.json @@ -393,6 +393,17 @@ "prerequisites": [], "difficulty": 2 }, + { + "slug": "square-root", + "name": "Square Root", + "uuid": "d74d3b6d-43db-4f46-a25d-b1a86df3fb47", + "practices": [], + "prerequisites": [], + "difficulty": 2, + "topics": [ + "math" + ] + }, { "slug": "sublist", "name": "Sublist", diff --git a/exercises/practice/square-root/.docs/instructions.md b/exercises/practice/square-root/.docs/instructions.md new file mode 100644 index 00000000..e9905e9d --- /dev/null +++ b/exercises/practice/square-root/.docs/instructions.md @@ -0,0 +1,13 @@ +# Instructions + +Given a natural radicand, return its square root. + +Note that the term "radicand" refers to the number for which the root is to be determined. +That is, it is the number under the root symbol. + +Check out the Wikipedia pages on [square root][square-root] and [methods of computing square roots][computing-square-roots]. + +Recall also that natural numbers are positive real whole numbers (i.e. 1, 2, 3 and up). + +[square-root]: https://en.wikipedia.org/wiki/Square_root +[computing-square-roots]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots diff --git a/exercises/practice/square-root/.meta/config.json b/exercises/practice/square-root/.meta/config.json new file mode 100644 index 00000000..e93a880b --- /dev/null +++ b/exercises/practice/square-root/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "square-root.el" + ], + "test": [ + "square-root-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given a natural radicand, return its square root.", + "source": "wolf99", + "source_url": "https://github.com/exercism/problem-specifications/pull/1582" +} diff --git a/exercises/practice/square-root/.meta/example.el b/exercises/practice/square-root/.meta/example.el new file mode 100644 index 00000000..9cfdd7b7 --- /dev/null +++ b/exercises/practice/square-root/.meta/example.el @@ -0,0 +1,15 @@ +;;; square-root.el --- Square Root (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun square-root (radicand) + (cl-loop for num from 0 + until (<= radicand (* num num)) + finally return num)) + +(provide 'square-root) +;;; square-root.el ends here diff --git a/exercises/practice/square-root/.meta/tests.toml b/exercises/practice/square-root/.meta/tests.toml new file mode 100644 index 00000000..ead7882f --- /dev/null +++ b/exercises/practice/square-root/.meta/tests.toml @@ -0,0 +1,28 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[9b748478-7b0a-490c-b87a-609dacf631fd] +description = "root of 1" + +[7d3aa9ba-9ac6-4e93-a18b-2e8b477139bb] +description = "root of 4" + +[6624aabf-3659-4ae0-a1c8-25ae7f33c6ef] +description = "root of 25" + +[93beac69-265e-4429-abb1-94506b431f81] +description = "root of 81" + +[fbddfeda-8c4f-4bc4-87ca-6991af35360e] +description = "root of 196" + +[c03d0532-8368-4734-a8e0-f96a9eb7fc1d] +description = "root of 65025" diff --git a/exercises/practice/square-root/square-root-test.el b/exercises/practice/square-root/square-root-test.el new file mode 100644 index 00000000..681b9592 --- /dev/null +++ b/exercises/practice/square-root/square-root-test.el @@ -0,0 +1,36 @@ +;;; square-root-test.el --- Tests for Square Root (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(load-file "square-root.el") +(declare-function square-root "square-root.el" (radicand)) + + +(ert-deftest root-of-1 () + (should (= 1 (square-root 1)))) + + +(ert-deftest root-of-4 () + (should (= 2 (square-root 4)))) + + +(ert-deftest root-of-25 () + (should (= 5 (square-root 25)))) + + +(ert-deftest root-of-81 () + (should (= 9 (square-root 81)))) + + +(ert-deftest root-of-196 () + (should (= 14 (square-root 196)))) + + +(ert-deftest root-of-65025 () + (should (= 255 (square-root 65025)))) + + +(provide 'square-root-test) +;;; square-root-test.el ends here diff --git a/exercises/practice/square-root/square-root.el b/exercises/practice/square-root/square-root.el new file mode 100644 index 00000000..43f56534 --- /dev/null +++ b/exercises/practice/square-root/square-root.el @@ -0,0 +1,13 @@ +;;; square-root.el --- Square Root (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun square-root (radicand) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'square-root) +;;; square-root.el ends here From 38895a462ec00c6de4184ba8ace747b249b397b2 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Wed, 8 May 2024 14:44:34 +1000 Subject: [PATCH 076/162] Add prime-factors exercise (#372) --- config.json | 11 ++++ .../prime-factors/.docs/instructions.md | 36 +++++++++++ .../practice/prime-factors/.meta/config.json | 19 ++++++ .../practice/prime-factors/.meta/example.el | 19 ++++++ .../practice/prime-factors/.meta/tests.toml | 46 ++++++++++++++ .../prime-factors/prime-factors-test.el | 60 +++++++++++++++++++ .../practice/prime-factors/prime-factors.el | 13 ++++ 7 files changed, 204 insertions(+) create mode 100644 exercises/practice/prime-factors/.docs/instructions.md create mode 100644 exercises/practice/prime-factors/.meta/config.json create mode 100644 exercises/practice/prime-factors/.meta/example.el create mode 100644 exercises/practice/prime-factors/.meta/tests.toml create mode 100644 exercises/practice/prime-factors/prime-factors-test.el create mode 100644 exercises/practice/prime-factors/prime-factors.el diff --git a/config.json b/config.json index 019ea7ac..23096a78 100644 --- a/config.json +++ b/config.json @@ -454,6 +454,17 @@ "strings" ] }, + { + "slug": "prime-factors", + "name": "Prime Factors", + "uuid": "cb79cb42-7efe-49fe-98c4-68dbdc32f2a3", + "practices": [], + "prerequisites": [], + "difficulty": 3, + "topics": [ + "math" + ] + }, { "slug": "largest-series-product", "name": "Largest Series Product", diff --git a/exercises/practice/prime-factors/.docs/instructions.md b/exercises/practice/prime-factors/.docs/instructions.md new file mode 100644 index 00000000..252cc8ee --- /dev/null +++ b/exercises/practice/prime-factors/.docs/instructions.md @@ -0,0 +1,36 @@ +# Instructions + +Compute the prime factors of a given natural number. + +A prime number is only evenly divisible by itself and 1. + +Note that 1 is not a prime number. + +## Example + +What are the prime factors of 60? + +- Our first divisor is 2. + 2 goes into 60, leaving 30. +- 2 goes into 30, leaving 15. + - 2 doesn't go cleanly into 15. + So let's move on to our next divisor, 3. +- 3 goes cleanly into 15, leaving 5. + - 3 does not go cleanly into 5. + The next possible factor is 4. + - 4 does not go cleanly into 5. + The next possible factor is 5. +- 5 does go cleanly into 5. +- We're left only with 1, so now, we're done. + +Our successful divisors in that computation represent the list of prime factors of 60: 2, 2, 3, and 5. + +You can check this yourself: + +```text +2 * 2 * 3 * 5 += 4 * 15 += 60 +``` + +Success! diff --git a/exercises/practice/prime-factors/.meta/config.json b/exercises/practice/prime-factors/.meta/config.json new file mode 100644 index 00000000..2758856f --- /dev/null +++ b/exercises/practice/prime-factors/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "prime-factors.el" + ], + "test": [ + "prime-factors-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Compute the prime factors of a given natural number.", + "source": "The Prime Factors Kata by Uncle Bob", + "source_url": "https://web.archive.org/web/20221026171801/http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata" +} diff --git a/exercises/practice/prime-factors/.meta/example.el b/exercises/practice/prime-factors/.meta/example.el new file mode 100644 index 00000000..146f34a2 --- /dev/null +++ b/exercises/practice/prime-factors/.meta/example.el @@ -0,0 +1,19 @@ +;;; prime-factors.el --- Prime Factors (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun factors-from (start value) + (unless (= value 1) + (cl-loop for p from start + until (= 0 (% value p)) + finally return (cons p (factors-from p (/ value p)))))) + +(defun factors (value) + (factors-from 2 value)) + +(provide 'prime-factors) +;;; prime-factors.el ends here diff --git a/exercises/practice/prime-factors/.meta/tests.toml b/exercises/practice/prime-factors/.meta/tests.toml new file mode 100644 index 00000000..6f9cc8ce --- /dev/null +++ b/exercises/practice/prime-factors/.meta/tests.toml @@ -0,0 +1,46 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[924fc966-a8f5-4288-82f2-6b9224819ccd] +description = "no factors" + +[17e30670-b105-4305-af53-ddde182cb6ad] +description = "prime number" + +[238d57c8-4c12-42ef-af34-ae4929f94789] +description = "another prime number" + +[f59b8350-a180-495a-8fb1-1712fbee1158] +description = "square of a prime" + +[756949d3-3158-4e3d-91f2-c4f9f043ee70] +description = "product of first prime" + +[bc8c113f-9580-4516-8669-c5fc29512ceb] +description = "cube of a prime" + +[7d6a3300-a4cb-4065-bd33-0ced1de6cb44] +description = "product of second prime" + +[073ac0b2-c915-4362-929d-fc45f7b9a9e4] +description = "product of third prime" + +[6e0e4912-7fb6-47f3-a9ad-dbcd79340c75] +description = "product of first and second prime" + +[00485cd3-a3fe-4fbe-a64a-a4308fc1f870] +description = "product of primes and non-primes" + +[02251d54-3ca1-4a9b-85e1-b38f4b0ccb91] +description = "product of primes" + +[070cf8dc-e202-4285-aa37-8d775c9cd473] +description = "factors include a large prime" diff --git a/exercises/practice/prime-factors/prime-factors-test.el b/exercises/practice/prime-factors/prime-factors-test.el new file mode 100644 index 00000000..c361ef78 --- /dev/null +++ b/exercises/practice/prime-factors/prime-factors-test.el @@ -0,0 +1,60 @@ +;;; prime-factors-test.el --- Tests for Prime Factors (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(load-file "prime-factors.el") +(declare-function factors "prime-factors.el" (value)) + + +(ert-deftest no-factors () + (should (equal '() (factors 1)))) + + +(ert-deftest prime-number () + (should (equal '(2) (factors 2)))) + + +(ert-deftest another-prime-number () + (should (equal '(3) (factors 3)))) + + +(ert-deftest square-of-a-prime () + (should (equal '(3 3) (factors 9)))) + + +(ert-deftest product-of-first-prime () + (should (equal '(2 2) (factors 4)))) + + +(ert-deftest cube-of-a-prime () + (should (equal '(2 2 2) (factors 8)))) + + +(ert-deftest product-of-second-prime () + (should (equal '(3 3 3) (factors 27)))) + + +(ert-deftest product-of-third-prime () + (should (equal '(5 5 5 5) (factors 625)))) + + +(ert-deftest product-of-first-and-second-prime () + (should (equal '(2 3) (factors 6)))) + + +(ert-deftest product-of-primes-and-non-primes () + (should (equal '(2 2 3) (factors 12)))) + + +(ert-deftest product-of-primes () + (should (equal '(5 17 23 461) (factors 901255)))) + + +(ert-deftest factors-include-a-large-prime () + (should (equal '(11 9539 894119) (factors 93819012551)))) + + +(provide 'prime-factors-test) +;;; prime-factors-test.el ends here diff --git a/exercises/practice/prime-factors/prime-factors.el b/exercises/practice/prime-factors/prime-factors.el new file mode 100644 index 00000000..076c9578 --- /dev/null +++ b/exercises/practice/prime-factors/prime-factors.el @@ -0,0 +1,13 @@ +;;; prime-factors.el --- Prime Factors (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun factors (value) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'prime-factors) +;;; prime-factors.el ends here From 69e181235ae3938f37e29ef0ade7a6b12f6274ae Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Wed, 8 May 2024 23:37:02 +1000 Subject: [PATCH 077/162] Add pythagorean-triplet exercise (#373) * Add pythagorean-triplet exercise * Reformat test cases --- config.json | 11 ++++ .../pythagorean-triplet/.docs/instructions.md | 23 ++++++++ .../pythagorean-triplet/.meta/config.json | 19 +++++++ .../pythagorean-triplet/.meta/example.el | 30 +++++++++++ .../pythagorean-triplet/.meta/tests.toml | 31 +++++++++++ .../pythagorean-triplet-test.el | 53 +++++++++++++++++++ .../pythagorean-triplet.el | 13 +++++ 7 files changed, 180 insertions(+) create mode 100644 exercises/practice/pythagorean-triplet/.docs/instructions.md create mode 100644 exercises/practice/pythagorean-triplet/.meta/config.json create mode 100644 exercises/practice/pythagorean-triplet/.meta/example.el create mode 100644 exercises/practice/pythagorean-triplet/.meta/tests.toml create mode 100644 exercises/practice/pythagorean-triplet/pythagorean-triplet-test.el create mode 100644 exercises/practice/pythagorean-triplet/pythagorean-triplet.el diff --git a/config.json b/config.json index 23096a78..54f093d4 100644 --- a/config.json +++ b/config.json @@ -587,6 +587,17 @@ "strings" ] }, + { + "slug": "pythagorean-triplet", + "name": "Pythagorean Triplet", + "uuid": "f33d976d-5189-4fcb-b0ac-42879a1067bf", + "practices": [], + "prerequisites": [], + "difficulty": 5, + "topics": [ + "math" + ] + }, { "slug": "rail-fence-cipher", "name": "Rail Fence Cipher", diff --git a/exercises/practice/pythagorean-triplet/.docs/instructions.md b/exercises/practice/pythagorean-triplet/.docs/instructions.md new file mode 100644 index 00000000..1c1a8aea --- /dev/null +++ b/exercises/practice/pythagorean-triplet/.docs/instructions.md @@ -0,0 +1,23 @@ +# Instructions + +A Pythagorean triplet is a set of three natural numbers, {a, b, c}, for which, + +```text +a² + b² = c² +``` + +and such that, + +```text +a < b < c +``` + +For example, + +```text +3² + 4² = 5². +``` + +Given an input integer N, find all Pythagorean triplets for which `a + b + c = N`. + +For example, with N = 1000, there is exactly one Pythagorean triplet for which `a + b + c = 1000`: `{200, 375, 425}`. diff --git a/exercises/practice/pythagorean-triplet/.meta/config.json b/exercises/practice/pythagorean-triplet/.meta/config.json new file mode 100644 index 00000000..ce368d16 --- /dev/null +++ b/exercises/practice/pythagorean-triplet/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "pythagorean-triplet.el" + ], + "test": [ + "pythagorean-triplet-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "There exists exactly one Pythagorean triplet for which a + b + c = 1000. Find the triplet.", + "source": "Problem 9 at Project Euler", + "source_url": "https://projecteuler.net/problem=9" +} diff --git a/exercises/practice/pythagorean-triplet/.meta/example.el b/exercises/practice/pythagorean-triplet/.meta/example.el new file mode 100644 index 00000000..51f1ecb8 --- /dev/null +++ b/exercises/practice/pythagorean-triplet/.meta/example.el @@ -0,0 +1,30 @@ +;;; pythagorean-triplet.el --- Pythagorean Triplet (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +; For every Pythagorean triplet with total a + b + c = n, +; a² + b² = c² +; <=> a² + b² = (n - a - b)², substituting c +; <=> 0 = n² - 2*n*a - 2*n*b + 2*a*b +; <=> (2*n - 2*a) b = (n² - 2*n*a) +; <=> b = (n² - 2*n*a) / (2*n - 2*a) + +;;; Code: + +(require 'cl-lib) + +(defun triplets-with-sum (n) + (cl-labels + ((recur (start) + (cl-loop for a from start + for numerator = (* n (- n a a)) + for denominator = (* 2 (- n a)) + for b = (/ numerator denominator) + always (< a b) + until (= 0 (% numerator denominator)) + finally return (cons (list a b (- n a b)) (recur (1+ a)))))) + (unless (< n 2) + (recur 1)))) + +(provide 'pythagorean-triplet) +;;; pythagorean-triplet.el ends here diff --git a/exercises/practice/pythagorean-triplet/.meta/tests.toml b/exercises/practice/pythagorean-triplet/.meta/tests.toml new file mode 100644 index 00000000..719620a9 --- /dev/null +++ b/exercises/practice/pythagorean-triplet/.meta/tests.toml @@ -0,0 +1,31 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[a19de65d-35b8-4480-b1af-371d9541e706] +description = "triplets whose sum is 12" + +[48b21332-0a3d-43b2-9a52-90b2a6e5c9f5] +description = "triplets whose sum is 108" + +[dffc1266-418e-4daa-81af-54c3e95c3bb5] +description = "triplets whose sum is 1000" + +[5f86a2d4-6383-4cce-93a5-e4489e79b186] +description = "no matching triplets for 1001" + +[bf17ba80-1596-409a-bb13-343bdb3b2904] +description = "returns all matching triplets" + +[9d8fb5d5-6c6f-42df-9f95-d3165963ac57] +description = "several matching triplets" + +[f5be5734-8aa0-4bd1-99a2-02adcc4402b4] +description = "triplets for large number" diff --git a/exercises/practice/pythagorean-triplet/pythagorean-triplet-test.el b/exercises/practice/pythagorean-triplet/pythagorean-triplet-test.el new file mode 100644 index 00000000..81dbebf8 --- /dev/null +++ b/exercises/practice/pythagorean-triplet/pythagorean-triplet-test.el @@ -0,0 +1,53 @@ +;;; pythagorean-triplet-test.el --- Tests for Pythagorean Triplet (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(load-file "pythagorean-triplet.el") +(declare-function triplets-with-sum "pythagorean-triplet.el" (n)) + + +(ert-deftest triplets-whose-sum-is-12 () + (should (equal '((3 4 5)) (triplets-with-sum 12)))) + + +(ert-deftest triplets-whose-sum-is-108 () + (should (equal '((27 36 45)) (triplets-with-sum 108)))) + + +(ert-deftest triplets-whose-sum-is-1000 () + (should (equal '((200 375 425)) (triplets-with-sum 1000)))) + + +(ert-deftest no-matching-triplets-for-1001 () + (should (equal '() (triplets-with-sum 1001)))) + + +(ert-deftest returns-all-matching-triplets () + (should (equal '((9 40 41) (15 36 39)) (triplets-with-sum 90)))) + + +(ert-deftest several-matching-triplets () + (should (equal '((40 399 401) + (56 390 394) + (105 360 375) + (120 350 370) + (140 336 364) + (168 315 357) + (210 280 350) + (240 252 348)) + (triplets-with-sum 840)))) + + +(ert-deftest triplets-for-large-number () + (should (equal '((1200 14375 14425) + (1875 14000 14125) + (5000 12000 13000) + (6000 11250 12750) + (7500 10000 12500)) + (triplets-with-sum 30000)))) + + +(provide 'pythagorean-triplet-test) +;;; pythagorean-triplet-test.el ends here diff --git a/exercises/practice/pythagorean-triplet/pythagorean-triplet.el b/exercises/practice/pythagorean-triplet/pythagorean-triplet.el new file mode 100644 index 00000000..19ad38d9 --- /dev/null +++ b/exercises/practice/pythagorean-triplet/pythagorean-triplet.el @@ -0,0 +1,13 @@ +;;; pythagorean-triplet.el --- Pythagorean Triplet (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun triplets-with-sum (n) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'pythagorean-triplet) +;;; pythagorean-triplet.el ends here From e5ca36b9cd6396cdbe179126d0b67cbbfe2f8cde Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Thu, 9 May 2024 23:49:53 +1000 Subject: [PATCH 078/162] Add series exercise (#375) * Add series exercise * reformat --- config.json | 11 ++++ .../practice/series/.docs/instructions.md | 19 ++++++ exercises/practice/series/.meta/config.json | 19 ++++++ exercises/practice/series/.meta/example.el | 22 +++++++ exercises/practice/series/.meta/tests.toml | 43 +++++++++++++ exercises/practice/series/series-test.el | 64 +++++++++++++++++++ exercises/practice/series/series.el | 14 ++++ 7 files changed, 192 insertions(+) create mode 100644 exercises/practice/series/.docs/instructions.md create mode 100644 exercises/practice/series/.meta/config.json create mode 100644 exercises/practice/series/.meta/example.el create mode 100644 exercises/practice/series/.meta/tests.toml create mode 100644 exercises/practice/series/series-test.el create mode 100644 exercises/practice/series/series.el diff --git a/config.json b/config.json index 54f093d4..5a903088 100644 --- a/config.json +++ b/config.json @@ -465,6 +465,17 @@ "math" ] }, + { + "slug": "series", + "name": "Series", + "uuid": "2e10ca92-6232-418e-b9ea-506ac1eba195", + "practices": [], + "prerequisites": [], + "difficulty": 3, + "topics": [ + "strings" + ] + }, { "slug": "largest-series-product", "name": "Largest Series Product", diff --git a/exercises/practice/series/.docs/instructions.md b/exercises/practice/series/.docs/instructions.md new file mode 100644 index 00000000..fd97a670 --- /dev/null +++ b/exercises/practice/series/.docs/instructions.md @@ -0,0 +1,19 @@ +# Instructions + +Given a string of digits, output all the contiguous substrings of length `n` in that string in the order that they appear. + +For example, the string "49142" has the following 3-digit series: + +- "491" +- "914" +- "142" + +And the following 4-digit series: + +- "4914" +- "9142" + +And if you ask for a 6-digit series from a 5-digit string, you deserve whatever you get. + +Note that these series are only required to occupy _adjacent positions_ in the input; +the digits need not be _numerically consecutive_. diff --git a/exercises/practice/series/.meta/config.json b/exercises/practice/series/.meta/config.json new file mode 100644 index 00000000..d7b49651 --- /dev/null +++ b/exercises/practice/series/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "series.el" + ], + "test": [ + "series-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given a string of digits, output all the contiguous substrings of length `n` in that string.", + "source": "A subset of the Problem 8 at Project Euler", + "source_url": "https://projecteuler.net/problem=8" +} diff --git a/exercises/practice/series/.meta/example.el b/exercises/practice/series/.meta/example.el new file mode 100644 index 00000000..e6675e98 --- /dev/null +++ b/exercises/practice/series/.meta/example.el @@ -0,0 +1,22 @@ +;;; series.el --- Series (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + + +(defun slices (series slice-length) + (cond + ((equal "" series) (error "series cannot be empty")) + ((> slice-length (length series)) (error "slice length cannot be greater than series length")) + ((= slice-length 0) (error "slice length cannot be zero")) + ((< slice-length 0) (error "slice length cannot be negative")) + (t (mapcar (lambda (start) + (substring series start (+ start slice-length))) + (number-sequence 0 (- (length series) slice-length)))))) + + +(provide 'series) +;;; series.el ends here + diff --git a/exercises/practice/series/.meta/tests.toml b/exercises/practice/series/.meta/tests.toml new file mode 100644 index 00000000..9696f51f --- /dev/null +++ b/exercises/practice/series/.meta/tests.toml @@ -0,0 +1,43 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[7ae7a46a-d992-4c2a-9c15-a112d125ebad] +description = "slices of one from one" + +[3143b71d-f6a5-4221-aeae-619f906244d2] +description = "slices of one from two" + +[dbb68ff5-76c5-4ccd-895a-93dbec6d5805] +description = "slices of two" + +[19bbea47-c987-4e11-a7d1-e103442adf86] +description = "slices of two overlap" + +[8e17148d-ba0a-4007-a07f-d7f87015d84c] +description = "slices can include duplicates" + +[bd5b085e-f612-4f81-97a8-6314258278b0] +description = "slices of a long series" + +[6d235d85-46cf-4fae-9955-14b6efef27cd] +description = "slice length is too large" + +[d7957455-346d-4e47-8e4b-87ed1564c6d7] +description = "slice length is way too large" + +[d34004ad-8765-4c09-8ba1-ada8ce776806] +description = "slice length cannot be zero" + +[10ab822d-8410-470a-a85d-23fbeb549e54] +description = "slice length cannot be negative" + +[c7ed0812-0e4b-4bf3-99c4-28cbbfc246a2] +description = "empty series is invalid" diff --git a/exercises/practice/series/series-test.el b/exercises/practice/series/series-test.el new file mode 100644 index 00000000..615531e6 --- /dev/null +++ b/exercises/practice/series/series-test.el @@ -0,0 +1,64 @@ +;;; series-test.el --- Tests for Series (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(load-file "series.el") +(declare-function slices "series.el" (series slice-length)) + + +(ert-deftest slices-of-one-from-one () + (should (equal '("1") (slices "1" 1)))) + + +(ert-deftest slices-of-one-from-two () + (should (equal '("1" "2") (slices "12" 1)))) + + +(ert-deftest slices-of-two () + (should (equal '("35") (slices "35" 2)))) + + +(ert-deftest slices-of-two-overlap () + (should (equal '("91" "14" "42") (slices "9142" 2)))) + + +(ert-deftest slices-can-include-duplicates () + (should (equal '("777" "777" "777" "777") (slices "777777" 3)))) + + +(ert-deftest slices-of-a-long-series () + (should (equal '("91849" + "18493" + "84939" + "49390" + "93904" + "39042" + "90424" + "04243") + (slices "918493904243" 5)))) + + +(ert-deftest slice-length-is-too-large () + (should-error (slices "12345" 6))) + + +(ert-deftest slice-length-is-way-too-large () + (should-error (slices "12345" 42))) + + +(ert-deftest slice-length-cannot-be-zero () + (should-error (slices "12345" 0))) + + +(ert-deftest slice-length-cannot-be-negative () + (should-error (slices "123" -1))) + + +(ert-deftest empty-series-is-invalid () + (should-error (slices "" 1))) + + +(provide 'series-test) +;;; series-test.el ends here diff --git a/exercises/practice/series/series.el b/exercises/practice/series/series.el new file mode 100644 index 00000000..2b298f22 --- /dev/null +++ b/exercises/practice/series/series.el @@ -0,0 +1,14 @@ +;;; series.el --- Series (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun slices (series slice-length) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'series) +;;; series.el ends here + From e5131342a2fb695ae0c8e913dd92e6420f46729f Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Sat, 11 May 2024 05:00:35 +1000 Subject: [PATCH 079/162] Add sieve exercise (#376) * Add sieve exercise * reformat across multiple lines, set difficulty 3 --- config.json | 12 ++++++ .../practice/sieve/.docs/instructions.md | 42 ++++++++++++++++++ .../practice/sieve/.docs/introduction.md | 7 +++ exercises/practice/sieve/.meta/config.json | 19 ++++++++ exercises/practice/sieve/.meta/example.el | 25 +++++++++++ exercises/practice/sieve/.meta/tests.toml | 25 +++++++++++ exercises/practice/sieve/sieve-test.el | 43 +++++++++++++++++++ exercises/practice/sieve/sieve.el | 14 ++++++ 8 files changed, 187 insertions(+) create mode 100644 exercises/practice/sieve/.docs/instructions.md create mode 100644 exercises/practice/sieve/.docs/introduction.md create mode 100644 exercises/practice/sieve/.meta/config.json create mode 100644 exercises/practice/sieve/.meta/example.el create mode 100644 exercises/practice/sieve/.meta/tests.toml create mode 100644 exercises/practice/sieve/sieve-test.el create mode 100644 exercises/practice/sieve/sieve.el diff --git a/config.json b/config.json index 5a903088..6c3ca65a 100644 --- a/config.json +++ b/config.json @@ -476,6 +476,18 @@ "strings" ] }, + { + "slug": "sieve", + "name": "Sieve", + "uuid": "21172aa9-a155-493c-ad9f-ab4884596488", + "practices": [], + "prerequisites": [], + "difficulty": 3, + "topics": [ + "control_flow_loops", + "math" + ] + }, { "slug": "largest-series-product", "name": "Largest Series Product", diff --git a/exercises/practice/sieve/.docs/instructions.md b/exercises/practice/sieve/.docs/instructions.md new file mode 100644 index 00000000..085c0a57 --- /dev/null +++ b/exercises/practice/sieve/.docs/instructions.md @@ -0,0 +1,42 @@ +# Instructions + +Your task is to create a program that implements the Sieve of Eratosthenes algorithm to find all prime numbers less than or equal to a given number. + +A prime number is a number larger than 1 that is only divisible by 1 and itself. +For example, 2, 3, 5, 7, 11, and 13 are prime numbers. +By contrast, 6 is _not_ a prime number as it not only divisible by 1 and itself, but also by 2 and 3. + +To use the Sieve of Eratosthenes, you first create a list of all the numbers between 2 and your given number. +Then you repeat the following steps: + +1. Find the next unmarked number in your list (skipping over marked numbers). + This is a prime number. +2. Mark all the multiples of that prime number as **not** prime. + +You keep repeating these steps until you've gone through every number in your list. +At the end, all the unmarked numbers are prime. + +~~~~exercism/note +The tests don't check that you've implemented the algorithm, only that you've come up with the correct list of primes. +To check you are implementing the Sieve correctly, a good first test is to check that you do not use division or remainder operations. +~~~~ + +## Example + +Let's say you're finding the primes less than or equal to 10. + +- List out 2, 3, 4, 5, 6, 7, 8, 9, 10, leaving them all unmarked. +- 2 is unmarked and is therefore a prime. + Mark 4, 6, 8 and 10 as "not prime". +- 3 is unmarked and is therefore a prime. + Mark 6 and 9 as not prime _(marking 6 is optional - as it's already been marked)_. +- 4 is marked as "not prime", so we skip over it. +- 5 is unmarked and is therefore a prime. + Mark 10 as not prime _(optional - as it's already been marked)_. +- 6 is marked as "not prime", so we skip over it. +- 7 is unmarked and is therefore a prime. +- 8 is marked as "not prime", so we skip over it. +- 9 is marked as "not prime", so we skip over it. +- 10 is marked as "not prime", so we stop as there are no more numbers to check. + +You've examined all numbers and found 2, 3, 5, and 7 are still unmarked, which means they're the primes less than or equal to 10. diff --git a/exercises/practice/sieve/.docs/introduction.md b/exercises/practice/sieve/.docs/introduction.md new file mode 100644 index 00000000..f6c1cf79 --- /dev/null +++ b/exercises/practice/sieve/.docs/introduction.md @@ -0,0 +1,7 @@ +# Introduction + +You bought a big box of random computer parts at a garage sale. +You've started putting the parts together to build custom computers. + +You want to test the performance of different combinations of parts, and decide to create your own benchmarking program to see how your computers compare. +You choose the famous "Sieve of Eratosthenes" algorithm, an ancient algorithm, but one that should push your computers to the limits. diff --git a/exercises/practice/sieve/.meta/config.json b/exercises/practice/sieve/.meta/config.json new file mode 100644 index 00000000..c98915f1 --- /dev/null +++ b/exercises/practice/sieve/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "sieve.el" + ], + "test": [ + "sieve-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Use the Sieve of Eratosthenes to find all the primes from 2 up to a given number.", + "source": "Sieve of Eratosthenes at Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes" +} diff --git a/exercises/practice/sieve/.meta/example.el b/exercises/practice/sieve/.meta/example.el new file mode 100644 index 00000000..fdd454ed --- /dev/null +++ b/exercises/practice/sieve/.meta/example.el @@ -0,0 +1,25 @@ +;;; sieve.el --- Sieve (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun primes (limit) + (let ((table (make-bool-vector (1+ limit) t)) + (result nil)) + (cl-loop for p from 2 + for psq = (* p p) + until (< limit psq) + do (when (aref table p) + (cl-loop for m from psq to limit by p + do (aset table m nil)))) + (cl-loop for p from limit downto 2 + do (when (aref table p) + (setq result (cons p result)))) + result)) + +(provide 'sieve) +;;; sieve.el ends here + diff --git a/exercises/practice/sieve/.meta/tests.toml b/exercises/practice/sieve/.meta/tests.toml new file mode 100644 index 00000000..fec5e1a1 --- /dev/null +++ b/exercises/practice/sieve/.meta/tests.toml @@ -0,0 +1,25 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[88529125-c4ce-43cc-bb36-1eb4ddd7b44f] +description = "no primes under two" + +[4afe9474-c705-4477-9923-840e1024cc2b] +description = "find first prime" + +[974945d8-8cd9-4f00-9463-7d813c7f17b7] +description = "find primes up to 10" + +[2e2417b7-3f3a-452a-8594-b9af08af6d82] +description = "limit is prime" + +[92102a05-4c7c-47de-9ed0-b7d5fcd00f21] +description = "find primes up to 1000" diff --git a/exercises/practice/sieve/sieve-test.el b/exercises/practice/sieve/sieve-test.el new file mode 100644 index 00000000..eb96b595 --- /dev/null +++ b/exercises/practice/sieve/sieve-test.el @@ -0,0 +1,43 @@ +;;; sieve-test.el --- Tests for Sieve (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(load-file "sieve.el") +(declare-function primes "sieve.el" (limit)) + + +(ert-deftest no-primes-under-two () + (should (equal '() (primes 1)))) + + +(ert-deftest find-first-prime () + (should (equal '(2) (primes 2)))) + + +(ert-deftest find-primes-up-to-10 () + (should (equal '(2 3 5 7) (primes 10)))) + + +(ert-deftest limit-is-prime () + (should (equal '(2 3 5 7 11 13) (primes 13)))) + + +(ert-deftest find-primes-up-to-1000 () + (should (equal '(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 + 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 + 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 + 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 + 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 + 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 + 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 + 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 + 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 + 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 + 929 937 941 947 953 967 971 977 983 991 997) + (primes 1000)))) + + +(provide 'sieve-test) +;;; sieve-test.el ends here diff --git a/exercises/practice/sieve/sieve.el b/exercises/practice/sieve/sieve.el new file mode 100644 index 00000000..89858dda --- /dev/null +++ b/exercises/practice/sieve/sieve.el @@ -0,0 +1,14 @@ +;;; sieve.el --- Sieve (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun primes (limit) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'sieve) +;;; sieve.el ends here + From 7078902e9e26da3bd33a823b4adf5fd3b19ee373 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Sat, 11 May 2024 12:02:55 +1000 Subject: [PATCH 080/162] Add knapsack exercise (#377) * Add knapsack exercise * Use association lists to represet items. --- config.json | 11 +++ .../practice/knapsack/.docs/instructions.md | 35 +++++++++ exercises/practice/knapsack/.meta/config.json | 19 +++++ exercises/practice/knapsack/.meta/example.el | 22 ++++++ exercises/practice/knapsack/.meta/tests.toml | 36 +++++++++ exercises/practice/knapsack/knapsack-test.el | 73 +++++++++++++++++++ exercises/practice/knapsack/knapsack.el | 14 ++++ 7 files changed, 210 insertions(+) create mode 100644 exercises/practice/knapsack/.docs/instructions.md create mode 100644 exercises/practice/knapsack/.meta/config.json create mode 100644 exercises/practice/knapsack/.meta/example.el create mode 100644 exercises/practice/knapsack/.meta/tests.toml create mode 100644 exercises/practice/knapsack/knapsack-test.el create mode 100644 exercises/practice/knapsack/knapsack.el diff --git a/config.json b/config.json index 6c3ca65a..86913445 100644 --- a/config.json +++ b/config.json @@ -671,6 +671,17 @@ "practices": [], "prerequisites": [], "difficulty": 5 + }, + { + "slug": "knapsack", + "name": "Knapsack", + "uuid": "41029de7-58a6-431b-9f82-6d4603604fb3", + "practices": [], + "prerequisites": [], + "difficulty": 7, + "topics": [ + "control_flow_loops" + ] } ] }, diff --git a/exercises/practice/knapsack/.docs/instructions.md b/exercises/practice/knapsack/.docs/instructions.md new file mode 100644 index 00000000..fadcee1b --- /dev/null +++ b/exercises/practice/knapsack/.docs/instructions.md @@ -0,0 +1,35 @@ +# Instructions + +In this exercise, let's try to solve a classic problem. + +Bob is a thief. +After months of careful planning, he finally manages to crack the security systems of a high-class apartment. + +In front of him are many items, each with a value (v) and weight (w). +Bob, of course, wants to maximize the total value he can get; he would gladly take all of the items if he could. +However, to his horror, he realizes that the knapsack he carries with him can only hold so much weight (W). + +Given a knapsack with a specific carrying capacity (W), help Bob determine the maximum value he can get from the items in the house. +Note that Bob can take only one of each item. + +All values given will be strictly positive. +Items will be represented as a list of items. +Each item will have a weight and value. + +For example: + +```none +Items: [ + { "weight": 5, "value": 10 }, + { "weight": 4, "value": 40 }, + { "weight": 6, "value": 30 }, + { "weight": 4, "value": 50 } +] + +Knapsack Limit: 10 +``` + +For the above, the first item has weight 5 and value 10, the second item has weight 4 and value 40, and so on. + +In this example, Bob should take the second and fourth item to maximize his value, which, in this case, is 90. +He cannot get more than 90 as his knapsack has a weight limit of 10. diff --git a/exercises/practice/knapsack/.meta/config.json b/exercises/practice/knapsack/.meta/config.json new file mode 100644 index 00000000..edb6f556 --- /dev/null +++ b/exercises/practice/knapsack/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "knapsack.el" + ], + "test": [ + "knapsack-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given a knapsack that can only carry a certain weight, determine which items to put in the knapsack in order to maximize their combined value.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Knapsack_problem" +} diff --git a/exercises/practice/knapsack/.meta/example.el b/exercises/practice/knapsack/.meta/example.el new file mode 100644 index 00000000..ebb56bb3 --- /dev/null +++ b/exercises/practice/knapsack/.meta/example.el @@ -0,0 +1,22 @@ +;;; knapsack.el --- Knapsack (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun maximum-value (maximum-weight items) + (let ((table (make-vector (1+ maximum-weight) 0))) + (dolist (item items) + (let ((weight (alist-get :weight item)) + (value (alist-get :value item))) + (cl-loop for index from maximum-weight downto weight + for new-value = (+ value (aref table (- index weight))) + do (when (> new-value (aref table index)) + (aset table index new-value))))) + (aref table maximum-weight))) + +(provide 'knapsack) +;;; knapsack.el ends here + diff --git a/exercises/practice/knapsack/.meta/tests.toml b/exercises/practice/knapsack/.meta/tests.toml new file mode 100644 index 00000000..8e013ef1 --- /dev/null +++ b/exercises/practice/knapsack/.meta/tests.toml @@ -0,0 +1,36 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[a4d7d2f0-ad8a-460c-86f3-88ba709d41a7] +description = "no items" +include = false + +[3993a824-c20e-493d-b3c9-ee8a7753ee59] +description = "no items" +reimplements = "a4d7d2f0-ad8a-460c-86f3-88ba709d41a7" + +[1d39e98c-6249-4a8b-912f-87cb12e506b0] +description = "one item, too heavy" + +[833ea310-6323-44f2-9d27-a278740ffbd8] +description = "five items (cannot be greedy by weight)" + +[277cdc52-f835-4c7d-872b-bff17bab2456] +description = "five items (cannot be greedy by value)" + +[81d8e679-442b-4f7a-8a59-7278083916c9] +description = "example knapsack" + +[f23a2449-d67c-4c26-bf3e-cde020f27ecc] +description = "8 items" + +[7c682ae9-c385-4241-a197-d2fa02c81a11] +description = "15 items" diff --git a/exercises/practice/knapsack/knapsack-test.el b/exercises/practice/knapsack/knapsack-test.el new file mode 100644 index 00000000..4692bba0 --- /dev/null +++ b/exercises/practice/knapsack/knapsack-test.el @@ -0,0 +1,73 @@ +;;; knapsack-test.el --- Tests for Knapsack (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "knapsack.el") +(declare-function maximum-value "knapsack.el" (maximum-weight items)) + + +(ert-deftest no-items () + (should (= 0 (maximum-value 100 '())))) + + +(ert-deftest one-item-too-heavy () + (should (= 0 (maximum-value 10 '(((:weight . 100) (:value . 1))))))) + + +(ert-deftest five-items-cannot-be-greedy-by-weight () + (should (= 21 (maximum-value 10 '(((:weight . 2) (:value . 5)) + ((:weight . 2) (:value . 5)) + ((:weight . 2) (:value . 5)) + ((:weight . 2) (:value . 5)) + ((:weight . 10) (:value . 21))))))) + + +(ert-deftest five-items-cannot-be-greedy-by-value () + (should (= 80 (maximum-value 10 '(((:weight . 2) (:value . 20)) + ((:weight . 2) (:value . 20)) + ((:weight . 2) (:value . 20)) + ((:weight . 2) (:value . 20)) + ((:weight . 10) (:value . 50))))))) + + +(ert-deftest example-knapsack () + (should (= 90 (maximum-value 10 '(((:weight . 5) (:value . 10)) + ((:weight . 4) (:value . 40)) + ((:weight . 6) (:value . 30)) + ((:weight . 4) (:value . 50))))))) + + +(ert-deftest 8-items () + (should (= 900 (maximum-value 104 '(((:weight . 25) (:value . 350)) + ((:weight . 35) (:value . 400)) + ((:weight . 45) (:value . 450)) + ((:weight . 5) (:value . 20)) + ((:weight . 25) (:value . 70)) + ((:weight . 3) (:value . 8)) + ((:weight . 2) (:value . 5)) + ((:weight . 2) (:value . 5))))))) + + +(ert-deftest 15-items () + (should (= 1458 (maximum-value 750 '(((:weight . 70) (:value . 135)) + ((:weight . 73) (:value . 139)) + ((:weight . 77) (:value . 149)) + ((:weight . 80) (:value . 150)) + ((:weight . 82) (:value . 156)) + ((:weight . 87) (:value . 163)) + ((:weight . 90) (:value . 173)) + ((:weight . 94) (:value . 184)) + ((:weight . 98) (:value . 192)) + ((:weight . 106) (:value . 201)) + ((:weight . 110) (:value . 210)) + ((:weight . 113) (:value . 214)) + ((:weight . 115) (:value . 221)) + ((:weight . 118) (:value . 229)) + ((:weight . 120) (:value . 240))))))) + + +(provide 'knapsack-test) +;;; knapsack-test.el ends here diff --git a/exercises/practice/knapsack/knapsack.el b/exercises/practice/knapsack/knapsack.el new file mode 100644 index 00000000..7c0559dd --- /dev/null +++ b/exercises/practice/knapsack/knapsack.el @@ -0,0 +1,14 @@ +;;; knapsack.el --- Knapsack (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun maximum-value (maximum-weight items) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'knapsack) +;;; knapsack.el ends here + From 94a84673242d96ed71be6d11b5d4a6883d92e332 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Sat, 11 May 2024 12:04:36 +1000 Subject: [PATCH 081/162] Add protein-translation exercise (#378) --- config.json | 11 ++ .../protein-translation/.docs/instructions.md | 45 +++++ .../protein-translation/.meta/config.json | 18 ++ .../protein-translation/.meta/example.el | 44 +++++ .../protein-translation/.meta/tests.toml | 102 ++++++++++++ .../protein-translation-test.el | 156 ++++++++++++++++++ .../protein-translation.el | 14 ++ 7 files changed, 390 insertions(+) create mode 100644 exercises/practice/protein-translation/.docs/instructions.md create mode 100644 exercises/practice/protein-translation/.meta/config.json create mode 100644 exercises/practice/protein-translation/.meta/example.el create mode 100644 exercises/practice/protein-translation/.meta/tests.toml create mode 100644 exercises/practice/protein-translation/protein-translation-test.el create mode 100644 exercises/practice/protein-translation/protein-translation.el diff --git a/config.json b/config.json index 86913445..a580df95 100644 --- a/config.json +++ b/config.json @@ -465,6 +465,17 @@ "math" ] }, + { + "slug": "protein-translation", + "name": "Protein Translation", + "uuid": "3201c23c-e2eb-4e1a-8a44-b56acac572f5", + "practices": [], + "prerequisites": [], + "difficulty": 3, + "topics": [ + "strings" + ] + }, { "slug": "series", "name": "Series", diff --git a/exercises/practice/protein-translation/.docs/instructions.md b/exercises/practice/protein-translation/.docs/instructions.md new file mode 100644 index 00000000..7dc34d2e --- /dev/null +++ b/exercises/practice/protein-translation/.docs/instructions.md @@ -0,0 +1,45 @@ +# Instructions + +Translate RNA sequences into proteins. + +RNA can be broken into three nucleotide sequences called codons, and then translated to a polypeptide like so: + +RNA: `"AUGUUUUCU"` => translates to + +Codons: `"AUG", "UUU", "UCU"` +=> which become a polypeptide with the following sequence => + +Protein: `"Methionine", "Phenylalanine", "Serine"` + +There are 64 codons which in turn correspond to 20 amino acids; however, all of the codon sequences and resulting amino acids are not important in this exercise. +If it works for one codon, the program should work for all of them. +However, feel free to expand the list in the test suite to include them all. + +There are also three terminating codons (also known as 'STOP' codons); if any of these codons are encountered (by the ribosome), all translation ends and the protein is terminated. + +All subsequent codons after are ignored, like this: + +RNA: `"AUGUUUUCUUAAAUG"` => + +Codons: `"AUG", "UUU", "UCU", "UAA", "AUG"` => + +Protein: `"Methionine", "Phenylalanine", "Serine"` + +Note the stop codon `"UAA"` terminates the translation and the final methionine is not translated into the protein sequence. + +Below are the codons and resulting Amino Acids needed for the exercise. + +| Codon | Protein | +| :----------------- | :------------ | +| AUG | Methionine | +| UUU, UUC | Phenylalanine | +| UUA, UUG | Leucine | +| UCU, UCC, UCA, UCG | Serine | +| UAU, UAC | Tyrosine | +| UGU, UGC | Cysteine | +| UGG | Tryptophan | +| UAA, UAG, UGA | STOP | + +Learn more about [protein translation on Wikipedia][protein-translation]. + +[protein-translation]: https://en.wikipedia.org/wiki/Translation_(biology) diff --git a/exercises/practice/protein-translation/.meta/config.json b/exercises/practice/protein-translation/.meta/config.json new file mode 100644 index 00000000..bef5c3b6 --- /dev/null +++ b/exercises/practice/protein-translation/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "protein-translation.el" + ], + "test": [ + "protein-translation-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Translate RNA sequences into proteins.", + "source": "Tyler Long" +} diff --git a/exercises/practice/protein-translation/.meta/example.el b/exercises/practice/protein-translation/.meta/example.el new file mode 100644 index 00000000..255b7aff --- /dev/null +++ b/exercises/practice/protein-translation/.meta/example.el @@ -0,0 +1,44 @@ +;;; protein-translation.el --- Protein Translation (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun translate (codon) + (pcase codon + ("AUG" "Methionine") + ("UUU" "Phenylalanine") + ("UUC" "Phenylalanine") + ("UUA" "Leucine") + ("UUG" "Leucine") + ("UCU" "Serine") + ("UCC" "Serine") + ("UCA" "Serine") + ("UCG" "Serine") + ("UAU" "Tyrosine") + ("UAC" "Tyrosine") + ("UGU" "Cysteine") + ("UGC" "Cysteine") + ("UGG" "Tryptophan") + ("UAA" nil) + ("UAG" nil) + ("UGA" nil) + (otherwise (error "Invalid codon")))) + +(defun proteins (strand) + (let* ((len (length strand)) + (stop (- len (% len 3)))) + (cl-labels + ((recur (index) + (if (= index stop) + (unless (= index len) (error "Invalid codon")) + (let* ((next (+ index 3)) + (protein (translate (substring strand index next)))) + (when protein (cons protein (recur next))))))) + (recur 0)))) + +(provide 'protein-translation) +;;; protein-translation.el ends here + diff --git a/exercises/practice/protein-translation/.meta/tests.toml b/exercises/practice/protein-translation/.meta/tests.toml new file mode 100644 index 00000000..804b446e --- /dev/null +++ b/exercises/practice/protein-translation/.meta/tests.toml @@ -0,0 +1,102 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[2c44f7bf-ba20-43f7-a3bf-f2219c0c3f98] +description = "Empty RNA sequence results in no proteins" + +[96d3d44f-34a2-4db4-84cd-fff523e069be] +description = "Methionine RNA sequence" + +[1b4c56d8-d69f-44eb-be0e-7b17546143d9] +description = "Phenylalanine RNA sequence 1" + +[81b53646-bd57-4732-b2cb-6b1880e36d11] +description = "Phenylalanine RNA sequence 2" + +[42f69d4f-19d2-4d2c-a8b0-f0ae9ee1b6b4] +description = "Leucine RNA sequence 1" + +[ac5edadd-08ed-40a3-b2b9-d82bb50424c4] +description = "Leucine RNA sequence 2" + +[8bc36e22-f984-44c3-9f6b-ee5d4e73f120] +description = "Serine RNA sequence 1" + +[5c3fa5da-4268-44e5-9f4b-f016ccf90131] +description = "Serine RNA sequence 2" + +[00579891-b594-42b4-96dc-7ff8bf519606] +description = "Serine RNA sequence 3" + +[08c61c3b-fa34-4950-8c4a-133945570ef6] +description = "Serine RNA sequence 4" + +[54e1e7d8-63c0-456d-91d2-062c72f8eef5] +description = "Tyrosine RNA sequence 1" + +[47bcfba2-9d72-46ad-bbce-22f7666b7eb1] +description = "Tyrosine RNA sequence 2" + +[3a691829-fe72-43a7-8c8e-1bd083163f72] +description = "Cysteine RNA sequence 1" + +[1b6f8a26-ca2f-43b8-8262-3ee446021767] +description = "Cysteine RNA sequence 2" + +[1e91c1eb-02c0-48a0-9e35-168ad0cb5f39] +description = "Tryptophan RNA sequence" + +[e547af0b-aeab-49c7-9f13-801773a73557] +description = "STOP codon RNA sequence 1" + +[67640947-ff02-4f23-a2ef-816f8a2ba72e] +description = "STOP codon RNA sequence 2" + +[9c2ad527-ebc9-4ace-808b-2b6447cb54cb] +description = "STOP codon RNA sequence 3" + +[f4d9d8ee-00a8-47bf-a1e3-1641d4428e54] +description = "Sequence of two protein codons translates into proteins" + +[dd22eef3-b4f1-4ad6-bb0b-27093c090a9d] +description = "Sequence of two different protein codons translates into proteins" + +[d0f295df-fb70-425c-946c-ec2ec185388e] +description = "Translate RNA strand into correct protein list" + +[e30e8505-97ec-4e5f-a73e-5726a1faa1f4] +description = "Translation stops if STOP codon at beginning of sequence" + +[5358a20b-6f4c-4893-bce4-f929001710f3] +description = "Translation stops if STOP codon at end of two-codon sequence" + +[ba16703a-1a55-482f-bb07-b21eef5093a3] +description = "Translation stops if STOP codon at end of three-codon sequence" + +[4089bb5a-d5b4-4e71-b79e-b8d1f14a2911] +description = "Translation stops if STOP codon in middle of three-codon sequence" + +[2c2a2a60-401f-4a80-b977-e0715b23b93d] +description = "Translation stops if STOP codon in middle of six-codon sequence" + +[1e75ea2a-f907-4994-ae5c-118632a1cb0f] +description = "Non-existing codon can't translate" +include = false + +[9eac93f3-627a-4c90-8653-6d0a0595bc6f] +description = "Unknown amino acids, not part of a codon, can't translate" +reimplements = "1e75ea2a-f907-4994-ae5c-118632a1cb0f" + +[9d73899f-e68e-4291-b1e2-7bf87c00f024] +description = "Incomplete RNA sequence can't translate" + +[43945cf7-9968-402d-ab9f-b8a28750b050] +description = "Incomplete RNA sequence can translate if valid until a STOP codon" diff --git a/exercises/practice/protein-translation/protein-translation-test.el b/exercises/practice/protein-translation/protein-translation-test.el new file mode 100644 index 00000000..60575dbb --- /dev/null +++ b/exercises/practice/protein-translation/protein-translation-test.el @@ -0,0 +1,156 @@ +;;; protein-translation-test.el --- Tests for Protein Translation (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "protein-translation.el") +(declare-function proteins "protein-translation.el" (strand)) + + +(ert-deftest empty-rna-sequence-results-in-no-proteins () + (should (equal '() + (proteins "")))) + + +(ert-deftest methionine-rna-sequence () + (should (equal '("Methionine") + (proteins "AUG")))) + + +(ert-deftest phenylalanine-rna-sequence-1 () + (should (equal '("Phenylalanine") + (proteins "UUU")))) + + +(ert-deftest phenylalanine-rna-sequence-2 () + (should (equal '("Phenylalanine") + (proteins "UUC")))) + + +(ert-deftest leucine-rna-sequence-1 () + (should (equal '("Leucine") + (proteins "UUA")))) + + +(ert-deftest leucine-rna-sequence-2 () + (should (equal '("Leucine") + (proteins "UUG")))) + + +(ert-deftest serine-rna-sequence-1 () + (should (equal '("Serine") + (proteins "UCU")))) + + +(ert-deftest serine-rna-sequence-2 () + (should (equal '("Serine") + (proteins "UCC")))) + + +(ert-deftest serine-rna-sequence-3 () + (should (equal '("Serine") + (proteins "UCA")))) + + +(ert-deftest serine-rna-sequence-4 () + (should (equal '("Serine") + (proteins "UCG")))) + + +(ert-deftest tyrosine-rna-sequence-1 () + (should (equal '("Tyrosine") + (proteins "UAU")))) + + +(ert-deftest tyrosine-rna-sequence-2 () + (should (equal '("Tyrosine") + (proteins "UAC")))) + + +(ert-deftest cysteine-rna-sequence-1 () + (should (equal '("Cysteine") + (proteins "UGU")))) + + +(ert-deftest cysteine-rna-sequence-2 () + (should (equal '("Cysteine") + (proteins "UGC")))) + + +(ert-deftest tryptophan-rna-sequence () + (should (equal '("Tryptophan") + (proteins "UGG")))) + + +(ert-deftest stop-codon-rna-sequence-1 () + (should (equal '() + (proteins "UAA")))) + + +(ert-deftest stop-codon-rna-sequence-2 () + (should (equal '() + (proteins "UAG")))) + + +(ert-deftest stop-codon-rna-sequence-3 () + (should (equal '() + (proteins "UGA")))) + + +(ert-deftest sequence-of-two-protein-codons-translates-into-proteins () + (should (equal '("Phenylalanine" "Phenylalanine") + (proteins "UUUUUU")))) + + +(ert-deftest sequence-of-two-different-protein-codons-translates-into-proteins () + (should (equal '("Leucine" "Leucine") + (proteins "UUAUUG")))) + + +(ert-deftest translate-rna-strand-into-correct-protein-list () + (should (equal '("Methionine" "Phenylalanine" "Tryptophan") + (proteins "AUGUUUUGG")))) + + +(ert-deftest translation-stops-if-stop-codon-at-beginning-of-sequence () + (should (equal '() + (proteins "UAGUGG")))) + + +(ert-deftest translation-stops-if-stop-codon-at-end-of-two-codon-sequence () + (should (equal '("Tryptophan") + (proteins "UGGUAG")))) + + +(ert-deftest translation-stops-if-stop-codon-at-end-of-three-codon-sequence () + (should (equal '("Methionine" "Phenylalanine") + (proteins "AUGUUUUAA")))) + + +(ert-deftest translation-stops-if-stop-codon-in-middle-of-three-codon-sequence () + (should (equal '("Tryptophan") + (proteins "UGGUAGUGG")))) + + +(ert-deftest translation-stops-if-stop-codon-in-middle-of-six-codon-sequence () + (should (equal '("Tryptophan" "Cysteine" "Tyrosine") + (proteins "UGGUGUUAUUAAUGGUUU")))) + + +(ert-deftest unknown-amino-acids-not-part-of-a-codon-cant-translate () + (should-error (proteins "XYZ"))) + + +(ert-deftest incomplete-rna-sequence-cant-translate () + (should-error (proteins "AUGU"))) + + +(ert-deftest incomplete-rna-sequence-can-translate-if-valid-until-a-stop-codon () + (should (equal '("Phenylalanine" "Phenylalanine") + (proteins "UUCUUCUAAUGGU")))) + + +(provide 'protein-translation-test) +;;; protein-translation-test.el ends here diff --git a/exercises/practice/protein-translation/protein-translation.el b/exercises/practice/protein-translation/protein-translation.el new file mode 100644 index 00000000..1d5f5366 --- /dev/null +++ b/exercises/practice/protein-translation/protein-translation.el @@ -0,0 +1,14 @@ +;;; protein-translation.el --- Protein Translation (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun proteins (strand) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'protein-translation) +;;; protein-translation.el ends here + From c46d64c6e73cd0e63cdc4d0f025aeb171fa562da Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Sat, 11 May 2024 14:56:20 +1000 Subject: [PATCH 082/162] Add nth-prime exercise (#379) --- config.json | 11 +++++ .../practice/nth-prime/.docs/instructions.md | 7 ++++ .../practice/nth-prime/.meta/config.json | 19 +++++++++ exercises/practice/nth-prime/.meta/example.el | 42 +++++++++++++++++++ exercises/practice/nth-prime/.meta/tests.toml | 25 +++++++++++ .../practice/nth-prime/nth-prime-test.el | 33 +++++++++++++++ exercises/practice/nth-prime/nth-prime.el | 14 +++++++ 7 files changed, 151 insertions(+) create mode 100644 exercises/practice/nth-prime/.docs/instructions.md create mode 100644 exercises/practice/nth-prime/.meta/config.json create mode 100644 exercises/practice/nth-prime/.meta/example.el create mode 100644 exercises/practice/nth-prime/.meta/tests.toml create mode 100644 exercises/practice/nth-prime/nth-prime-test.el create mode 100644 exercises/practice/nth-prime/nth-prime.el diff --git a/config.json b/config.json index a580df95..a0a5c4ce 100644 --- a/config.json +++ b/config.json @@ -511,6 +511,17 @@ "strings" ] }, + { + "slug": "nth-prime", + "name": "Nth Prime", + "uuid": "4dfd9ac8-d0e8-4db5-a68c-75e8647b19c4", + "practices": [], + "prerequisites": [], + "difficulty": 4, + "topics": [ + "math" + ] + }, { "slug": "affine-cipher", "name": "Affine Cipher", diff --git a/exercises/practice/nth-prime/.docs/instructions.md b/exercises/practice/nth-prime/.docs/instructions.md new file mode 100644 index 00000000..065e323a --- /dev/null +++ b/exercises/practice/nth-prime/.docs/instructions.md @@ -0,0 +1,7 @@ +# Instructions + +Given a number n, determine what the nth prime is. + +By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13. + +If your language provides methods in the standard library to deal with prime numbers, pretend they don't exist and implement them yourself. diff --git a/exercises/practice/nth-prime/.meta/config.json b/exercises/practice/nth-prime/.meta/config.json new file mode 100644 index 00000000..33ae427a --- /dev/null +++ b/exercises/practice/nth-prime/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "nth-prime.el" + ], + "test": [ + "nth-prime-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given a number n, determine what the nth prime is.", + "source": "A variation on Problem 7 at Project Euler", + "source_url": "https://projecteuler.net/problem=7" +} diff --git a/exercises/practice/nth-prime/.meta/example.el b/exercises/practice/nth-prime/.meta/example.el new file mode 100644 index 00000000..3f07c768 --- /dev/null +++ b/exercises/practice/nth-prime/.meta/example.el @@ -0,0 +1,42 @@ +;;; nth-prime.el --- Nth Prime (exercism) -*- lexical-binding: t; -*- + + +;;; Commentary: + +; We use the prime number theorem to over-estimate the nth prime +; as 1 + n (log2 n) + +; We use the Sieve of Eratosthenes to generate primes. + + +;;; Code: + +(require 'cl-lib) + +(defun over-estimate (number) + (cl-loop for count from 1 + while (< (ash 1 count) number) + finally return (1+ (* number count)))) + +(defun prime (number) + (when (= number 0) + (error "there is no zeroth prime")) + (let* ((limit (over-estimate number)) + (table (make-bool-vector (1+ limit) t)) + (count 0)) + (cl-loop for p from 2 + for psq = (* p p) + until (< limit psq) + do (when (aref table p) + (cl-loop for m from psq to limit by p + do (aset table m nil)))) + (cl-loop for p from 2 + do (when (aref table p) + (setq count (1+ count))) + until (= count number) + finally return p))) + + +(provide 'nth-prime) +;;; nth-prime.el ends here + diff --git a/exercises/practice/nth-prime/.meta/tests.toml b/exercises/practice/nth-prime/.meta/tests.toml new file mode 100644 index 00000000..daccec42 --- /dev/null +++ b/exercises/practice/nth-prime/.meta/tests.toml @@ -0,0 +1,25 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[75c65189-8aef-471a-81de-0a90c728160c] +description = "first prime" + +[2c38804c-295f-4701-b728-56dea34fd1a0] +description = "second prime" + +[56692534-781e-4e8c-b1f9-3e82c1640259] +description = "sixth prime" + +[fce1e979-0edb-412d-93aa-2c744e8f50ff] +description = "big prime" + +[bd0a9eae-6df7-485b-a144-80e13c7d55b2] +description = "there is no zeroth prime" diff --git a/exercises/practice/nth-prime/nth-prime-test.el b/exercises/practice/nth-prime/nth-prime-test.el new file mode 100644 index 00000000..e7c436be --- /dev/null +++ b/exercises/practice/nth-prime/nth-prime-test.el @@ -0,0 +1,33 @@ +;;; nth-prime-test.el --- Tests for Nth Prime (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "nth-prime.el") +(declare-function prime "nth-prime.el" (number)) + + +(ert-deftest first-prime () + (should (= 2 (prime 1)))) + + +(ert-deftest second-prime () + (should (= 3 (prime 2)))) + + +(ert-deftest sixth-prime () + (should (= 13 (prime 6)))) + + +(ert-deftest big-prime () + (should (= 104743 (prime 10001)))) + + +(ert-deftest there-is-no-zeroth-prime () + (should-error (prime 0))) + + +(provide 'nth-prime-test) +;;; nth-prime-test.el ends here diff --git a/exercises/practice/nth-prime/nth-prime.el b/exercises/practice/nth-prime/nth-prime.el new file mode 100644 index 00000000..1c09096a --- /dev/null +++ b/exercises/practice/nth-prime/nth-prime.el @@ -0,0 +1,14 @@ +;;; nth-prime.el --- Nth Prime (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun prime (number) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'nth-prime) +;;; nth-prime.el ends here + From e2641cc46342feda4fb2d2c466555d659bcda325 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Sat, 11 May 2024 15:43:46 +1000 Subject: [PATCH 083/162] Add space-age exercise (#380) --- config.json | 8 +++ .../practice/space-age/.docs/instructions.md | 28 ++++++++++ .../practice/space-age/.docs/introduction.md | 20 +++++++ .../practice/space-age/.meta/config.json | 19 +++++++ exercises/practice/space-age/.meta/example.el | 26 +++++++++ exercises/practice/space-age/.meta/tests.toml | 37 +++++++++++++ .../practice/space-age/space-age-test.el | 53 +++++++++++++++++++ exercises/practice/space-age/space-age.el | 14 +++++ 8 files changed, 205 insertions(+) create mode 100644 exercises/practice/space-age/.docs/instructions.md create mode 100644 exercises/practice/space-age/.docs/introduction.md create mode 100644 exercises/practice/space-age/.meta/config.json create mode 100644 exercises/practice/space-age/.meta/example.el create mode 100644 exercises/practice/space-age/.meta/tests.toml create mode 100644 exercises/practice/space-age/space-age-test.el create mode 100644 exercises/practice/space-age/space-age.el diff --git a/config.json b/config.json index a0a5c4ce..5a0fdaa5 100644 --- a/config.json +++ b/config.json @@ -393,6 +393,14 @@ "prerequisites": [], "difficulty": 2 }, + { + "slug": "space-age", + "name": "Space Age", + "uuid": "183eb493-2141-4823-8fe6-0f01ecbcb27a", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "square-root", "name": "Square Root", diff --git a/exercises/practice/space-age/.docs/instructions.md b/exercises/practice/space-age/.docs/instructions.md new file mode 100644 index 00000000..f23b5e2c --- /dev/null +++ b/exercises/practice/space-age/.docs/instructions.md @@ -0,0 +1,28 @@ +# Instructions + +Given an age in seconds, calculate how old someone would be on a planet in our Solar System. + +One Earth year equals 365.25 Earth days, or 31,557,600 seconds. +If you were told someone was 1,000,000,000 seconds old, their age would be 31.69 Earth-years. + +For the other planets, you have to account for their orbital period in Earth Years: + +| Planet | Orbital period in Earth Years | +| ------- | ----------------------------- | +| Mercury | 0.2408467 | +| Venus | 0.61519726 | +| Earth | 1.0 | +| Mars | 1.8808158 | +| Jupiter | 11.862615 | +| Saturn | 29.447498 | +| Uranus | 84.016846 | +| Neptune | 164.79132 | + +~~~~exercism/note +The actual length of one complete orbit of the Earth around the sun is closer to 365.256 days (1 sidereal year). +The Gregorian calendar has, on average, 365.2425 days. +While not entirely accurate, 365.25 is the value used in this exercise. +See [Year on Wikipedia][year] for more ways to measure a year. + +[year]: https://en.wikipedia.org/wiki/Year#Summary +~~~~ diff --git a/exercises/practice/space-age/.docs/introduction.md b/exercises/practice/space-age/.docs/introduction.md new file mode 100644 index 00000000..014d7885 --- /dev/null +++ b/exercises/practice/space-age/.docs/introduction.md @@ -0,0 +1,20 @@ +# Introduction + +The year is 2525 and you've just embarked on a journey to visit all planets in the Solar System (Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus and Neptune). +The first stop is Mercury, where customs require you to fill out a form (bureaucracy is apparently _not_ Earth-specific). +As you hand over the form to the customs officer, they scrutinize it and frown. +"Do you _really_ expect me to believe you're just 50 years old? +You must be closer to 200 years old!" + +Amused, you wait for the customs officer to start laughing, but they appear to be dead serious. +You realize that you've entered your age in _Earth years_, but the officer expected it in _Mercury years_! +As Mercury's orbital period around the sun is significantly shorter than Earth, you're actually a lot older in Mercury years. +After some quick calculations, you're able to provide your age in Mercury Years. +The customs officer smiles, satisfied, and waves you through. +You make a mental note to pre-calculate your planet-specific age _before_ future customs checks, to avoid such mix-ups. + +~~~~exercism/note +If you're wondering why Pluto didn't make the cut, go watch [this YouTube video][pluto-video]. + +[pluto-video]: https://www.youtube.com/watch?v=Z_2gbGXzFbs +~~~~ diff --git a/exercises/practice/space-age/.meta/config.json b/exercises/practice/space-age/.meta/config.json new file mode 100644 index 00000000..94990597 --- /dev/null +++ b/exercises/practice/space-age/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "space-age.el" + ], + "test": [ + "space-age-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given an age in seconds, calculate how old someone is in terms of a given planet's solar years.", + "source": "Partially inspired by Chapter 1 in Chris Pine's online Learn to Program tutorial.", + "source_url": "https://pine.fm/LearnToProgram/?Chapter=01" +} diff --git a/exercises/practice/space-age/.meta/example.el b/exercises/practice/space-age/.meta/example.el new file mode 100644 index 00000000..86a4835b --- /dev/null +++ b/exercises/practice/space-age/.meta/example.el @@ -0,0 +1,26 @@ +;;; space-age.el --- Space Age (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun orbital-period (planet) + (pcase planet + (:mercury 0.2408467) + (:venus 0.61519726) + (:earth 1.0) + (:mars 1.8808158) + (:jupiter 11.862615) + (:saturn 29.447498) + (:uranus 84.016846) + (:neptune 164.79132) + (_ (error "not a planet")))) + +(defun age (planet seconds) + (/ seconds (* (orbital-period planet) 31557600))) + + +(provide 'space-age) +;;; space-age.el ends here + diff --git a/exercises/practice/space-age/.meta/tests.toml b/exercises/practice/space-age/.meta/tests.toml new file mode 100644 index 00000000..7957bb77 --- /dev/null +++ b/exercises/practice/space-age/.meta/tests.toml @@ -0,0 +1,37 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[84f609af-5a91-4d68-90a3-9e32d8a5cd34] +description = "age on Earth" + +[ca20c4e9-6054-458c-9312-79679ffab40b] +description = "age on Mercury" + +[502c6529-fd1b-41d3-8fab-65e03082b024] +description = "age on Venus" + +[9ceadf5e-a0d5-4388-9d40-2c459227ceb8] +description = "age on Mars" + +[42927dc3-fe5e-4f76-a5b5-f737fc19bcde] +description = "age on Jupiter" + +[8469b332-7837-4ada-b27c-00ee043ebcad] +description = "age on Saturn" + +[999354c1-76f8-4bb5-a672-f317b6436743] +description = "age on Uranus" + +[80096d30-a0d4-4449-903e-a381178355d8] +description = "age on Neptune" + +[57b96e2a-1178-40b7-b34d-f3c9c34e4bf4] +description = "invalid planet causes error" diff --git a/exercises/practice/space-age/space-age-test.el b/exercises/practice/space-age/space-age-test.el new file mode 100644 index 00000000..8e99d48f --- /dev/null +++ b/exercises/practice/space-age/space-age-test.el @@ -0,0 +1,53 @@ +;;; space-age-test.el --- Tests for Space Age (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "space-age.el") +(declare-function age "space-age.el" (planet seconds)) + + +(defmacro should-approximate (expected actual) + (list 'should (list '< (- expected 0.01) actual (+ expected 0.01)))) + + +(ert-deftest age-on-earth () + (should-approximate 31.69 (age :earth 1000000000))) + + +(ert-deftest age-on-mercury () + (should-approximate 280.88 (age :mercury 2134835688))) + + +(ert-deftest age-on-venus () + (should-approximate 9.78 (age :venus 189839836))) + + +(ert-deftest age-on-mars () + (should-approximate 35.88 (age :mars 2129871239))) + + +(ert-deftest age-on-jupiter () + (should-approximate 2.41 (age :jupiter 901876382))) + + +(ert-deftest age-on-saturn () + (should-approximate 2.15 (age :saturn 2000000000))) + + +(ert-deftest age-on-uranus () + (should-approximate 0.46 (age :uranus 1210123456))) + + +(ert-deftest age-on-neptune () + (should-approximate 0.35 (age :neptune 1821023456))) + + +(ert-deftest invalid-planet-causes-error () + (should-error (age :sun 680804807))) + + +(provide 'space-age-test) +;;; space-age-test.el ends here diff --git a/exercises/practice/space-age/space-age.el b/exercises/practice/space-age/space-age.el new file mode 100644 index 00000000..502a22ff --- /dev/null +++ b/exercises/practice/space-age/space-age.el @@ -0,0 +1,14 @@ +;;; space-age.el --- Space Age (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun age (planet seconds) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'space-age) +;;; space-age.el ends here + From 894151d55fb1e654230fc70e2093f5ae9c107821 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Mon, 13 May 2024 05:30:11 +1000 Subject: [PATCH 084/162] Add sum-of-multiples exercise (#382) * Add sum-of-multiples exercise * empty stub --- config.json | 11 +++ .../sum-of-multiples/.docs/instructions.md | 27 +++++++ .../sum-of-multiples/.docs/introduction.md | 6 ++ .../sum-of-multiples/.meta/config.json | 19 +++++ .../sum-of-multiples/.meta/example.el | 21 +++++ .../sum-of-multiples/.meta/tests.toml | 58 ++++++++++++++ .../sum-of-multiples/sum-of-multiples-test.el | 77 +++++++++++++++++++ .../sum-of-multiples/sum-of-multiples.el | 13 ++++ 8 files changed, 232 insertions(+) create mode 100644 exercises/practice/sum-of-multiples/.docs/instructions.md create mode 100644 exercises/practice/sum-of-multiples/.docs/introduction.md create mode 100644 exercises/practice/sum-of-multiples/.meta/config.json create mode 100644 exercises/practice/sum-of-multiples/.meta/example.el create mode 100644 exercises/practice/sum-of-multiples/.meta/tests.toml create mode 100644 exercises/practice/sum-of-multiples/sum-of-multiples-test.el create mode 100644 exercises/practice/sum-of-multiples/sum-of-multiples.el diff --git a/config.json b/config.json index 5a0fdaa5..ee954486 100644 --- a/config.json +++ b/config.json @@ -429,6 +429,17 @@ "recursion" ] }, + { + "slug": "sum-of-multiples", + "name": "Sum of Multiples", + "uuid": "3df22483-1a7c-445d-9eca-131a00c74231", + "practices": [], + "prerequisites": [], + "difficulty": 2, + "topics": [ + "math" + ] + }, { "slug": "triangle", "name": "Triangle", diff --git a/exercises/practice/sum-of-multiples/.docs/instructions.md b/exercises/practice/sum-of-multiples/.docs/instructions.md new file mode 100644 index 00000000..d69f890e --- /dev/null +++ b/exercises/practice/sum-of-multiples/.docs/instructions.md @@ -0,0 +1,27 @@ +# Instructions + +Your task is to write the code that calculates the energy points that get awarded to players when they complete a level. + +The points awarded depend on two things: + +- The level (a number) that the player completed. +- The base value of each magical item collected by the player during that level. + +The energy points are awarded according to the following rules: + +1. For each magical item, take the base value and find all the multiples of that value that are less than the level number. +2. Combine the sets of numbers. +3. Remove any duplicates. +4. Calculate the sum of all the numbers that are left. + +Let's look at an example: + +**The player completed level 20 and found two magical items with base values of 3 and 5.** + +To calculate the energy points earned by the player, we need to find all the unique multiples of these base values that are less than level 20. + +- Multiples of 3 less than 20: `{3, 6, 9, 12, 15, 18}` +- Multiples of 5 less than 20: `{5, 10, 15}` +- Combine the sets and remove duplicates: `{3, 5, 6, 9, 10, 12, 15, 18}` +- Sum the unique multiples: `3 + 5 + 6 + 9 + 10 + 12 + 15 + 18 = 78` +- Therefore, the player earns **78** energy points for completing level 20 and finding the two magical items with base values of 3 and 5. diff --git a/exercises/practice/sum-of-multiples/.docs/introduction.md b/exercises/practice/sum-of-multiples/.docs/introduction.md new file mode 100644 index 00000000..69cabeed --- /dev/null +++ b/exercises/practice/sum-of-multiples/.docs/introduction.md @@ -0,0 +1,6 @@ +# Introduction + +You work for a company that makes an online, fantasy-survival game. + +When a player finishes a level, they are awarded energy points. +The amount of energy awarded depends on which magical items the player found while exploring that level. diff --git a/exercises/practice/sum-of-multiples/.meta/config.json b/exercises/practice/sum-of-multiples/.meta/config.json new file mode 100644 index 00000000..eb31d82f --- /dev/null +++ b/exercises/practice/sum-of-multiples/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "sum-of-multiples.el" + ], + "test": [ + "sum-of-multiples-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given a number, find the sum of all the multiples of particular numbers up to but not including that number.", + "source": "A variation on Problem 1 at Project Euler", + "source_url": "https://projecteuler.net/problem=1" +} diff --git a/exercises/practice/sum-of-multiples/.meta/example.el b/exercises/practice/sum-of-multiples/.meta/example.el new file mode 100644 index 00000000..20b08480 --- /dev/null +++ b/exercises/practice/sum-of-multiples/.meta/example.el @@ -0,0 +1,21 @@ +;;; sum-of-multiples.el --- Sum of Multiples (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun sum (factors limit) + (let* ((set (make-hash-table)) + (total 0)) + (dolist (factor (remove 0 factors)) + (cl-loop for multiple from factor below limit by factor + do (puthash multiple t set))) + (maphash (lambda (key value) (setq total (+ total key))) + set) + total)) + +(provide 'sum-of-multiples) +;;; sum-of-multiples.el ends here + diff --git a/exercises/practice/sum-of-multiples/.meta/tests.toml b/exercises/practice/sum-of-multiples/.meta/tests.toml new file mode 100644 index 00000000..1e9b1241 --- /dev/null +++ b/exercises/practice/sum-of-multiples/.meta/tests.toml @@ -0,0 +1,58 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[54aaab5a-ce86-4edc-8b40-d3ab2400a279] +description = "no multiples within limit" + +[361e4e50-c89b-4f60-95ef-5bc5c595490a] +description = "one factor has multiples within limit" + +[e644e070-040e-4ae0-9910-93c69fc3f7ce] +description = "more than one multiple within limit" + +[607d6eb9-535c-41ce-91b5-3a61da3fa57f] +description = "more than one factor with multiples within limit" + +[f47e8209-c0c5-4786-b07b-dc273bf86b9b] +description = "each multiple is only counted once" + +[28c4b267-c980-4054-93e9-07723db615ac] +description = "a much larger limit" + +[09c4494d-ff2d-4e0f-8421-f5532821ee12] +description = "three factors" + +[2d0d5faa-f177-4ad6-bde9-ebb865083751] +description = "factors not relatively prime" + +[ece8f2e8-96aa-4166-bbb7-6ce71261e354] +description = "some pairs of factors relatively prime and some not" + +[624fdade-6ffb-400e-8472-456a38c171c0] +description = "one factor is a multiple of another" + +[949ee7eb-db51-479c-b5cb-4a22b40ac057] +description = "much larger factors" + +[41093673-acbd-482c-ab80-d00a0cbedecd] +description = "all numbers are multiples of 1" + +[1730453b-baaa-438e-a9c2-d754497b2a76] +description = "no factors means an empty sum" + +[214a01e9-f4bf-45bb-80f1-1dce9fbb0310] +description = "the only multiple of 0 is 0" + +[c423ae21-a0cb-4ec7-aeb1-32971af5b510] +description = "the factor 0 does not affect the sum of multiples of other factors" + +[17053ba9-112f-4ac0-aadb-0519dd836342] +description = "solutions using include-exclude must extend to cardinality greater than 3" diff --git a/exercises/practice/sum-of-multiples/sum-of-multiples-test.el b/exercises/practice/sum-of-multiples/sum-of-multiples-test.el new file mode 100644 index 00000000..cdee87cd --- /dev/null +++ b/exercises/practice/sum-of-multiples/sum-of-multiples-test.el @@ -0,0 +1,77 @@ +;;; sum-of-multiples-test.el --- Tests for Sum of Multiples (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "sum-of-multiples.el") +(declare-function sum "sum-of-multiples.el" (factors limit)) + + +(ert-deftest no-multiples-within-limit () + (should (= 0 (sum '(3 5) 1)))) + + +(ert-deftest one-factor-has-multiples-within-limit () + (should (= 3 (sum '(3 5) 4)))) + + +(ert-deftest more-than-one-multiple-within-limit () + (should (= 9 (sum '(3) 7)))) + + +(ert-deftest more-than-one-factor-with-multiples-within-limit () + (should (= 23 (sum '(3 5) 10)))) + + +(ert-deftest each-multiple-is-only-counted-once () + (should (= 2318 (sum '(3 5) 100)))) + + +(ert-deftest a-much-larger-limit () + (should (= 233168 (sum '(3 5) 1000)))) + + +(ert-deftest three-factors () + (should (= 51 (sum '(7 13 17) 20)))) + + +(ert-deftest factors-not-relatively-prime () + (should (= 30 (sum '(4 6) 15)))) + + +(ert-deftest some-pairs-of-factors-relatively-prime-and-some-not () + (should (= 4419 (sum '(5 6 8) 150)))) + + +(ert-deftest one-factor-is-a-multiple-of-another () + (should (= 275 (sum '(5 25) 51)))) + + +(ert-deftest much-larger-factors () + (should (= 2203160 (sum '(43 47) 10000)))) + + +(ert-deftest all-numbers-are-multiples-of-1 () + (should (= 4950 (sum '(1) 100)))) + + +(ert-deftest no-factors-means-an-empty-sum () + (should (= 0 (sum '() 10000)))) + + +(ert-deftest the-only-multiple-of-0-is-0 () + (should (= 0 (sum '(0) 1)))) + + +(ert-deftest the-factor-0-does-not-affect-the-sum-of-multiples-of-other-factors () + (should (= 3 (sum '(3 0) 4)))) + + +(ert-deftest solutions-using-include-exclude-must-extend-to-cardinality-greater-than-3 () + (should (= 39614537 (sum '(2 3 5 7 11) 10000)))) + + +(provide 'sum-of-multiples-test) +;;; sum-of-multiples-test.el ends here diff --git a/exercises/practice/sum-of-multiples/sum-of-multiples.el b/exercises/practice/sum-of-multiples/sum-of-multiples.el new file mode 100644 index 00000000..9426de56 --- /dev/null +++ b/exercises/practice/sum-of-multiples/sum-of-multiples.el @@ -0,0 +1,13 @@ +;;; sum-of-multiples.el --- Sum of Multiples (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun sum (factors limit) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'sum-of-multiples) +;;; sum-of-multiples.el ends here From 36ac94c1e6cb693833e185a1e3ac2d9a04ad881a Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Mon, 13 May 2024 05:33:01 +1000 Subject: [PATCH 085/162] Add minesweeper exercise (#381) --- config.json | 13 +- .../minesweeper/.docs/instructions.md | 26 ++++ .../minesweeper/.docs/introduction.md | 5 + .../practice/minesweeper/.meta/config.json | 17 +++ .../practice/minesweeper/.meta/example.el | 36 +++++ .../practice/minesweeper/.meta/tests.toml | 46 ++++++ .../practice/minesweeper/minesweeper-test.el | 135 ++++++++++++++++++ exercises/practice/minesweeper/minesweeper.el | 14 ++ 8 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 exercises/practice/minesweeper/.docs/instructions.md create mode 100644 exercises/practice/minesweeper/.docs/introduction.md create mode 100644 exercises/practice/minesweeper/.meta/config.json create mode 100644 exercises/practice/minesweeper/.meta/example.el create mode 100644 exercises/practice/minesweeper/.meta/tests.toml create mode 100644 exercises/practice/minesweeper/minesweeper-test.el create mode 100644 exercises/practice/minesweeper/minesweeper.el diff --git a/config.json b/config.json index ee954486..3572df2b 100644 --- a/config.json +++ b/config.json @@ -244,7 +244,7 @@ "functional_programming", "generics", "lists", - "loops" + "control_flow_loops" ] }, { @@ -637,6 +637,17 @@ "strings" ] }, + { + "slug": "minesweeper", + "name": "Minesweeper", + "uuid": "58e8c0ba-6a1c-4285-bea3-4809a6987da0", + "practices": [], + "prerequisites": [], + "difficulty": 5, + "topics": [ + "control_flow_loops" + ] + }, { "slug": "nucleotide-count", "name": "Nucleotide Count", diff --git a/exercises/practice/minesweeper/.docs/instructions.md b/exercises/practice/minesweeper/.docs/instructions.md new file mode 100644 index 00000000..7c1df2e4 --- /dev/null +++ b/exercises/practice/minesweeper/.docs/instructions.md @@ -0,0 +1,26 @@ +# Instructions + +Your task is to add the mine counts to empty squares in a completed Minesweeper board. +The board itself is a rectangle composed of squares that are either empty (`' '`) or a mine (`'*'`). + +For each empty square, count the number of mines adjacent to it (horizontally, vertically, diagonally). +If the empty square has no adjacent mines, leave it empty. +Otherwise replace it with the adjacent mines count. + +For example, you may receive a 5 x 4 board like this (empty spaces are represented here with the '·' character for display on screen): + +```text +·*·*· +··*·· +··*·· +····· +``` + +Which your code should transform into this: + +```text +1*3*1 +13*31 +·2*2· +·111· +``` diff --git a/exercises/practice/minesweeper/.docs/introduction.md b/exercises/practice/minesweeper/.docs/introduction.md new file mode 100644 index 00000000..5f74a742 --- /dev/null +++ b/exercises/practice/minesweeper/.docs/introduction.md @@ -0,0 +1,5 @@ +# Introduction + +[Minesweeper][wikipedia] is a popular game where the user has to find the mines using numeric hints that indicate how many mines are directly adjacent (horizontally, vertically, diagonally) to a square. + +[wikipedia]: https://en.wikipedia.org/wiki/Minesweeper_(video_game) diff --git a/exercises/practice/minesweeper/.meta/config.json b/exercises/practice/minesweeper/.meta/config.json new file mode 100644 index 00000000..0bc81f7a --- /dev/null +++ b/exercises/practice/minesweeper/.meta/config.json @@ -0,0 +1,17 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "minesweeper.el" + ], + "test": [ + "minesweeper-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Add the numbers to a minesweeper board." +} diff --git a/exercises/practice/minesweeper/.meta/example.el b/exercises/practice/minesweeper/.meta/example.el new file mode 100644 index 00000000..f2cab1bf --- /dev/null +++ b/exercises/practice/minesweeper/.meta/example.el @@ -0,0 +1,36 @@ +;;; minesweeper.el --- Minesweeper (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun annotate (minefield) + (when minefield + (let* ((num-columns (length (car minefield))) + (lines (vconcat minefield)) + (num-rows (length lines)) + (results nil)) + (cl-loop for row from (1- num-rows) downto 0 + for result = (copy-sequence (aref lines row)) + for r-start = (max 0 (1- row)) + for r-end = (min num-rows (+ 2 row)) + do (cl-loop for column from 0 below num-columns + for c-start = (max 0 (1- column)) + for c-end = (min num-columns (+ 2 column)) + for count = 0 + do (unless (= ?* (aref result column)) + (cl-loop for r from r-start below r-end + for line = (aref lines r) + do (cl-loop for c from c-start below c-end + do (when (= ?* (aref line c)) + (setq count (1+ count))))) + (unless (= 0 count) + (aset result column (+ ?0 count))))) + do (setq results (cons result results))) + results))) + +(provide 'minesweeper) +;;; minesweeper.el ends here + diff --git a/exercises/practice/minesweeper/.meta/tests.toml b/exercises/practice/minesweeper/.meta/tests.toml new file mode 100644 index 00000000..2a142222 --- /dev/null +++ b/exercises/practice/minesweeper/.meta/tests.toml @@ -0,0 +1,46 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[0c5ec4bd-dea7-4138-8651-1203e1cb9f44] +description = "no rows" + +[650ac4c0-ad6b-4b41-acde-e4ea5852c3b8] +description = "no columns" + +[6fbf8f6d-a03b-42c9-9a58-b489e9235478] +description = "no mines" + +[61aff1c4-fb31-4078-acad-cd5f1e635655] +description = "minefield with only mines" + +[84167147-c504-4896-85d7-246b01dea7c5] +description = "mine surrounded by spaces" + +[cb878f35-43e3-4c9d-93d9-139012cccc4a] +description = "space surrounded by mines" + +[7037f483-ddb4-4b35-b005-0d0f4ef4606f] +description = "horizontal line" + +[e359820f-bb8b-4eda-8762-47b64dba30a6] +description = "horizontal line, mines at edges" + +[c5198b50-804f-47e9-ae02-c3b42f7ce3ab] +description = "vertical line" + +[0c79a64d-703d-4660-9e90-5adfa5408939] +description = "vertical line, mines at edges" + +[4b098563-b7f3-401c-97c6-79dd1b708f34] +description = "cross" + +[04a260f1-b40a-4e89-839e-8dd8525abe0e] +description = "large minefield" diff --git a/exercises/practice/minesweeper/minesweeper-test.el b/exercises/practice/minesweeper/minesweeper-test.el new file mode 100644 index 00000000..8659a963 --- /dev/null +++ b/exercises/practice/minesweeper/minesweeper-test.el @@ -0,0 +1,135 @@ +;;; minesweeper-test.el --- Tests for Minesweeper (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "minesweeper.el") +(declare-function annotate "minesweeper.el" (minefield)) + + +(ert-deftest no-rows () + (should (equal '() + + (annotate '())))) + + +(ert-deftest no-columns () + (should (equal '("") + + (annotate '(""))))) + + +(ert-deftest no-mines () + (should (equal '(" " + " " + " ") + + (annotate '(" " + " " + " "))))) + + +(ert-deftest minefield-with-only-mines () + (should (equal '("***" + "***" + "***") + + (annotate '("***" + "***" + "***"))))) + + +(ert-deftest mine-surrounded-by-spaces () + (should (equal '("111" + "1*1" + "111") + + (annotate '(" " + " * " + " "))))) + + +(ert-deftest space-surrounded-by-mines () + (should (equal '("***" + "*8*" + "***") + + (annotate '("***" + "* *" + "***"))))) + + +(ert-deftest horizontal-line () + (should (equal '("1*2*1") + + (annotate '(" * * "))))) + + +(ert-deftest horizontal-line-mines-at-edges () + (should (equal '("*1 1*") + + (annotate '("* *"))))) + + +(ert-deftest vertical-line () + (should (equal '("1" + "*" + "2" + "*" + "1") + + (annotate '(" " + "*" + " " + "*" + " "))))) + + +(ert-deftest vertical-line-mines-at-edges () + (should (equal '("*" + "1" + " " + "1" + "*") + + (annotate '("*" + " " + " " + " " + "*"))))) + + +(ert-deftest cross () + (should (equal '(" 2*2 " + "25*52" + "*****" + "25*52" + " 2*2 ") + + (annotate '(" * " + " * " + "*****" + " * " + " * "))))) + + +(ert-deftest large-minefield () + (should (equal '("1*22*1" + "12*322" + " 123*2" + "112*4*" + "1*22*2" + "111111") + + (annotate '(" * * " + " * " + " * " + " * *" + " * * " + " "))))) + + +(provide 'minesweeper-test) +;;; minesweeper-test.el ends here diff --git a/exercises/practice/minesweeper/minesweeper.el b/exercises/practice/minesweeper/minesweeper.el new file mode 100644 index 00000000..45a5c41f --- /dev/null +++ b/exercises/practice/minesweeper/minesweeper.el @@ -0,0 +1,14 @@ +;;; minesweeper.el --- Minesweeper (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun annotate (minefield) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'minesweeper) +;;; minesweeper.el ends here + From 60b517c1145264e01fb0188f219e0f362933bbb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Sun, 12 May 2024 21:06:31 -0700 Subject: [PATCH 086/162] Deprecate trinary for all-your-base (#383) --- config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.json b/config.json index 3572df2b..968f9b25 100644 --- a/config.json +++ b/config.json @@ -460,7 +460,8 @@ "difficulty": 2, "topics": [ "math" - ] + ], + "status": "deprecated" }, { "slug": "two-fer", From 76121e2d5031072c627046b7ccd9300162cc4a1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Sun, 12 May 2024 21:06:47 -0700 Subject: [PATCH 087/162] Sync tests for luhn and update stub (#384) --- exercises/practice/luhn/.meta/tests.toml | 3 +++ exercises/practice/luhn/luhn.el | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/exercises/practice/luhn/.meta/tests.toml b/exercises/practice/luhn/.meta/tests.toml index c0be0c4d..98626ea0 100644 --- a/exercises/practice/luhn/.meta/tests.toml +++ b/exercises/practice/luhn/.meta/tests.toml @@ -68,9 +68,12 @@ description = "valid luhn with an odd number of digits and non zero first digit" [39a06a5a-5bad-4e0f-b215-b042d46209b1] description = "using ascii value for non-doubled non-digit isn't allowed" +include = false [f94cf191-a62f-4868-bc72-7253114aa157] description = "using ascii value for doubled non-digit isn't allowed" +include = false [8b72ad26-c8be-49a2-b99c-bcc3bf631b33] description = "non-numeric, non-space char in the middle with a sum that's divisible by 10 isn't allowed" +include = false diff --git a/exercises/practice/luhn/luhn.el b/exercises/practice/luhn/luhn.el index 039007f2..5801251f 100644 --- a/exercises/practice/luhn/luhn.el +++ b/exercises/practice/luhn/luhn.el @@ -1,10 +1,14 @@ -;;; luhn.el --- Luhn exercise (exercism) -*- lexical-binding: t; -*- +;;; luhn.el --- Luhn (exercism) -*- lexical-binding: t; -*- ;;; Commentary: -(defun luhn-p (str) ;;; Code: -) + + +(defun luhn-p (str) + (error "Delete this S-Expression and write your own implementation")) + (provide 'luhn) ;;; luhn.el ends here + From ee74738071b646b6fdc5c2d636141d043fa4fd72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Sun, 12 May 2024 21:07:04 -0700 Subject: [PATCH 088/162] Sync test inputs for bob (#385) * Sync test inputs for bob * Update stub --- exercises/practice/bob/bob-test.el | 10 +++++----- exercises/practice/bob/bob.el | 9 ++++++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/exercises/practice/bob/bob-test.el b/exercises/practice/bob/bob-test.el index 2c8a2544..ea481e6f 100644 --- a/exercises/practice/bob/bob-test.el +++ b/exercises/practice/bob/bob-test.el @@ -33,19 +33,19 @@ (ert-deftest responds-to-talking-forcefully () (should - (string= "Whatever." (response-for "Let's go make out behind the gym!")))) + (string= "Whatever." (response-for "Hi there!")))) (ert-deftest responds-to-using-acronyms-in-regular-speech () (should - (string= "Whatever." (response-for "It's OK if you don't want to go to the DMV.")))) + (string= "Whatever." (response-for "It's OK if you don't want to go work for NASA.")))) (ert-deftest responds-to-forceful-question () (should - (string= "Calm down, I know what I'm doing!" (response-for "WHAT THE HELL WERE YOU THINKING?")))) + (string= "Calm down, I know what I'm doing!" (response-for "WHAT'S GOING ON?")))) (ert-deftest responds-to-shouting-numbers () (should - (string= "Whoa, chill out!" (response-for "1, 2, 3, GO!")))) + (string= "Whoa, chill out!" (response-for "1, 2, 3 GO!")))) (ert-deftest responds-to-only-numbers () (should @@ -61,7 +61,7 @@ (ert-deftest responds-to-shouting-with-no-exclamation-mark () (should - (string= "Whoa, chill out!" (response-for "I HATE YOU")))) + (string= "Whoa, chill out!" (response-for "I HATE THE DENTIST")))) (ert-deftest responds-to-statement-containing-question-mark () (should diff --git a/exercises/practice/bob/bob.el b/exercises/practice/bob/bob.el index 92089eb4..d2e36b7d 100644 --- a/exercises/practice/bob/bob.el +++ b/exercises/practice/bob/bob.el @@ -1,10 +1,13 @@ -;;; bob.el --- Bob exercise (exercism) -*- lexical-binding: t; -*- +;;; bob.el --- Bob (exercism) -*- lexical-binding: t; -*- ;;; Commentary: -(defun response-for (phrase) ;;; Code: -) + + +(defun response-for (phrase) + (error "Delete this S-Expression and write your own implementation")) + (provide 'bob) ;;; bob.el ends here From 967f1d112bf0853bbba36d7cdfb6b79cb915116e Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Tue, 14 May 2024 01:27:04 +1000 Subject: [PATCH 089/162] Add game-of-life exercise (#387) --- config.json | 12 +++ .../game-of-life/.docs/instructions.md | 11 +++ .../game-of-life/.docs/introduction.md | 9 ++ .../practice/game-of-life/.meta/config.json | 19 ++++ .../practice/game-of-life/.meta/example.el | 41 ++++++++ .../practice/game-of-life/.meta/tests.toml | 34 +++++++ .../game-of-life/game-of-life-test.el | 99 +++++++++++++++++++ .../practice/game-of-life/game-of-life.el | 14 +++ 8 files changed, 239 insertions(+) create mode 100644 exercises/practice/game-of-life/.docs/instructions.md create mode 100644 exercises/practice/game-of-life/.docs/introduction.md create mode 100644 exercises/practice/game-of-life/.meta/config.json create mode 100644 exercises/practice/game-of-life/.meta/example.el create mode 100644 exercises/practice/game-of-life/.meta/tests.toml create mode 100644 exercises/practice/game-of-life/game-of-life-test.el create mode 100644 exercises/practice/game-of-life/game-of-life.el diff --git a/config.json b/config.json index 968f9b25..5f9c5c3f 100644 --- a/config.json +++ b/config.json @@ -625,6 +625,18 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "game-of-life", + "name": "Conway's Game of Life", + "uuid": "4e8130a9-bdde-46c5-bb50-e780c3af8670", + "practices": [], + "prerequisites": [], + "difficulty": 5, + "topics": [ + "control_flow_loops", + "lists" + ] + }, { "slug": "luhn", "name": "Luhn", diff --git a/exercises/practice/game-of-life/.docs/instructions.md b/exercises/practice/game-of-life/.docs/instructions.md new file mode 100644 index 00000000..49531406 --- /dev/null +++ b/exercises/practice/game-of-life/.docs/instructions.md @@ -0,0 +1,11 @@ +# Instructions + +After each generation, the cells interact with their eight neighbors, which are cells adjacent horizontally, vertically, or diagonally. + +The following rules are applied to each cell: + +- Any live cell with two or three live neighbors lives on. +- Any dead cell with exactly three live neighbors becomes a live cell. +- All other cells die or stay dead. + +Given a matrix of 1s and 0s (corresponding to live and dead cells), apply the rules to each cell, and return the next generation. diff --git a/exercises/practice/game-of-life/.docs/introduction.md b/exercises/practice/game-of-life/.docs/introduction.md new file mode 100644 index 00000000..2347b936 --- /dev/null +++ b/exercises/practice/game-of-life/.docs/introduction.md @@ -0,0 +1,9 @@ +# Introduction + +[Conway's Game of Life][game-of-life] is a fascinating cellular automaton created by the British mathematician John Horton Conway in 1970. + +The game consists of a two-dimensional grid of cells that can either be "alive" or "dead." + +After each generation, the cells interact with their eight neighbors via a set of rules, which define the new generation. + +[game-of-life]: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life diff --git a/exercises/practice/game-of-life/.meta/config.json b/exercises/practice/game-of-life/.meta/config.json new file mode 100644 index 00000000..4ecf5937 --- /dev/null +++ b/exercises/practice/game-of-life/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "game-of-life.el" + ], + "test": [ + "game-of-life-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Implement Conway's Game of Life.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life" +} diff --git a/exercises/practice/game-of-life/.meta/example.el b/exercises/practice/game-of-life/.meta/example.el new file mode 100644 index 00000000..c1b9f875 --- /dev/null +++ b/exercises/practice/game-of-life/.meta/example.el @@ -0,0 +1,41 @@ +;;; game-of-life.el --- Conway's Game of Life (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun tick (matrix) + (when matrix + (let* ((lines (vconcat (mapcar #'vconcat matrix))) + (num-rows (length lines)) + (num-columns (length (aref lines 0))) + (results nil)) + (cl-loop for row from (1- num-rows) downto 0 + for result = nil + for r-start = (max 0 (1- row)) + for r-end = (min num-rows (+ 2 row)) + do (cl-loop for column from (1- num-columns) downto 0 + for c-start = (max 0 (1- column)) + for c-end = (min num-columns (+ 2 column)) + for previous = (aref (aref lines row) column) + for count = (- previous) + do (cl-loop for r from r-start below r-end + for line = (aref lines r) + do (cl-loop for c from c-start below c-end + do (when (= 1 (aref line c)) + (setq count (1+ count))))) + for cell = (cl-case count + (3 1) + (2 previous) + (t 0)) + do (setq result (cons cell result))) + + do (setq results (cons result results))) + results))) + + +(provide 'game-of-life) +;;; game-of-life.el ends here + diff --git a/exercises/practice/game-of-life/.meta/tests.toml b/exercises/practice/game-of-life/.meta/tests.toml new file mode 100644 index 00000000..398cd454 --- /dev/null +++ b/exercises/practice/game-of-life/.meta/tests.toml @@ -0,0 +1,34 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[ae86ea7d-bd07-4357-90b3-ac7d256bd5c5] +description = "empty matrix" + +[4ea5ccb7-7b73-4281-954a-bed1b0f139a5] +description = "live cells with zero live neighbors die" + +[df245adc-14ff-4f9c-b2ae-f465ef5321b2] +description = "live cells with only one live neighbor die" + +[2a713b56-283c-48c8-adae-1d21306c80ae] +description = "live cells with two live neighbors stay alive" + +[86d5c5a5-ab7b-41a1-8907-c9b3fc5e9dae] +description = "live cells with three live neighbors stay alive" + +[015f60ac-39d8-4c6c-8328-57f334fc9f89] +description = "dead cells with three live neighbors become alive" + +[2ee69c00-9d41-4b8b-89da-5832e735ccf1] +description = "live cells with four or more neighbors die" + +[a79b42be-ed6c-4e27-9206-43da08697ef6] +description = "bigger matrix" diff --git a/exercises/practice/game-of-life/game-of-life-test.el b/exercises/practice/game-of-life/game-of-life-test.el new file mode 100644 index 00000000..93efc211 --- /dev/null +++ b/exercises/practice/game-of-life/game-of-life-test.el @@ -0,0 +1,99 @@ +;;; game-of-life-test.el --- Tests for Conway's Game of Life (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "game-of-life.el") +(declare-function tick "game-of-life.el" (matrix)) + + +(ert-deftest empty-matrix () + (should (equal '() + + (tick '())))) + + +(ert-deftest live-cells-with-zero-live-neighbors-die () + (should (equal '((0 0 0) + (0 0 0) + (0 0 0)) + + (tick '((0 0 0) + (0 1 0) + (0 0 0)))))) + + +(ert-deftest live-cells-with-only-one-live-neighbor-die () + (should (equal '((0 0 0) + (0 0 0) + (0 0 0)) + + (tick '((0 0 0) + (0 1 0) + (0 1 0)))))) + + +(ert-deftest live-cells-with-two-live-neighbors-stay-alive () + (should (equal '((0 0 0) + (1 0 1) + (0 0 0)) + + (tick '((1 0 1) + (1 0 1) + (1 0 1)))))) + + +(ert-deftest live-cells-with-three-live-neighbors-stay-alive () + (should (equal '((0 0 0) + (1 0 0) + (1 1 0)) + + (tick '((0 1 0) + (1 0 0) + (1 1 0)))))) + + +(ert-deftest dead-cells-with-three-live-neighbors-become-alive () + (should (equal '((0 0 0) + (1 1 0) + (0 0 0)) + + (tick '((1 1 0) + (0 0 0) + (1 0 0)))))) + + +(ert-deftest live-cells-with-four-or-more-neighbors-die () + (should (equal '((1 0 1) + (0 0 0) + (1 0 1)) + + (tick '((1 1 1) + (1 1 1) + (1 1 1)))))) + + +(ert-deftest bigger-matrix () + (should (equal '((1 1 0 1 1 0 0 0) + (0 0 0 0 0 1 1 0) + (1 0 1 1 1 1 0 1) + (1 0 0 0 0 0 0 1) + (1 1 0 0 1 0 0 1) + (1 1 0 1 0 0 0 1) + (1 0 0 0 0 0 0 0) + (0 0 0 0 0 0 1 1)) + + (tick '((1 1 0 1 1 0 0 0) + (1 0 1 1 0 0 0 0) + (1 1 1 0 0 1 1 1) + (0 0 0 0 0 1 1 0) + (1 0 0 0 1 1 0 0) + (1 1 0 0 0 1 1 1) + (0 0 1 0 1 0 0 1) + (1 0 0 0 0 0 1 1)))))) + + +(provide 'game-of-life-test) +;;; game-of-life-test.el ends here diff --git a/exercises/practice/game-of-life/game-of-life.el b/exercises/practice/game-of-life/game-of-life.el new file mode 100644 index 00000000..57f7fb22 --- /dev/null +++ b/exercises/practice/game-of-life/game-of-life.el @@ -0,0 +1,14 @@ +;;; game-of-life.el --- Conway's Game of Life (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun tick (matrix) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'game-of-life) +;;; game-of-life.el ends here + From 32e600bf92ce24730c36421357a142a5885cf040 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 16 May 2024 15:20:43 +0200 Subject: [PATCH 090/162] Sync the `knapsack` exercise's docs with the latest data. (#389) --- .../practice/knapsack/.docs/instructions.md | 20 +++++-------------- .../practice/knapsack/.docs/introduction.md | 8 ++++++++ 2 files changed, 13 insertions(+), 15 deletions(-) create mode 100644 exercises/practice/knapsack/.docs/introduction.md diff --git a/exercises/practice/knapsack/.docs/instructions.md b/exercises/practice/knapsack/.docs/instructions.md index fadcee1b..3411db98 100644 --- a/exercises/practice/knapsack/.docs/instructions.md +++ b/exercises/practice/knapsack/.docs/instructions.md @@ -1,24 +1,15 @@ # Instructions -In this exercise, let's try to solve a classic problem. +Your task is to determine which items to take so that the total value of his selection is maximized, taking into account the knapsack's carrying capacity. -Bob is a thief. -After months of careful planning, he finally manages to crack the security systems of a high-class apartment. - -In front of him are many items, each with a value (v) and weight (w). -Bob, of course, wants to maximize the total value he can get; he would gladly take all of the items if he could. -However, to his horror, he realizes that the knapsack he carries with him can only hold so much weight (W). - -Given a knapsack with a specific carrying capacity (W), help Bob determine the maximum value he can get from the items in the house. -Note that Bob can take only one of each item. - -All values given will be strictly positive. Items will be represented as a list of items. Each item will have a weight and value. +All values given will be strictly positive. +Bob can take only one of each item. For example: -```none +```text Items: [ { "weight": 5, "value": 10 }, { "weight": 4, "value": 40 }, @@ -26,10 +17,9 @@ Items: [ { "weight": 4, "value": 50 } ] -Knapsack Limit: 10 +Knapsack Maximum Weight: 10 ``` For the above, the first item has weight 5 and value 10, the second item has weight 4 and value 40, and so on. - In this example, Bob should take the second and fourth item to maximize his value, which, in this case, is 90. He cannot get more than 90 as his knapsack has a weight limit of 10. diff --git a/exercises/practice/knapsack/.docs/introduction.md b/exercises/practice/knapsack/.docs/introduction.md new file mode 100644 index 00000000..9b2bed8b --- /dev/null +++ b/exercises/practice/knapsack/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +Bob is a thief. +After months of careful planning, he finally manages to crack the security systems of a fancy store. + +In front of him are many items, each with a value and weight. +Bob would gladly take all of the items, but his knapsack can only hold so much weight. +Bob has to carefully consider which items to take so that the total value of his selection is maximized. From 6a2c5cf9d3ce88a2dceb662c721ead416867018c Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 16 May 2024 15:22:15 +0200 Subject: [PATCH 091/162] Sync the `anagram` exercise's docs with the latest data. (#388) --- exercises/practice/anagram/.docs/instructions.md | 6 +++--- exercises/practice/anagram/.docs/introduction.md | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 exercises/practice/anagram/.docs/introduction.md diff --git a/exercises/practice/anagram/.docs/instructions.md b/exercises/practice/anagram/.docs/instructions.md index 7d1c8283..a7298485 100644 --- a/exercises/practice/anagram/.docs/instructions.md +++ b/exercises/practice/anagram/.docs/instructions.md @@ -1,9 +1,9 @@ # Instructions -An anagram is a rearrangement of letters to form a new word: for example `"owns"` is an anagram of `"snow"`. -A word is not its own anagram: for example, `"stop"` is not an anagram of `"stop"`. +Your task is to, given a target word and a set of candidate words, to find the subset of the candidates that are anagrams of the target. -Given a target word and a set of candidate words, this exercise requests the anagram set: the subset of the candidates that are anagrams of the target. +An anagram is a rearrangement of letters to form a new word: for example `"owns"` is an anagram of `"snow"`. +A word is _not_ its own anagram: for example, `"stop"` is not an anagram of `"stop"`. The target and candidates are words of one or more ASCII alphabetic characters (`A`-`Z` and `a`-`z`). Lowercase and uppercase characters are equivalent: for example, `"PoTS"` is an anagram of `"sTOp"`, but `StoP` is not an anagram of `sTOp`. diff --git a/exercises/practice/anagram/.docs/introduction.md b/exercises/practice/anagram/.docs/introduction.md new file mode 100644 index 00000000..1acbdf00 --- /dev/null +++ b/exercises/practice/anagram/.docs/introduction.md @@ -0,0 +1,12 @@ +# Introduction + +At a garage sale, you find a lovely vintage typewriter at a bargain price! +Excitedly, you rush home, insert a sheet of paper, and start typing away. +However, your excitement wanes when you examine the output: all words are garbled! +For example, it prints "stop" instead of "post" and "least" instead of "stale." +Carefully, you try again, but now it prints "spot" and "slate." +After some experimentation, you find there is a random delay before each letter is printed, which messes up the order. +You now understand why they sold it for so little money! + +You realize this quirk allows you to generate anagrams, which are words formed by rearranging the letters of another word. +Pleased with your finding, you spend the rest of the day generating hundreds of anagrams. From ff19758c1452e1e43028830878b73229e37ca73b Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 16 May 2024 15:32:43 +0200 Subject: [PATCH 092/162] Sync the `kindergarten-garden` exercise's docs with the latest data. (#390) --- .../kindergarten-garden/.docs/instructions.md | 32 +++++++++---------- .../kindergarten-garden/.docs/introduction.md | 6 ++++ 2 files changed, 21 insertions(+), 17 deletions(-) create mode 100644 exercises/practice/kindergarten-garden/.docs/introduction.md diff --git a/exercises/practice/kindergarten-garden/.docs/instructions.md b/exercises/practice/kindergarten-garden/.docs/instructions.md index 472ee26f..6fe11a58 100644 --- a/exercises/practice/kindergarten-garden/.docs/instructions.md +++ b/exercises/practice/kindergarten-garden/.docs/instructions.md @@ -1,16 +1,21 @@ # Instructions -Given a diagram, determine which plants each child in the kindergarten class is -responsible for. +Your task is to, given a diagram, determine which plants each child in the kindergarten class is responsible for. -The kindergarten class is learning about growing plants. -The teacher thought it would be a good idea to give them actual seeds, plant them in actual dirt, and grow actual plants. +There are 12 children in the class: + +- Alice, Bob, Charlie, David, Eve, Fred, Ginny, Harriet, Ileana, Joseph, Kincaid, and Larry. + +Four different types of seeds are planted: -They've chosen to grow grass, clover, radishes, and violets. +| Plant | Diagram encoding | +| ------ | ---------------- | +| Grass | G | +| Clover | C | +| Radish | R | +| Violet | V | -To this end, the children have put little cups along the window sills, and -planted one type of plant in each cup, choosing randomly from the available -types of seeds. +Each child gets four cups, two on each row: ```text [window][window][window] @@ -18,16 +23,9 @@ types of seeds. ........................ ``` -There are 12 children in the class: - -- Alice, Bob, Charlie, David, -- Eve, Fred, Ginny, Harriet, -- Ileana, Joseph, Kincaid, and Larry. - -Each child gets 4 cups, two on each row. -Their teacher assigns cups to the children alphabetically by their names. +Their teacher assigns cups to the children alphabetically by their names, which means that Alice comes first and Larry comes last. -The following diagram represents Alice's plants: +Here is an example diagram representing Alice's plants: ```text [window][window][window] diff --git a/exercises/practice/kindergarten-garden/.docs/introduction.md b/exercises/practice/kindergarten-garden/.docs/introduction.md new file mode 100644 index 00000000..5ad97d23 --- /dev/null +++ b/exercises/practice/kindergarten-garden/.docs/introduction.md @@ -0,0 +1,6 @@ +# Introduction + +The kindergarten class is learning about growing plants. +The teacher thought it would be a good idea to give the class seeds to plant and grow in the dirt. +To this end, the children have put little cups along the window sills and planted one type of plant in each cup. +The children got to pick their favorites from four available types of seeds: grass, clover, radishes, and violets. From ab39fb7cd80bf434641c108865fcbe3d3872b4ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 May 2024 18:12:18 -0700 Subject: [PATCH 093/162] Bump actions/checkout from 4.1.5 to 4.1.6 (#391) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.5 to 4.1.6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/44c2b7a8a4ea60a981eaca3cf939b5f4305c123b...a5ac7e51b41094c92402da3b24376905380afc29) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/configlet-sync.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ab34cc2..b33276f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: with: version: 28.2 - - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.0.0 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.0.0 - name: Run exercism/emacs-lisp ci (runs tests) for all exercises run: | diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index 19301c78..31117f00 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.0.0 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.0.0 - name: Fetch configlet uses: exercism/github-actions/configlet-ci@main From e89a3411984eb69138a03319795d150a7110d18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Wed, 22 May 2024 06:47:22 -0700 Subject: [PATCH 094/162] Add dnd-character (#392) --- config.json | 12 +- .../dnd-character/.docs/instructions.md | 32 ++++++ .../dnd-character/.docs/introduction.md | 10 ++ .../practice/dnd-character/.meta/config.json | 19 ++++ .../practice/dnd-character/.meta/example.el | 32 ++++++ .../practice/dnd-character/.meta/tests.toml | 74 ++++++++++++ .../dnd-character/dnd-character-test.el | 105 ++++++++++++++++++ .../practice/dnd-character/dnd-character.el | 22 ++++ 8 files changed, 304 insertions(+), 2 deletions(-) create mode 100644 exercises/practice/dnd-character/.docs/instructions.md create mode 100644 exercises/practice/dnd-character/.docs/introduction.md create mode 100644 exercises/practice/dnd-character/.meta/config.json create mode 100644 exercises/practice/dnd-character/.meta/example.el create mode 100644 exercises/practice/dnd-character/.meta/tests.toml create mode 100644 exercises/practice/dnd-character/dnd-character-test.el create mode 100644 exercises/practice/dnd-character/dnd-character.el diff --git a/config.json b/config.json index 5f9c5c3f..4491920e 100644 --- a/config.json +++ b/config.json @@ -134,6 +134,14 @@ "math" ] }, + { + "slug": "dnd-character", + "name": "D&D Character", + "uuid": "79f913e1-9571-4b1e-81f5-f0f3160898cc", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "eliuds-eggs", "name": "Eliud's Eggs", @@ -458,10 +466,10 @@ "practices": [], "prerequisites": [], "difficulty": 2, + "status": "deprecated", "topics": [ "math" - ], - "status": "deprecated" + ] }, { "slug": "two-fer", diff --git a/exercises/practice/dnd-character/.docs/instructions.md b/exercises/practice/dnd-character/.docs/instructions.md new file mode 100644 index 00000000..e14e7949 --- /dev/null +++ b/exercises/practice/dnd-character/.docs/instructions.md @@ -0,0 +1,32 @@ +# Instructions + +For a game of [Dungeons & Dragons][dnd], each player starts by generating a character they can play with. +This character has, among other things, six abilities; strength, dexterity, constitution, intelligence, wisdom and charisma. +These six abilities have scores that are determined randomly. +You do this by rolling four 6-sided dice and recording the sum of the largest three dice. +You do this six times, once for each ability. + +Your character's initial hitpoints are 10 + your character's constitution modifier. +You find your character's constitution modifier by subtracting 10 from your character's constitution, divide by 2 and round down. + +Write a random character generator that follows the above rules. + +For example, the six throws of four dice may look like: + +- 5, 3, 1, 6: You discard the 1 and sum 5 + 3 + 6 = 14, which you assign to strength. +- 3, 2, 5, 3: You discard the 2 and sum 3 + 5 + 3 = 11, which you assign to dexterity. +- 1, 1, 1, 1: You discard the 1 and sum 1 + 1 + 1 = 3, which you assign to constitution. +- 2, 1, 6, 6: You discard the 1 and sum 2 + 6 + 6 = 14, which you assign to intelligence. +- 3, 5, 3, 4: You discard the 3 and sum 5 + 3 + 4 = 12, which you assign to wisdom. +- 6, 6, 6, 6: You discard the 6 and sum 6 + 6 + 6 = 18, which you assign to charisma. + +Because constitution is 3, the constitution modifier is -4 and the hitpoints are 6. + +~~~~exercism/note +Most programming languages feature (pseudo-)random generators, but few programming languages are designed to roll dice. +One such language is [Troll][troll]. + +[troll]: https://di.ku.dk/Ansatte/?pure=da%2Fpublications%2Ftroll-a-language-for-specifying-dicerolls(84a45ff0-068b-11df-825d-000ea68e967b)%2Fexport.html +~~~~ + +[dnd]: https://en.wikipedia.org/wiki/Dungeons_%26_Dragons diff --git a/exercises/practice/dnd-character/.docs/introduction.md b/exercises/practice/dnd-character/.docs/introduction.md new file mode 100644 index 00000000..5301f618 --- /dev/null +++ b/exercises/practice/dnd-character/.docs/introduction.md @@ -0,0 +1,10 @@ +# Introduction + +After weeks of anticipation, you and your friends get together for your very first game of [Dungeons & Dragons][dnd] (D&D). +Since this is the first session of the game, each player has to generate a character to play with. +The character's abilities are determined by rolling 6-sided dice, but where _are_ the dice? +With a shock, you realize that your friends are waiting for _you_ to produce the dice; after all it was your idea to play D&D! +Panicking, you realize you forgot to bring the dice, which would mean no D&D game. +As you have some basic coding skills, you quickly come up with a solution: you'll write a program to simulate dice rolls. + +[dnd]: https://en.wikipedia.org/wiki/Dungeons_%26_Dragons diff --git a/exercises/practice/dnd-character/.meta/config.json b/exercises/practice/dnd-character/.meta/config.json new file mode 100644 index 00000000..1df1479e --- /dev/null +++ b/exercises/practice/dnd-character/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "dnd-character.el" + ], + "test": [ + "dnd-character-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Randomly generate Dungeons & Dragons characters.", + "source": "Simon Shine, Erik Schierboom", + "source_url": "https://github.com/exercism/problem-specifications/issues/616#issuecomment-437358945" +} diff --git a/exercises/practice/dnd-character/.meta/example.el b/exercises/practice/dnd-character/.meta/example.el new file mode 100644 index 00000000..5aa185ff --- /dev/null +++ b/exercises/practice/dnd-character/.meta/example.el @@ -0,0 +1,32 @@ +;;; dnd-character.el --- D&D Character (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun modifier (score) + (floor (- score 10) 2)) + + +(defun ability () + (let ((rolls '())) + (dotimes (i 4) + (push (+ 1 (random 6)) rolls)) + (apply '+ (cdr (sort rolls '<))))) + +(defun generate-dnd-character () + (let ((constitution (ability))) + (record 'dnd-character + (ability) ; strength + (ability) ; dexterity + constitution ; constitution + (ability) ; intelligence + (ability) ; wisdom + (ability) ; charisma + (+ 10 (modifier constitution))))) ; hitpoints + + +(provide 'dnd-character) +;;; dnd-character.el ends here + diff --git a/exercises/practice/dnd-character/.meta/tests.toml b/exercises/practice/dnd-character/.meta/tests.toml new file mode 100644 index 00000000..e945b5dc --- /dev/null +++ b/exercises/practice/dnd-character/.meta/tests.toml @@ -0,0 +1,74 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[1e9ae1dc-35bd-43ba-aa08-e4b94c20fa37] +description = "ability modifier -> ability modifier for score 3 is -4" + +[cc9bb24e-56b8-4e9e-989d-a0d1a29ebb9c] +description = "ability modifier -> ability modifier for score 4 is -3" + +[5b519fcd-6946-41ee-91fe-34b4f9808326] +description = "ability modifier -> ability modifier for score 5 is -3" + +[dc2913bd-6d7a-402e-b1e2-6d568b1cbe21] +description = "ability modifier -> ability modifier for score 6 is -2" + +[099440f5-0d66-4b1a-8a10-8f3a03cc499f] +description = "ability modifier -> ability modifier for score 7 is -2" + +[cfda6e5c-3489-42f0-b22b-4acb47084df0] +description = "ability modifier -> ability modifier for score 8 is -1" + +[c70f0507-fa7e-4228-8463-858bfbba1754] +description = "ability modifier -> ability modifier for score 9 is -1" + +[6f4e6c88-1cd9-46a0-92b8-db4a99b372f7] +description = "ability modifier -> ability modifier for score 10 is 0" + +[e00d9e5c-63c8-413f-879d-cd9be9697097] +description = "ability modifier -> ability modifier for score 11 is 0" + +[eea06f3c-8de0-45e7-9d9d-b8cab4179715] +description = "ability modifier -> ability modifier for score 12 is +1" + +[9c51f6be-db72-4af7-92ac-b293a02c0dcd] +description = "ability modifier -> ability modifier for score 13 is +1" + +[94053a5d-53b6-4efc-b669-a8b5098f7762] +description = "ability modifier -> ability modifier for score 14 is +2" + +[8c33e7ca-3f9f-4820-8ab3-65f2c9e2f0e2] +description = "ability modifier -> ability modifier for score 15 is +2" + +[c3ec871e-1791-44d0-b3cc-77e5fb4cd33d] +description = "ability modifier -> ability modifier for score 16 is +3" + +[3d053cee-2888-4616-b9fd-602a3b1efff4] +description = "ability modifier -> ability modifier for score 17 is +3" + +[bafd997a-e852-4e56-9f65-14b60261faee] +description = "ability modifier -> ability modifier for score 18 is +4" + +[4f28f19c-2e47-4453-a46a-c0d365259c14] +description = "random ability is within range" + +[385d7e72-864f-4e88-8279-81a7d75b04ad] +description = "random character is valid" + +[2ca77b9b-c099-46c3-a02c-0d0f68ffa0fe] +description = "each ability is only calculated once" +include = false + +[dca2b2ec-f729-4551-84b9-078876bb4808] +description = "each ability is only calculated once" +reimplements = "2ca77b9b-c099-46c3-a02c-0d0f68ffa0fe" +include = false + diff --git a/exercises/practice/dnd-character/dnd-character-test.el b/exercises/practice/dnd-character/dnd-character-test.el new file mode 100644 index 00000000..3cea20e4 --- /dev/null +++ b/exercises/practice/dnd-character/dnd-character-test.el @@ -0,0 +1,105 @@ +;;; dnd-character-test.el --- D&D Character (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "dnd-character.el") +(declare-function modifier "dnd-character.el" (score)) +(declare-function ability "dnd-character.el" ()) +(declare-function generate-dnd-character "dnd-character.el" ()) + + +(ert-deftest ability-modifier-for-score-3-is-negative-4 () + (should (= -4 (modifier 3)))) + + +(ert-deftest ability-modifier-for-score-4-is-negative-3 () + (should (= -3 (modifier 4)))) + + +(ert-deftest ability-modifier-for-score-5-is-negative-3 () + (should (= -3 (modifier 5)))) + + +(ert-deftest ability-modifier-for-score-6-is-negative-2 () + (should (= -2 (modifier 6)))) + + +(ert-deftest ability-modifier-for-score-7-is-negative-2 () + (should (= -2 (modifier 7)))) + + +(ert-deftest ability-modifier-for-score-8-is-negative-1 () + (should (= -1 (modifier 8)))) + + +(ert-deftest ability-modifier-for-score-9-is-negative-1 () + (should (= -1 (modifier 9)))) + + +(ert-deftest ability-modifier-for-score-10-is-0 () + (should (= 0 (modifier 10)))) + + +(ert-deftest ability-modifier-for-score-11-is-0 () + (should (= 0 (modifier 11)))) + + +(ert-deftest ability-modifier-for-score-12-is-positive-1 () + (should (= 1 (modifier 12)))) + + +(ert-deftest ability-modifier-for-score-13-is-positive-1 () + (should (= 1 (modifier 13)))) + + +(ert-deftest ability-modifier-for-score-14-is-positive-2 () + (should (= 2 (modifier 14)))) + + +(ert-deftest ability-modifier-for-score-15-is-positive-2 () + (should (= 2 (modifier 15)))) + + +(ert-deftest ability-modifier-for-score-16-is-positive-3 () + (should (= 3 (modifier 16)))) + + +(ert-deftest ability-modifier-for-score-17-is-positive-3 () + (should (= 3 (modifier 17)))) + + +(ert-deftest ability-modifier-for-score-18-is-positive-4 () + (should (= 4 (modifier 18)))) + + +(defun valid-range-p (score) + (and (<= 3 score) (>= 18 score))) + +(ert-deftest random-ability-is-within-range () + (should (valid-range-p (ability)))) + + +(ert-deftest random-character-is-valid () + (let* ((dnd-char (generate-dnd-character)) + (strength (aref dnd-char 1)) + (dexterity (aref dnd-char 2)) + (constitution (aref dnd-char 3)) + (intelligence (aref dnd-char 4)) + (wisdom (aref dnd-char 5)) + (charisma (aref dnd-char 6)) + (hitpoints (aref dnd-char 7))) + (should (and (recordp dnd-char) + (valid-range-p strength) + (valid-range-p dexterity) + (valid-range-p constitution) + (valid-range-p intelligence) + (valid-range-p wisdom) + (valid-range-p charisma))))) + + +(provide 'dnd-character-test) +;;; dnd-character-test.el ends here + diff --git a/exercises/practice/dnd-character/dnd-character.el b/exercises/practice/dnd-character/dnd-character.el new file mode 100644 index 00000000..ee4ce8fa --- /dev/null +++ b/exercises/practice/dnd-character/dnd-character.el @@ -0,0 +1,22 @@ +;;; dnd-character.el --- D&D Character (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun modifier (score) + (error "Delete this S-Expression and write your own implementation")) + + +(defun ability () + (error "Delete this S-Expression and write your own implementation")) + + +(defun generate-dnd-character () + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'dnd-character) +;;; dnd-character.el ends here + From 17b0420abdb7a528e04eb48b3e7265ad2babfe1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Thu, 23 May 2024 06:41:16 -0700 Subject: [PATCH 095/162] Add robot simulator (#393) --- config.json | 8 ++ .../robot-simulator/.docs/instructions.md | 25 +++++ .../robot-simulator/.meta/config.json | 18 +++ .../practice/robot-simulator/.meta/example.el | 48 ++++++++ .../practice/robot-simulator/.meta/tests.toml | 64 +++++++++++ .../robot-simulator/robot-simulator-test.el | 104 ++++++++++++++++++ .../robot-simulator/robot-simulator.el | 17 +++ 7 files changed, 284 insertions(+) create mode 100644 exercises/practice/robot-simulator/.docs/instructions.md create mode 100644 exercises/practice/robot-simulator/.meta/config.json create mode 100644 exercises/practice/robot-simulator/.meta/example.el create mode 100644 exercises/practice/robot-simulator/.meta/tests.toml create mode 100644 exercises/practice/robot-simulator/robot-simulator-test.el create mode 100644 exercises/practice/robot-simulator/robot-simulator.el diff --git a/config.json b/config.json index 4491920e..5d9d873a 100644 --- a/config.json +++ b/config.json @@ -308,6 +308,14 @@ "prerequisites": [], "difficulty": 2 }, + { + "slug": "robot-simulator", + "name": "Robot Simulator", + "uuid": "575a40bd-2ff9-4623-ae98-c8d9b9f279a8", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "rna-transcription", "name": "RNA Transcription", diff --git a/exercises/practice/robot-simulator/.docs/instructions.md b/exercises/practice/robot-simulator/.docs/instructions.md new file mode 100644 index 00000000..0ac96ce0 --- /dev/null +++ b/exercises/practice/robot-simulator/.docs/instructions.md @@ -0,0 +1,25 @@ +# Instructions + +Write a robot simulator. + +A robot factory's test facility needs a program to verify robot movements. + +The robots have three possible movements: + +- turn right +- turn left +- advance + +Robots are placed on a hypothetical infinite grid, facing a particular direction (north, east, south, or west) at a set of {x,y} coordinates, +e.g., {3,8}, with coordinates increasing to the north and east. + +The robot then receives a number of instructions, at which point the testing facility verifies the robot's new position, and in which direction it is pointing. + +- The letter-string "RAALAL" means: + - Turn right + - Advance twice + - Turn left + - Advance once + - Turn left yet again +- Say a robot starts at {7, 3} facing north. + Then running this stream of instructions should leave it at {9, 4} facing west. diff --git a/exercises/practice/robot-simulator/.meta/config.json b/exercises/practice/robot-simulator/.meta/config.json new file mode 100644 index 00000000..a5ce9004 --- /dev/null +++ b/exercises/practice/robot-simulator/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "robot-simulator.el" + ], + "test": [ + "robot-simulator-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Write a robot simulator.", + "source": "Inspired by an interview question at a famous company." +} diff --git a/exercises/practice/robot-simulator/.meta/example.el b/exercises/practice/robot-simulator/.meta/example.el new file mode 100644 index 00000000..0cc1c767 --- /dev/null +++ b/exercises/practice/robot-simulator/.meta/example.el @@ -0,0 +1,48 @@ +;;; robot-simulator.el --- robot-simulator Exercise (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defconst directions [north east south west]) + + +(defconst steps '((north . (0 1)) + (east . (1 0)) + (south . (0 -1)) + (west . (-1 0)))) + + +(defun create-robot (x y direction) + (record 'robot x y direction)) + + +(defun move (robot instructions) + (let ((state robot)) + (seq-doseq (instruction instructions) + (cond ((equal ?L instruction) + (rotate state -1)) + ((equal ?R instruction) + (rotate state 1)) + ((equal ?A instruction) + (advance state)))) + state)) + + +(defun rotate (robot offset) + (let* ((old-index (cl-position (aref robot 3) directions)) + (new-index (mod (+ old-index offset) 4))) + (aset robot 3 (aref directions new-index)))) + + +(defun advance (robot) + (let* ((delta (assq (aref robot 3) steps)) + (delta-x (cadr delta)) + (delta-y (caddr delta))) + (aset robot 1 (+ delta-x (aref robot 1))) + (aset robot 2 (+ delta-y (aref robot 2))))) + + +(provide 'robot-simulator) +;;; robot-simulator.el ends here diff --git a/exercises/practice/robot-simulator/.meta/tests.toml b/exercises/practice/robot-simulator/.meta/tests.toml new file mode 100644 index 00000000..16da03d4 --- /dev/null +++ b/exercises/practice/robot-simulator/.meta/tests.toml @@ -0,0 +1,64 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[c557c16d-26c1-4e06-827c-f6602cd0785c] +description = "Create robot -> at origin facing north" + +[bf0dffce-f11c-4cdb-8a5e-2c89d8a5a67d] +description = "Create robot -> at negative position facing south" + +[8cbd0086-6392-4680-b9b9-73cf491e67e5] +description = "Rotating clockwise -> changes north to east" + +[8abc87fc-eab2-4276-93b7-9c009e866ba1] +description = "Rotating clockwise -> changes east to south" + +[3cfe1b85-bbf2-4bae-b54d-d73e7e93617a] +description = "Rotating clockwise -> changes south to west" + +[5ea9fb99-3f2c-47bd-86f7-46b7d8c3c716] +description = "Rotating clockwise -> changes west to north" + +[fa0c40f5-6ba3-443d-a4b3-58cbd6cb8d63] +description = "Rotating counter-clockwise -> changes north to west" + +[da33d734-831f-445c-9907-d66d7d2a92e2] +description = "Rotating counter-clockwise -> changes west to south" + +[bd1ca4b9-4548-45f4-b32e-900fc7c19389] +description = "Rotating counter-clockwise -> changes south to east" + +[2de27b67-a25c-4b59-9883-bc03b1b55bba] +description = "Rotating counter-clockwise -> changes east to north" + +[f0dc2388-cddc-4f83-9bed-bcf46b8fc7b8] +description = "Moving forward one -> facing north increments Y" + +[2786cf80-5bbf-44b0-9503-a89a9c5789da] +description = "Moving forward one -> facing south decrements Y" + +[84bf3c8c-241f-434d-883d-69817dbd6a48] +description = "Moving forward one -> facing east increments X" + +[bb69c4a7-3bbf-4f64-b415-666fa72d7b04] +description = "Moving forward one -> facing west decrements X" + +[e34ac672-4ed4-4be3-a0b8-d9af259cbaa1] +description = "Follow series of instructions -> moving east and north from README" + +[f30e4955-4b47-4aa3-8b39-ae98cfbd515b] +description = "Follow series of instructions -> moving west and north" + +[3e466bf6-20ab-4d79-8b51-264165182fca] +description = "Follow series of instructions -> moving west and south" + +[41f0bb96-c617-4e6b-acff-a4b279d44514] +description = "Follow series of instructions -> moving east and north" diff --git a/exercises/practice/robot-simulator/robot-simulator-test.el b/exercises/practice/robot-simulator/robot-simulator-test.el new file mode 100644 index 00000000..022a89d2 --- /dev/null +++ b/exercises/practice/robot-simulator/robot-simulator-test.el @@ -0,0 +1,104 @@ +;;; robot-simulator-test.el --- Tests for robot-simulator (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "robot-simulator.el") +(declare-function create-robot "robot-simulator.el" (x y direction)) +(declare-function move "robot-simulator.el" (robot instructions)) + + +(ert-deftest create-robot-at-origin-facing-north () + (should (equal #s(robot 0 0 north) + (create-robot 0 0 'north)))) + + +(ert-deftest create-robot-at-negative-position-facing-south () + (should (equal #s(robot -1 -1 south) + (create-robot -1 -1 'south)))) + + +(ert-deftest rotating-clockwise-changes-north-to-east () + (should (equal #s(robot 0 0 east) + (move (create-robot 0 0 'north) "R")))) + + +(ert-deftest rotating-clockwise-changes-east-to-south () + (should (equal #s(robot 0 0 south) + (move (create-robot 0 0 'east) "R")))) + + +(ert-deftest rotating-clockwise-changes-south-to-west () + (should (equal #s(robot 0 0 west) + (move (create-robot 0 0 'south) "R")))) + + +(ert-deftest rotating-clockwise-changes-west-to-north () + (should (equal #s(robot 0 0 north) + (move (create-robot 0 0 'west) "R")))) + + +(ert-deftest rotating-counter-clockwise-changes-north-to-west () + (should (equal #s(robot 0 0 west) + (move (create-robot 0 0 'north) "L")))) + + +(ert-deftest rotating-counter-clockwise-changes-west-to-south () + (should (equal #s(robot 0 0 south) + (move (create-robot 0 0 'west) "L")))) + + +(ert-deftest rotating-counter-clockwise-changes-south-to-east () + (should (equal #s(robot 0 0 east) + (move (create-robot 0 0 'south) "L")))) + + +(ert-deftest rotating-counter-clockwise-changes-east-to-north () + (should (equal #s(robot 0 0 north) + (move (create-robot 0 0 'east) "L")))) + + +(ert-deftest moving-forward-one-facing-north-increments-y () + (should (equal #s(robot 0 1 north) + (move (create-robot 0 0 'north) "A")))) + + +(ert-deftest moving-forward-one-facing-south-decrements-y () + (should (equal #s(robot 0 -1 south) + (move (create-robot 0 0 'south) "A")))) + + +(ert-deftest moving-forward-one-facing-east-increments-x () + (should (equal #s(robot 1 0 east) + (move (create-robot 0 0 'east) "A")))) + + +(ert-deftest moving-forward-one-facing-west-decrements-x () + (should (equal #s(robot -1 0 west) + (move (create-robot 0 0 'west) "A")))) + + +(ert-deftest follow-series-of-instructions-moving-east-and-north-from-README () + (should (equal #s(robot 9 4 west) + (move (create-robot 7 3 'north) "RAALAL")))) + + +(ert-deftest follow-series-of-instructions-moving-west-and-north () + (should (equal #s(robot -4 1 west) + (move (create-robot 0 0 'north) "LAAARALA")))) + + +(ert-deftest follow-series-of-instructions-moving-west-and-south () + (should (equal #s(robot -3 -8 south) + (move (create-robot 2 -7 'east) "RRAAAAALA")))) + + +(ert-deftest follow-series-of-instructions-moving-east-and-north () + (should (equal #s(robot 11 5 north) + (move (create-robot 8 4 'south) "LAAARRRALLLL")))) + + +(provide 'robot-simulator-test) +;;; robot-simulator-test.el ends here diff --git a/exercises/practice/robot-simulator/robot-simulator.el b/exercises/practice/robot-simulator/robot-simulator.el new file mode 100644 index 00000000..18e308f2 --- /dev/null +++ b/exercises/practice/robot-simulator/robot-simulator.el @@ -0,0 +1,17 @@ +;;; robot-simulator.el --- robot-simulator (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun create-robot (x y direction) + (error "Delete this S-Expression and write your own implementation")) + + +(defun move (robot instructions) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'robot-simulator) +;;; robot-simulator.el ends here From 7c61f7623c17b6c2698a19bb348f5fbb729a6b64 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Mon, 3 Jun 2024 04:40:02 +1000 Subject: [PATCH 096/162] Add spiral-matrix exercise (#394) --- config.json | 8 ++++ .../spiral-matrix/.docs/instructions.md | 24 ++++++++++ .../practice/spiral-matrix/.meta/config.json | 19 ++++++++ .../practice/spiral-matrix/.meta/example.el | 41 ++++++++++++++++ .../practice/spiral-matrix/.meta/tests.toml | 28 +++++++++++ .../spiral-matrix/spiral-matrix-test.el | 47 +++++++++++++++++++ .../practice/spiral-matrix/spiral-matrix.el | 14 ++++++ 7 files changed, 181 insertions(+) create mode 100644 exercises/practice/spiral-matrix/.docs/instructions.md create mode 100644 exercises/practice/spiral-matrix/.meta/config.json create mode 100644 exercises/practice/spiral-matrix/.meta/example.el create mode 100644 exercises/practice/spiral-matrix/.meta/tests.toml create mode 100644 exercises/practice/spiral-matrix/spiral-matrix-test.el create mode 100644 exercises/practice/spiral-matrix/spiral-matrix.el diff --git a/config.json b/config.json index 5d9d873a..60a7a381 100644 --- a/config.json +++ b/config.json @@ -731,6 +731,14 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "spiral-matrix", + "name": "Spiral Matrix", + "uuid": "4ce2b869-140a-4d5d-90dd-6fc717ef7696", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, { "slug": "word-count", "name": "Word Count", diff --git a/exercises/practice/spiral-matrix/.docs/instructions.md b/exercises/practice/spiral-matrix/.docs/instructions.md new file mode 100644 index 00000000..ba99e12c --- /dev/null +++ b/exercises/practice/spiral-matrix/.docs/instructions.md @@ -0,0 +1,24 @@ +# Instructions + +Given the size, return a square matrix of numbers in spiral order. + +The matrix should be filled with natural numbers, starting from 1 in the top-left corner, increasing in an inward, clockwise spiral order, like these examples: + +## Examples + +### Spiral matrix of size 3 + +```text +1 2 3 +8 9 4 +7 6 5 +``` + +### Spiral matrix of size 4 + +```text + 1 2 3 4 +12 13 14 5 +11 16 15 6 +10 9 8 7 +``` diff --git a/exercises/practice/spiral-matrix/.meta/config.json b/exercises/practice/spiral-matrix/.meta/config.json new file mode 100644 index 00000000..20a3b7fb --- /dev/null +++ b/exercises/practice/spiral-matrix/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "spiral-matrix.el" + ], + "test": [ + "spiral-matrix-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given the size, return a square matrix of numbers in spiral order.", + "source": "Reddit r/dailyprogrammer challenge #320 [Easy] Spiral Ascension.", + "source_url": "https://web.archive.org/web/20230607064729/https://old.reddit.com/r/dailyprogrammer/comments/6i60lr/20170619_challenge_320_easy_spiral_ascension/" +} diff --git a/exercises/practice/spiral-matrix/.meta/example.el b/exercises/practice/spiral-matrix/.meta/example.el new file mode 100644 index 00000000..dfd6ddc9 --- /dev/null +++ b/exercises/practice/spiral-matrix/.meta/example.el @@ -0,0 +1,41 @@ +;;; spiral-matrix.el --- Spiral Matrix (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun spiral-matrix (size) + (let* ((result (make-vector size nil)) + (value 1) + (row 0) + (column 0) + (side (1- size))) + (cl-loop for r below size + do (aset result r (make-vector size (* size size)))) + (while (>= side 1) + (cl-loop repeat side + do (aset (aref result row) column value) + do (setq value (1+ value)) + do (setq column (1+ column))) + (cl-loop repeat side + do (aset (aref result row) column value) + do (setq value (1+ value)) + do (setq row (1+ row))) + (cl-loop repeat side + do (aset (aref result row) column value) + do (setq value (1+ value)) + do (setq column (1- column))) + (cl-loop repeat side + do (aset (aref result row) column value) + do (setq value (1+ value)) + do (setq row (1- row))) + (setq row (1+ row)) + (setq column (1+ column)) + (setq side (- side 2))) + result)) + +(provide 'spiral-matrix) +;;; spiral-matrix.el ends here + diff --git a/exercises/practice/spiral-matrix/.meta/tests.toml b/exercises/practice/spiral-matrix/.meta/tests.toml new file mode 100644 index 00000000..9ac5baca --- /dev/null +++ b/exercises/practice/spiral-matrix/.meta/tests.toml @@ -0,0 +1,28 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[8f584201-b446-4bc9-b132-811c8edd9040] +description = "empty spiral" + +[e40ae5f3-e2c9-4639-8116-8a119d632ab2] +description = "trivial spiral" + +[cf05e42d-eb78-4098-a36e-cdaf0991bc48] +description = "spiral of size 2" + +[1c475667-c896-4c23-82e2-e033929de939] +description = "spiral of size 3" + +[05ccbc48-d891-44f5-9137-f4ce462a759d] +description = "spiral of size 4" + +[f4d2165b-1738-4e0c-bed0-c459045ae50d] +description = "spiral of size 5" diff --git a/exercises/practice/spiral-matrix/spiral-matrix-test.el b/exercises/practice/spiral-matrix/spiral-matrix-test.el new file mode 100644 index 00000000..ee9f6fd5 --- /dev/null +++ b/exercises/practice/spiral-matrix/spiral-matrix-test.el @@ -0,0 +1,47 @@ +;;; spiral-matrix-test.el --- Tests for Spiral Matrix (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "spiral-matrix.el") +(declare-function spiral-matrix "spiral-matrix.el" (size)) + + +(ert-deftest empty-spiral () + (should (equal [] (spiral-matrix 0)))) + + +(ert-deftest trivial-spiral () + (should (equal [[1]] (spiral-matrix 1)))) + + +(ert-deftest spiral-of-size-2 () + (should (equal [[1 2] + [4 3]] (spiral-matrix 2)))) + + +(ert-deftest spiral-of-size-3 () + (should (equal [[1 2 3] + [8 9 4] + [7 6 5]] (spiral-matrix 3)))) + + +(ert-deftest spiral-of-size-4 () + (should (equal [[1 2 3 4] + [12 13 14 5] + [11 16 15 6] + [10 9 8 7]] (spiral-matrix 4)))) + + +(ert-deftest spiral-of-size-5 () + (should (equal [[1 2 3 4 5] + [16 17 18 19 6] + [15 24 25 20 7] + [14 23 22 21 8] + [13 12 11 10 9]] (spiral-matrix 5)))) + + +(provide 'spiral-matrix-test) +;;; spiral-matrix-test.el ends here diff --git a/exercises/practice/spiral-matrix/spiral-matrix.el b/exercises/practice/spiral-matrix/spiral-matrix.el new file mode 100644 index 00000000..efefe513 --- /dev/null +++ b/exercises/practice/spiral-matrix/spiral-matrix.el @@ -0,0 +1,14 @@ +;;; spiral-matrix.el --- Spiral Matrix (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun spiral-matrix (size) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'spiral-matrix) +;;; spiral-matrix.el ends here + From 3ba948b5c9e464ce3f33ce0a4e10452e7f9baa73 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Mon, 3 Jun 2024 04:42:19 +1000 Subject: [PATCH 097/162] Add diamond exercise (#396) --- config.json | 8 ++ .../practice/diamond/.docs/instructions.md | 52 ++++++++++ exercises/practice/diamond/.meta/config.json | 19 ++++ exercises/practice/diamond/.meta/example.el | 27 ++++++ exercises/practice/diamond/.meta/tests.toml | 25 +++++ exercises/practice/diamond/diamond-test.el | 95 +++++++++++++++++++ exercises/practice/diamond/diamond.el | 14 +++ 7 files changed, 240 insertions(+) create mode 100644 exercises/practice/diamond/.docs/instructions.md create mode 100644 exercises/practice/diamond/.meta/config.json create mode 100644 exercises/practice/diamond/.meta/example.el create mode 100644 exercises/practice/diamond/.meta/tests.toml create mode 100644 exercises/practice/diamond/diamond-test.el create mode 100644 exercises/practice/diamond/diamond.el diff --git a/config.json b/config.json index 60a7a381..9c73604e 100644 --- a/config.json +++ b/config.json @@ -535,6 +535,14 @@ "math" ] }, + { + "slug": "diamond", + "name": "Diamond", + "uuid": "312bff7d-34f4-4ade-bbd3-479bce9bff58", + "practices": [], + "prerequisites": [], + "difficulty": 4 + }, { "slug": "largest-series-product", "name": "Largest Series Product", diff --git a/exercises/practice/diamond/.docs/instructions.md b/exercises/practice/diamond/.docs/instructions.md new file mode 100644 index 00000000..3034802f --- /dev/null +++ b/exercises/practice/diamond/.docs/instructions.md @@ -0,0 +1,52 @@ +# Instructions + +The diamond kata takes as its input a letter, and outputs it in a diamond shape. +Given a letter, it prints a diamond starting with 'A', with the supplied letter at the widest point. + +## Requirements + +- The first row contains one 'A'. +- The last row contains one 'A'. +- All rows, except the first and last, have exactly two identical letters. +- All rows have as many trailing spaces as leading spaces. (This might be 0). +- The diamond is horizontally symmetric. +- The diamond is vertically symmetric. +- The diamond has a square shape (width equals height). +- The letters form a diamond shape. +- The top half has the letters in ascending order. +- The bottom half has the letters in descending order. +- The four corners (containing the spaces) are triangles. + +## Examples + +In the following examples, spaces are indicated by `·` characters. + +Diamond for letter 'A': + +```text +A +``` + +Diamond for letter 'C': + +```text +··A·· +·B·B· +C···C +·B·B· +··A·· +``` + +Diamond for letter 'E': + +```text +····A···· +···B·B··· +··C···C·· +·D·····D· +E·······E +·D·····D· +··C···C·· +···B·B··· +····A···· +``` diff --git a/exercises/practice/diamond/.meta/config.json b/exercises/practice/diamond/.meta/config.json new file mode 100644 index 00000000..a60c3eb4 --- /dev/null +++ b/exercises/practice/diamond/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "diamond.el" + ], + "test": [ + "diamond-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given a letter, print a diamond starting with 'A' with the supplied letter at the widest point.", + "source": "Seb Rose", + "source_url": "https://web.archive.org/web/20220807163751/http://claysnow.co.uk/recycling-tests-in-tdd/" +} diff --git a/exercises/practice/diamond/.meta/example.el b/exercises/practice/diamond/.meta/example.el new file mode 100644 index 00000000..2088c9e0 --- /dev/null +++ b/exercises/practice/diamond/.meta/example.el @@ -0,0 +1,27 @@ +;;; diamond.el --- Diamond (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun rows (letter) + (let* ((n (- letter ?A)) + (length (1+ (* 2 n))) + (result (make-vector length nil))) + (cl-labels + ((row (index) + (let ((str (make-string length 32))) + (aset str (- n index) (+ ?A index)) + (aset str (+ n index) (+ ?A index)) + str))) + (cl-loop for index to n + do (aset result index (funcall #'row index))) + (cl-loop for index below n + do (aset result (- length 1 index) (funcall #'row index))) + result))) + +(provide 'diamond) +;;; diamond.el ends here + diff --git a/exercises/practice/diamond/.meta/tests.toml b/exercises/practice/diamond/.meta/tests.toml new file mode 100644 index 00000000..4e7802ec --- /dev/null +++ b/exercises/practice/diamond/.meta/tests.toml @@ -0,0 +1,25 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[202fb4cc-6a38-4883-9193-a29d5cb92076] +description = "Degenerate case with a single 'A' row" + +[bd6a6d78-9302-42e9-8f60-ac1461e9abae] +description = "Degenerate case with no row containing 3 distinct groups of spaces" + +[af8efb49-14ed-447f-8944-4cc59ce3fd76] +description = "Smallest non-degenerate case with odd diamond side length" + +[e0c19a95-9888-4d05-86a0-fa81b9e70d1d] +description = "Smallest non-degenerate case with even diamond side length" + +[82ea9aa9-4c0e-442a-b07e-40204e925944] +description = "Largest possible diamond" diff --git a/exercises/practice/diamond/diamond-test.el b/exercises/practice/diamond/diamond-test.el new file mode 100644 index 00000000..3dc7adf2 --- /dev/null +++ b/exercises/practice/diamond/diamond-test.el @@ -0,0 +1,95 @@ +;;; diamond-test.el --- Tests for Diamond (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "diamond.el") +(declare-function rows "diamond.el" (letter)) + + +(ert-deftest degenerate-case-with-a-single-a-row () + (should (equal ["A"] (rows ?A)))) + + +(ert-deftest degenerate-case-with-no-row-containing-3-distinct-groups-of-spaces () + (should (equal [" A " + "B B" + " A "] (rows ?B)))) + + +(ert-deftest smallest-non-degenerate-case-with-odd-diamond-side-length () + (should (equal [" A " + " B B " + "C C" + " B B " + " A "] (rows ?C)))) + + +(ert-deftest smallest-non-degenerate-case-with-even-diamond-side-length () + (should (equal [" A " + " B B " + " C C " + "D D" + " C C " + " B B " + " A "] (rows ?D)))) + + +(ert-deftest largest-possible-diamond () + (should (equal [" A " + " B B " + " C C " + " D D " + " E E " + " F F " + " G G " + " H H " + " I I " + " J J " + " K K " + " L L " + " M M " + " N N " + " O O " + " P P " + " Q Q " + " R R " + " S S " + " T T " + " U U " + " V V " + " W W " + " X X " + " Y Y " + "Z Z" + " Y Y " + " X X " + " W W " + " V V " + " U U " + " T T " + " S S " + " R R " + " Q Q " + " P P " + " O O " + " N N " + " M M " + " L L " + " K K " + " J J " + " I I " + " H H " + " G G " + " F F " + " E E " + " D D " + " C C " + " B B " + " A "] (rows ?Z)))) + + +(provide 'diamond-test) +;;; diamond-test.el ends here diff --git a/exercises/practice/diamond/diamond.el b/exercises/practice/diamond/diamond.el new file mode 100644 index 00000000..d04eee02 --- /dev/null +++ b/exercises/practice/diamond/diamond.el @@ -0,0 +1,14 @@ +;;; diamond.el --- Diamond (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun rows (letter) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'diamond) +;;; diamond.el ends here + From 53d7c1cff77a10e9913fabc2023b93dbf2cb1e80 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Mon, 3 Jun 2024 04:43:18 +1000 Subject: [PATCH 098/162] Add pascals-triangle exercise (#395) --- config.json | 11 +++ .../pascals-triangle/.docs/instructions.md | 14 ++++ .../pascals-triangle/.meta/config.json | 19 +++++ .../pascals-triangle/.meta/example.el | 23 +++++++ .../pascals-triangle/.meta/tests.toml | 34 +++++++++ .../pascals-triangle/pascals-triangle-test.el | 69 +++++++++++++++++++ .../pascals-triangle/pascals-triangle.el | 14 ++++ 7 files changed, 184 insertions(+) create mode 100644 exercises/practice/pascals-triangle/.docs/instructions.md create mode 100644 exercises/practice/pascals-triangle/.meta/config.json create mode 100644 exercises/practice/pascals-triangle/.meta/example.el create mode 100644 exercises/practice/pascals-triangle/.meta/tests.toml create mode 100644 exercises/practice/pascals-triangle/pascals-triangle-test.el create mode 100644 exercises/practice/pascals-triangle/pascals-triangle.el diff --git a/config.json b/config.json index 9c73604e..36a93ae6 100644 --- a/config.json +++ b/config.json @@ -566,6 +566,17 @@ "math" ] }, + { + "slug": "pascals-triangle", + "name": "Pascal's Triangle", + "uuid": "cc71a6d5-efb2-4054-bf72-102b3e96e0bc", + "practices": [], + "prerequisites": [], + "difficulty": 4, + "topics": [ + "math" + ] + }, { "slug": "affine-cipher", "name": "Affine Cipher", diff --git a/exercises/practice/pascals-triangle/.docs/instructions.md b/exercises/practice/pascals-triangle/.docs/instructions.md new file mode 100644 index 00000000..f5567859 --- /dev/null +++ b/exercises/practice/pascals-triangle/.docs/instructions.md @@ -0,0 +1,14 @@ +# Instructions + +Compute Pascal's triangle up to a given number of rows. + +In Pascal's Triangle each number is computed by adding the numbers to the right and left of the current position in the previous row. + +```text + 1 + 1 1 + 1 2 1 + 1 3 3 1 +1 4 6 4 1 +# ... etc +``` diff --git a/exercises/practice/pascals-triangle/.meta/config.json b/exercises/practice/pascals-triangle/.meta/config.json new file mode 100644 index 00000000..ce634d22 --- /dev/null +++ b/exercises/practice/pascals-triangle/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "pascals-triangle.el" + ], + "test": [ + "pascals-triangle-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Compute Pascal's triangle up to a given number of rows.", + "source": "Pascal's Triangle at Wolfram Math World", + "source_url": "https://www.wolframalpha.com/input/?i=Pascal%27s+triangle" +} diff --git a/exercises/practice/pascals-triangle/.meta/example.el b/exercises/practice/pascals-triangle/.meta/example.el new file mode 100644 index 00000000..8e0afc2f --- /dev/null +++ b/exercises/practice/pascals-triangle/.meta/example.el @@ -0,0 +1,23 @@ +;;; pascals-triangle.el --- Pascal's Triangle (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun rows (count) + (let ((result (make-vector count nil)) + (current nil) + (previous nil)) + (cl-loop for r below count + do (setq current (make-vector (1+ r) 1)) + do (cl-loop for c from 1 below r + do (aset current c (+ (aref previous (1- c)) (aref previous c)))) + do (aset result r current) + do (setq previous current)) + result)) + +(provide 'pascals-triangle) +;;; pascals-triangle.el ends here + diff --git a/exercises/practice/pascals-triangle/.meta/tests.toml b/exercises/practice/pascals-triangle/.meta/tests.toml new file mode 100644 index 00000000..2db0ee52 --- /dev/null +++ b/exercises/practice/pascals-triangle/.meta/tests.toml @@ -0,0 +1,34 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[9920ce55-9629-46d5-85d6-4201f4a4234d] +description = "zero rows" + +[70d643ce-a46d-4e93-af58-12d88dd01f21] +description = "single row" + +[a6e5a2a2-fc9a-4b47-9f4f-ed9ad9fbe4bd] +description = "two rows" + +[97206a99-79ba-4b04-b1c5-3c0fa1e16925] +description = "three rows" + +[565a0431-c797-417c-a2c8-2935e01ce306] +description = "four rows" + +[06f9ea50-9f51-4eb2-b9a9-c00975686c27] +description = "five rows" + +[c3912965-ddb4-46a9-848e-3363e6b00b13] +description = "six rows" + +[6cb26c66-7b57-4161-962c-81ec8c99f16b] +description = "ten rows" diff --git a/exercises/practice/pascals-triangle/pascals-triangle-test.el b/exercises/practice/pascals-triangle/pascals-triangle-test.el new file mode 100644 index 00000000..969d987b --- /dev/null +++ b/exercises/practice/pascals-triangle/pascals-triangle-test.el @@ -0,0 +1,69 @@ +;;; pascals-triangle-test.el --- Tests for Pascal's Triangle (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "pascals-triangle.el") +(declare-function rows "pascals-triangle.el" (count)) + + +(ert-deftest zero-rows () + (should (equal [] (rows 0)))) + + +(ert-deftest single-row () + (should (equal [[1]] (rows 1)))) + + +(ert-deftest two-rows () + (should (equal [[1] + [1 1]] (rows 2)))) + + +(ert-deftest three-rows () + (should (equal [[1] + [1 1] + [1 2 1]] (rows 3)))) + + +(ert-deftest four-rows () + (should (equal [[1] + [1 1] + [1 2 1] + [1 3 3 1]] (rows 4)))) + + +(ert-deftest five-rows () + (should (equal [[1] + [1 1] + [1 2 1] + [1 3 3 1] + [1 4 6 4 1]] (rows 5)))) + + +(ert-deftest six-rows () + (should (equal [[1] + [1 1] + [1 2 1] + [1 3 3 1] + [1 4 6 4 1] + [1 5 10 10 5 1]] (rows 6)))) + + +(ert-deftest ten-rows () + (should (equal [[1] + [1 1] + [1 2 1] + [1 3 3 1] + [1 4 6 4 1] + [1 5 10 10 5 1] + [1 6 15 20 15 6 1] + [1 7 21 35 35 21 7 1] + [1 8 28 56 70 56 28 8 1] + [1 9 36 84 126 126 84 36 9 1]] (rows 10)))) + + +(provide 'pascals-triangle-test) +;;; pascals-triangle-test.el ends here diff --git a/exercises/practice/pascals-triangle/pascals-triangle.el b/exercises/practice/pascals-triangle/pascals-triangle.el new file mode 100644 index 00000000..9fd2baab --- /dev/null +++ b/exercises/practice/pascals-triangle/pascals-triangle.el @@ -0,0 +1,14 @@ +;;; pascals-triangle.el --- Pascal's Triangle (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun rows (count) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'pascals-triangle) +;;; pascals-triangle.el ends here + From 8a297c3baf3d681f8513b26cc08ec8715671c383 Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Tue, 4 Jun 2024 04:34:23 +1000 Subject: [PATCH 099/162] Add secret-handshake exercise (#397) --- config.json | 8 +++ .../secret-handshake/.docs/instructions.md | 48 ++++++++++++++++ .../secret-handshake/.docs/introduction.md | 7 +++ .../secret-handshake/.meta/config.json | 19 +++++++ .../secret-handshake/.meta/example.el | 26 +++++++++ .../secret-handshake/.meta/tests.toml | 43 ++++++++++++++ .../secret-handshake/secret-handshake-test.el | 57 +++++++++++++++++++ .../secret-handshake/secret-handshake.el | 14 +++++ 8 files changed, 222 insertions(+) create mode 100644 exercises/practice/secret-handshake/.docs/instructions.md create mode 100644 exercises/practice/secret-handshake/.docs/introduction.md create mode 100644 exercises/practice/secret-handshake/.meta/config.json create mode 100644 exercises/practice/secret-handshake/.meta/example.el create mode 100644 exercises/practice/secret-handshake/.meta/tests.toml create mode 100644 exercises/practice/secret-handshake/secret-handshake-test.el create mode 100644 exercises/practice/secret-handshake/secret-handshake.el diff --git a/config.json b/config.json index 36a93ae6..e5c26429 100644 --- a/config.json +++ b/config.json @@ -512,6 +512,14 @@ "strings" ] }, + { + "slug": "secret-handshake", + "name": "Secret Handshake", + "uuid": "e55f5562-9126-4cc7-9f9e-a3cbdfd292b4", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "series", "name": "Series", diff --git a/exercises/practice/secret-handshake/.docs/instructions.md b/exercises/practice/secret-handshake/.docs/instructions.md new file mode 100644 index 00000000..d2120b9b --- /dev/null +++ b/exercises/practice/secret-handshake/.docs/instructions.md @@ -0,0 +1,48 @@ +# Instructions + +Your task is to convert a number between 1 and 31 to a sequence of actions in the secret handshake. + +The sequence of actions is chosen by looking at the rightmost five digits of the number once it's been converted to binary. +Start at the right-most digit and move left. + +The actions for each number place are: + +```plaintext +00001 = wink +00010 = double blink +00100 = close your eyes +01000 = jump +10000 = Reverse the order of the operations in the secret handshake. +``` + +Let's use the number `9` as an example: + +- 9 in binary is `1001`. +- The digit that is farthest to the right is 1, so the first action is `wink`. +- Going left, the next digit is 0, so there is no double-blink. +- Going left again, the next digit is 0, so you leave your eyes open. +- Going left again, the next digit is 1, so you jump. + +That was the last digit, so the final code is: + +```plaintext +wink, jump +``` + +Given the number 26, which is `11010` in binary, we get the following actions: + +- double blink +- jump +- reverse actions + +The secret handshake for 26 is therefore: + +```plaintext +jump, double blink +``` + +~~~~exercism/note +If you aren't sure what binary is or how it works, check out [this binary tutorial][intro-to-binary]. + +[intro-to-binary]: https://medium.com/basecs/bits-bytes-building-with-binary-13cb4289aafa +~~~~ diff --git a/exercises/practice/secret-handshake/.docs/introduction.md b/exercises/practice/secret-handshake/.docs/introduction.md new file mode 100644 index 00000000..176b92e8 --- /dev/null +++ b/exercises/practice/secret-handshake/.docs/introduction.md @@ -0,0 +1,7 @@ +# Introduction + +You are starting a secret coding club with some friends and friends-of-friends. +Not everyone knows each other, so you and your friends have decided to create a secret handshake that you can use to recognize that someone is a member. +You don't want anyone who isn't in the know to be able to crack the code. + +You've designed the code so that one person says a number between 1 and 31, and the other person turns it into a series of actions. diff --git a/exercises/practice/secret-handshake/.meta/config.json b/exercises/practice/secret-handshake/.meta/config.json new file mode 100644 index 00000000..ec07121c --- /dev/null +++ b/exercises/practice/secret-handshake/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "secret-handshake.el" + ], + "test": [ + "secret-handshake-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given a decimal number, convert it to the appropriate sequence of events for a secret handshake.", + "source": "Bert, in Mary Poppins", + "source_url": "https://www.imdb.com/title/tt0058331/quotes/?item=qt0437047" +} diff --git a/exercises/practice/secret-handshake/.meta/example.el b/exercises/practice/secret-handshake/.meta/example.el new file mode 100644 index 00000000..8271b79f --- /dev/null +++ b/exercises/practice/secret-handshake/.meta/example.el @@ -0,0 +1,26 @@ +;;; secret-handshake.el --- Secret Handshake (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defun commands (number) + (let ((all-commands '("wink" "double blink" "close your eyes" "jump")) + (result nil)) + (cl-labels + ((extract (action shift pending) + (cl-loop until (null pending) + if (/= (logand number action) 0) + do (setq result (cons (car pending) result)) + do (setq pending (cdr pending)) + do (setq action (lsh action shift)) + finally return result))) + (if (= (logand number 16) 0) + (funcall #'extract 8 -1 (reverse all-commands)) + (funcall #'extract 1 1 all-commands))))) + +(provide 'secret-handshake) +;;; secret-handshake.el ends here + diff --git a/exercises/practice/secret-handshake/.meta/tests.toml b/exercises/practice/secret-handshake/.meta/tests.toml new file mode 100644 index 00000000..f318e528 --- /dev/null +++ b/exercises/practice/secret-handshake/.meta/tests.toml @@ -0,0 +1,43 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[b8496fbd-6778-468c-8054-648d03c4bb23] +description = "wink for 1" + +[83ec6c58-81a9-4fd1-bfaf-0160514fc0e3] +description = "double blink for 10" + +[0e20e466-3519-4134-8082-5639d85fef71] +description = "close your eyes for 100" + +[b339ddbb-88b7-4b7d-9b19-4134030d9ac0] +description = "jump for 1000" + +[40499fb4-e60c-43d7-8b98-0de3ca44e0eb] +description = "combine two actions" + +[9730cdd5-ef27-494b-afd3-5c91ad6c3d9d] +description = "reverse two actions" + +[0b828205-51ca-45cd-90d5-f2506013f25f] +description = "reversing one action gives the same action" + +[9949e2ac-6c9c-4330-b685-2089ab28b05f] +description = "reversing no actions still gives no actions" + +[23fdca98-676b-4848-970d-cfed7be39f81] +description = "all possible actions" + +[ae8fe006-d910-4d6f-be00-54b7c3799e79] +description = "reverse all possible actions" + +[3d36da37-b31f-4cdb-a396-d93a2ee1c4a5] +description = "do nothing for zero" diff --git a/exercises/practice/secret-handshake/secret-handshake-test.el b/exercises/practice/secret-handshake/secret-handshake-test.el new file mode 100644 index 00000000..9ef4e020 --- /dev/null +++ b/exercises/practice/secret-handshake/secret-handshake-test.el @@ -0,0 +1,57 @@ +;;; secret-handshake-test.el --- Tests for Secret Handshake (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "secret-handshake.el") +(declare-function commands "secret-handshake.el" (number)) + + +(ert-deftest wink-for-1 () + (should (equal '("wink") (commands 1)))) + + +(ert-deftest double-blink-for-10 () + (should (equal '("double blink") (commands 2)))) + + +(ert-deftest close-your-eyes-for-100 () + (should (equal '("close your eyes") (commands 4)))) + + +(ert-deftest jump-for-1000 () + (should (equal '("jump") (commands 8)))) + + +(ert-deftest combine-two-actions () + (should (equal '("wink" "double blink") (commands 3)))) + + +(ert-deftest reverse-two-actions () + (should (equal '("double blink" "wink") (commands 19)))) + + +(ert-deftest reversing-one-action-gives-the-same-action () + (should (equal '("jump") (commands 24)))) + + +(ert-deftest reversing-no-actions-still-gives-no-actions () + (should (equal '() (commands 16)))) + + +(ert-deftest all-possible-actions () + (should (equal '("wink" "double blink" "close your eyes" "jump") (commands 15)))) + + +(ert-deftest reverse-all-possible-actions () + (should (equal '("jump" "close your eyes" "double blink" "wink") (commands 31)))) + + +(ert-deftest do-nothing-for-zero () + (should (equal '() (commands 0)))) + + +(provide 'secret-handshake-test) +;;; secret-handshake-test.el ends here diff --git a/exercises/practice/secret-handshake/secret-handshake.el b/exercises/practice/secret-handshake/secret-handshake.el new file mode 100644 index 00000000..d6dbf7ea --- /dev/null +++ b/exercises/practice/secret-handshake/secret-handshake.el @@ -0,0 +1,14 @@ +;;; secret-handshake.el --- Secret Handshake (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun commands (number) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'secret-handshake) +;;; secret-handshake.el ends here + From 96f8de8eac908484828fba2c2a0ba05a8be6d4ff Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Wed, 5 Jun 2024 00:19:39 +1000 Subject: [PATCH 100/162] Add satellite exercise (#398) --- config.json | 8 +++ .../practice/satellite/.docs/instructions.md | 27 ++++++++++ .../practice/satellite/.meta/config.json | 17 ++++++ exercises/practice/satellite/.meta/example.el | 31 +++++++++++ exercises/practice/satellite/.meta/tests.toml | 28 ++++++++++ .../practice/satellite/satellite-test.el | 52 +++++++++++++++++++ exercises/practice/satellite/satellite.el | 14 +++++ 7 files changed, 177 insertions(+) create mode 100644 exercises/practice/satellite/.docs/instructions.md create mode 100644 exercises/practice/satellite/.meta/config.json create mode 100644 exercises/practice/satellite/.meta/example.el create mode 100644 exercises/practice/satellite/.meta/tests.toml create mode 100644 exercises/practice/satellite/satellite-test.el create mode 100644 exercises/practice/satellite/satellite.el diff --git a/config.json b/config.json index e5c26429..507171b0 100644 --- a/config.json +++ b/config.json @@ -788,6 +788,14 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "satellite", + "name": "Satellite", + "uuid": "02d23d01-c4c6-4fd1-9e0b-f6a457c402ed", + "practices": [], + "prerequisites": [], + "difficulty": 6 + }, { "slug": "knapsack", "name": "Knapsack", diff --git a/exercises/practice/satellite/.docs/instructions.md b/exercises/practice/satellite/.docs/instructions.md new file mode 100644 index 00000000..fbbf14f4 --- /dev/null +++ b/exercises/practice/satellite/.docs/instructions.md @@ -0,0 +1,27 @@ +# Instructions + +Imagine you need to transmit a binary tree to a satellite approaching Alpha Centauri and you have limited bandwidth. +Since the tree has no repeating items it can be uniquely represented by its [pre-order and in-order traversals][wiki]. + +Write the software for the satellite to rebuild the tree from the traversals. + +A pre-order traversal reads the value of the current node before (hence "pre") reading the left subtree in pre-order. +Afterwards the right subtree is read in pre-order. + +An in-order traversal reads the left subtree in-order then the current node and finally the right subtree in-order. +So in order from left to right. + +For example the pre-order traversal of this tree is [a, i, x, f, r]. +The in-order traversal of this tree is [i, a, f, x, r] + +```text + a + / \ +i x + / \ + f r +``` + +Note: the first item in the pre-order traversal is always the root. + +[wiki]: https://en.wikipedia.org/wiki/Tree_traversal diff --git a/exercises/practice/satellite/.meta/config.json b/exercises/practice/satellite/.meta/config.json new file mode 100644 index 00000000..d7503331 --- /dev/null +++ b/exercises/practice/satellite/.meta/config.json @@ -0,0 +1,17 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "satellite.el" + ], + "test": [ + "satellite-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Rebuild binary trees from pre-order and in-order traversals." +} diff --git a/exercises/practice/satellite/.meta/example.el b/exercises/practice/satellite/.meta/example.el new file mode 100644 index 00000000..b4fb6ac8 --- /dev/null +++ b/exercises/practice/satellite/.meta/example.el @@ -0,0 +1,31 @@ +;;; satellite.el --- Satellite (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) +(require 'seq) + +(defun tree-from-traversals (preorder inorder) + (when (/= (length preorder) (length inorder)) + (error "traversals must have the same length")) + (when (or (/= (length preorder) (length (seq-uniq preorder))) + (/= (length inorder) (length (seq-uniq inorder)))) + (error "traversals must contain unique items")) + (cl-labels + ((traverse (successor) + (cond + ((and successor (equal (car inorder) successor)) nil) + ((null preorder) (error "traversals must have the same elements")) + (t (let ((v (car preorder))) + (setq preorder (cdr preorder)) + (let ((l (funcall #'traverse v))) + (setq inorder (cdr inorder)) + (let ((r (and inorder (funcall #'traverse successor)))) + (list (cons :v v) (cons :l l) (cons :r r))))))))) + (and preorder (funcall #'traverse nil)))) + +(provide 'satellite) +;;; satellite.el ends here + diff --git a/exercises/practice/satellite/.meta/tests.toml b/exercises/practice/satellite/.meta/tests.toml new file mode 100644 index 00000000..b32dc3b1 --- /dev/null +++ b/exercises/practice/satellite/.meta/tests.toml @@ -0,0 +1,28 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[8df3fa26-811a-4165-9286-ff9ac0850d19] +description = "Empty tree" + +[f945ccfc-05e3-47d7-825b-0270559d43ad] +description = "Tree with one item" + +[a0121d5f-37b0-48dd-9c64-cba4c4464135] +description = "Tree with many items" + +[6074041f-4891-4d81-a128-401050c2a3b0] +description = "Reject traversals of different length" + +[27916ce4-45f3-4d8b-8528-496fedc157ca] +description = "Reject inconsistent traversals of same length" + +[d86a3d72-76a9-43b5-9d3a-e64cb1216035] +description = "Reject traversals with repeated items" diff --git a/exercises/practice/satellite/satellite-test.el b/exercises/practice/satellite/satellite-test.el new file mode 100644 index 00000000..bfa19d13 --- /dev/null +++ b/exercises/practice/satellite/satellite-test.el @@ -0,0 +1,52 @@ +;;; satellite-test.el --- Tests for Satellite (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "satellite.el") +(declare-function tree-from-traversals "satellite.el" (preorder inorder)) + + +(ert-deftest empty-tree () + (should (equal nil + (tree-from-traversals '() '())))) + + +(ert-deftest tree-with-one-item () + (should (equal '((:v . "a") + (:l . nil) + (:r . nil)) + (tree-from-traversals '("a") '("a"))))) + + +(ert-deftest tree-with-many-items () + (should (equal '((:v . "a") + (:l . ((:v . "i") + (:l . nil) + (:r . nil))) + (:r . ((:v . "x") + (:l . ((:v . "f") + (:l . nil) + (:r . nil))) + (:r . ((:v . "r") + (:l . nil) + (:r . nil)))))) + (tree-from-traversals '("a" "i" "x" "f" "r") '("i" "a" "f" "x" "r"))))) + + +(ert-deftest reject-traversals-of-different-length () + (should-error (tree-from-traversals '("a" "b") '("b" "a" "r")))) + + +(ert-deftest reject-inconsistent-traversals-of-same-length () + (should-error (tree-from-traversals '("x" "y" "z") '("a" "b" "c")))) + + +(ert-deftest reject-traversals-with-repeated-items () + (should-error (tree-from-traversals '("a" "b" "a") '("b" "a" "a")))) + + +(provide 'satellite-test) +;;; satellite-test.el ends here diff --git a/exercises/practice/satellite/satellite.el b/exercises/practice/satellite/satellite.el new file mode 100644 index 00000000..ad0e3447 --- /dev/null +++ b/exercises/practice/satellite/satellite.el @@ -0,0 +1,14 @@ +;;; satellite.el --- Satellite (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun tree-from-traversals (preorder inorder) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'satellite) +;;; satellite.el ends here + From 1ec1febb04f9731bcf8842c71abbb0db595554dd Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Mon, 10 Jun 2024 13:13:14 -0500 Subject: [PATCH 101/162] add `pig-latin` (#399) --- config.json | 8 ++ .../practice/pig-latin/.docs/instructions.md | 46 ++++++++ .../practice/pig-latin/.docs/introduction.md | 8 ++ .../practice/pig-latin/.meta/config.json | 19 ++++ exercises/practice/pig-latin/.meta/example.el | 52 +++++++++ exercises/practice/pig-latin/.meta/tests.toml | 76 +++++++++++++ .../practice/pig-latin/pig-latin-test.el | 102 ++++++++++++++++++ exercises/practice/pig-latin/pig-latin.el | 14 +++ 8 files changed, 325 insertions(+) create mode 100644 exercises/practice/pig-latin/.docs/instructions.md create mode 100644 exercises/practice/pig-latin/.docs/introduction.md create mode 100644 exercises/practice/pig-latin/.meta/config.json create mode 100644 exercises/practice/pig-latin/.meta/example.el create mode 100644 exercises/practice/pig-latin/.meta/tests.toml create mode 100644 exercises/practice/pig-latin/pig-latin-test.el create mode 100644 exercises/practice/pig-latin/pig-latin.el diff --git a/config.json b/config.json index 507171b0..1a2f8f7a 100644 --- a/config.json +++ b/config.json @@ -806,6 +806,14 @@ "topics": [ "control_flow_loops" ] + }, + { + "slug": "pig-latin", + "name": "Pig Latin", + "uuid": "3bee6827-8766-4d4d-9d0f-3facc3bfd3f4", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, diff --git a/exercises/practice/pig-latin/.docs/instructions.md b/exercises/practice/pig-latin/.docs/instructions.md new file mode 100644 index 00000000..a9645ac2 --- /dev/null +++ b/exercises/practice/pig-latin/.docs/instructions.md @@ -0,0 +1,46 @@ +# Instructions + +Your task is to translate text from English to Pig Latin. +The translation is defined using four rules, which look at the pattern of vowels and consonants at the beginning of a word. +These rules look at each word's use of vowels and consonants: + +- vowels: the letters `a`, `e`, `i`, `o`, and `u` +- consonants: the other 21 letters of the English alphabet + +## Rule 1 + +If a word begins with a vowel, or starts with `"xr"` or `"yt"`, add an `"ay"` sound to the end of the word. + +For example: + +- `"apple"` -> `"appleay"` (starts with vowel) +- `"xray"` -> `"xrayay"` (starts with `"xr"`) +- `"yttria"` -> `"yttriaay"` (starts with `"yt"`) + +## Rule 2 + +If a word begins with one or more consonants, first move those consonants to the end of the word and then add an `"ay"` sound to the end of the word. + +For example: + +- `"pig"` -> `"igp"` -> `"igpay"` (starts with single consonant) +- `"chair"` -> `"airch"` -> `"airchay"` (starts with multiple consonants) +- `"thrush"` -> `"ushthr"` -> `"ushthray"` (starts with multiple consonants) + +## Rule 3 + +If a word starts with zero or more consonants followed by `"qu"`, first move those consonants (if any) and the `"qu"` part to the end of the word, and then add an `"ay"` sound to the end of the word. + +For example: + +- `"quick"` -> `"ickqu"` -> `"ickquay"` (starts with `"qu"`, no preceding consonants) +- `"square"` -> `"aresqu"` -> `"aresquay"` (starts with one consonant followed by `"qu`") + +## Rule 4 + +If a word starts with one or more consonants followed by `"y"`, first move the consonants preceding the `"y"`to the end of the word, and then add an `"ay"` sound to the end of the word. + +Some examples: + +- `"my"` -> `"ym"` -> `"ymay"` (starts with single consonant followed by `"y"`) +- `"rhythm"` -> `"ythmrh"` -> `"ythmrhay"` (starts with multiple consonants followed by `"y"`) diff --git a/exercises/practice/pig-latin/.docs/introduction.md b/exercises/practice/pig-latin/.docs/introduction.md new file mode 100644 index 00000000..04baa475 --- /dev/null +++ b/exercises/practice/pig-latin/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +Your parents have challenged you and your sibling to a game of two-on-two basketball. +Confident they'll win, they let you score the first couple of points, but then start taking over the game. +Needing a little boost, you start speaking in [Pig Latin][pig-latin], which is a made-up children's language that's difficult for non-children to understand. +This will give you the edge to prevail over your parents! + +[pig-latin]: https://en.wikipedia.org/wiki/Pig_latin diff --git a/exercises/practice/pig-latin/.meta/config.json b/exercises/practice/pig-latin/.meta/config.json new file mode 100644 index 00000000..86d6dc4d --- /dev/null +++ b/exercises/practice/pig-latin/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "pig-latin.el" + ], + "test": [ + "pig-latin-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Implement a program that translates from English to Pig Latin.", + "source": "The Pig Latin exercise at Test First Teaching by Ultrasaurus", + "source_url": "https://github.com/ultrasaurus/test-first-teaching/blob/master/learn_ruby/pig_latin/" +} diff --git a/exercises/practice/pig-latin/.meta/example.el b/exercises/practice/pig-latin/.meta/example.el new file mode 100644 index 00000000..32322d0b --- /dev/null +++ b/exercises/practice/pig-latin/.meta/example.el @@ -0,0 +1,52 @@ +;;; pig-latin.el --- Pig Latin (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(defvar +vowels+ '("a" "e" "i" "o" "u" "xr" "yt")) + +(defun custom-split-string (str) + "Split STR into a list of words." + (if (zerop (length str)) + nil + (let* ((split-at (string-match " " str)) + (word (if split-at (substring str 0 split-at) str)) + (rest-str (if split-at (substring str (1+ split-at)) ""))) + (cons word (custom-split-string rest-str))))) + +(defun starts-with-p (word search-list) + "Check if WORD starts with any prefix in SEARCH-LIST." + (if search-list + (if (string-prefix-p (car search-list) word) + t + (starts-with-p word (cdr search-list))))) + +(defun stop-p (word index) + "Determine if processing should stop based on WORD and INDEX." + (or (starts-with-p word +vowels+) + (and (char-equal ?y (aref word 0)) (= index 1)))) + +(defun take-consonants (word &optional index) + "Calculate the number of consonants at the start of WORD. +INDEX is used to keep track of the current position." + (unless index + (setq index 0)) + (cond + ((stop-p word index) index) + ((starts-with-p word '("qu")) (take-consonants (substring word 2) (+ 2 index))) + (t (take-consonants (substring word 1) (1+ index))))) + +(defun translate-word (word) + "Translate a single WORD into Pig Latin." + (let ((index (take-consonants word))) + (concat (substring word index) (substring word 0 index) "ay"))) + +(defun translate (phrase) + "Translate a PHRASE into Pig Latin." + (mapconcat #'translate-word (split-string phrase) " ")) + + +(provide 'pig-latin) +;;; pig-latin.el ends here + diff --git a/exercises/practice/pig-latin/.meta/tests.toml b/exercises/practice/pig-latin/.meta/tests.toml new file mode 100644 index 00000000..c29168c5 --- /dev/null +++ b/exercises/practice/pig-latin/.meta/tests.toml @@ -0,0 +1,76 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[11567f84-e8c6-4918-aedb-435f0b73db57] +description = "ay is added to words that start with vowels -> word beginning with a" + +[f623f581-bc59-4f45-9032-90c3ca9d2d90] +description = "ay is added to words that start with vowels -> word beginning with e" + +[7dcb08b3-23a6-4e8a-b9aa-d4e859450d58] +description = "ay is added to words that start with vowels -> word beginning with i" + +[0e5c3bff-266d-41c8-909f-364e4d16e09c] +description = "ay is added to words that start with vowels -> word beginning with o" + +[614ba363-ca3c-4e96-ab09-c7320799723c] +description = "ay is added to words that start with vowels -> word beginning with u" + +[bf2538c6-69eb-4fa7-a494-5a3fec911326] +description = "ay is added to words that start with vowels -> word beginning with a vowel and followed by a qu" + +[e5be8a01-2d8a-45eb-abb4-3fcc9582a303] +description = "first letter and ay are moved to the end of words that start with consonants -> word beginning with p" + +[d36d1e13-a7ed-464d-a282-8820cb2261ce] +description = "first letter and ay are moved to the end of words that start with consonants -> word beginning with k" + +[d838b56f-0a89-4c90-b326-f16ff4e1dddc] +description = "first letter and ay are moved to the end of words that start with consonants -> word beginning with x" + +[bce94a7a-a94e-4e2b-80f4-b2bb02e40f71] +description = "first letter and ay are moved to the end of words that start with consonants -> word beginning with q without a following u" + +[c01e049a-e3e2-451c-bf8e-e2abb7e438b8] +description = "some letter clusters are treated like a single consonant -> word beginning with ch" + +[9ba1669e-c43f-4b93-837a-cfc731fd1425] +description = "some letter clusters are treated like a single consonant -> word beginning with qu" + +[92e82277-d5e4-43d7-8dd3-3a3b316c41f7] +description = "some letter clusters are treated like a single consonant -> word beginning with qu and a preceding consonant" + +[79ae4248-3499-4d5b-af46-5cb05fa073ac] +description = "some letter clusters are treated like a single consonant -> word beginning with th" + +[e0b3ae65-f508-4de3-8999-19c2f8e243e1] +description = "some letter clusters are treated like a single consonant -> word beginning with thr" + +[20bc19f9-5a35-4341-9d69-1627d6ee6b43] +description = "some letter clusters are treated like a single consonant -> word beginning with sch" + +[54b796cb-613d-4509-8c82-8fbf8fc0af9e] +description = "some letter clusters are treated like a single vowel -> word beginning with yt" + +[8c37c5e1-872e-4630-ba6e-d20a959b67f6] +description = "some letter clusters are treated like a single vowel -> word beginning with xr" + +[a4a36d33-96f3-422c-a233-d4021460ff00] +description = "position of y in a word determines if it is a consonant or a vowel -> y is treated like a consonant at the beginning of a word" + +[adc90017-1a12-4100-b595-e346105042c7] +description = "position of y in a word determines if it is a consonant or a vowel -> y is treated like a vowel at the end of a consonant cluster" + +[29b4ca3d-efe5-4a95-9a54-8467f2e5e59a] +description = "position of y in a word determines if it is a consonant or a vowel -> y as second letter in two letter word" + +[44616581-5ce3-4a81-82d0-40c7ab13d2cf] +description = "phrases are translated -> a whole phrase" diff --git a/exercises/practice/pig-latin/pig-latin-test.el b/exercises/practice/pig-latin/pig-latin-test.el new file mode 100644 index 00000000..d3540983 --- /dev/null +++ b/exercises/practice/pig-latin/pig-latin-test.el @@ -0,0 +1,102 @@ +;;; pig-latin-test.el --- Pig Latin (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "pig-latin.el") +(declare-function translate "pig-latin.el" (phrase)) + + +(ert-deftest word-beginning-with-a () + (should (string= (translate "apple") "appleay"))) + + +(ert-deftest word-beginning-with-e () + (should (string= (translate "ear") "earay"))) + + +(ert-deftest word-beginning-with-i () + (should (string= (translate "igloo") "iglooay"))) + + +(ert-deftest word-beginning-with-o () + (should (string= (translate "object") "objectay"))) + + +(ert-deftest word-beginning-with-u () + (should (string= (translate "under") "underay"))) + + +(ert-deftest word-beginning-with-a-vowel-and-followed-by-a-qu () + (should (string= (translate "equal") "equalay"))) + + +(ert-deftest word-beginning-with-p () + (should (string= (translate "pig") "igpay"))) + + +(ert-deftest word-beginning-with-k () + (should (string= (translate "koala") "oalakay"))) + + +(ert-deftest word-beginning-with-x () + (should (string= (translate "xenon") "enonxay"))) + + +(ert-deftest word-beginning-with-q-without-a-following-u () + (should (string= (translate "qat") "atqay"))) + + +(ert-deftest word-beginning-with-ch () + (should (string= (translate "chair") "airchay"))) + + +(ert-deftest word-beginning-with-qu () + (should (string= (translate "queen") "eenquay"))) + + +(ert-deftest word-beginning-with-qu-and-a-preceding-consonant () + (should (string= (translate "square") "aresquay"))) + + +(ert-deftest word-beginning-with-th () + (should (string= (translate "therapy") "erapythay"))) + + +(ert-deftest word-beginning-with-thr () + (should (string= (translate "thrush") "ushthray"))) + + +(ert-deftest word-beginning-with-sch () + (should (string= (translate "school") "oolschay"))) + + +(ert-deftest word-beginning-with-yt () + (should (string= (translate "yttria") "yttriaay"))) + + +(ert-deftest word-beginning-with-xr () + (should (string= (translate "xray") "xrayay"))) + + +(ert-deftest y-is-treated-like-a-consonant-at-the-beginning-of-a-word () + (should (string= (translate "yellow") "ellowyay"))) + + +(ert-deftest y-is-treated-like-a-vowel-at-the-end-of-a-consonant-cluster () + (should (string= (translate "rhythm") "ythmrhay"))) + + +(ert-deftest y-as-second-letter-in-two-letter-word () + (should (string= (translate "my") "ymay"))) + + +(ert-deftest a-whole-phrase () + (should (string= (translate "quick fast run") "ickquay astfay unray"))) + + +(provide 'pig-latin-test) +;;; pig-latin-test.el ends here + diff --git a/exercises/practice/pig-latin/pig-latin.el b/exercises/practice/pig-latin/pig-latin.el new file mode 100644 index 00000000..5824d6e0 --- /dev/null +++ b/exercises/practice/pig-latin/pig-latin.el @@ -0,0 +1,14 @@ +;;; pig-latin.el --- Pig Latin (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun translate (phrase) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'pig-latin) +;;; pig-latin.el ends here + From 47115c8cd2019e53de4c577336c86745be8ae010 Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Wed, 12 Jun 2024 16:47:12 -0500 Subject: [PATCH 102/162] add food-chain (#402) --- config.json | 8 + .../practice/food-chain/.docs/instructions.md | 64 +++++++ .../practice/food-chain/.meta/config.json | 19 +++ .../practice/food-chain/.meta/example.el | 46 +++++ .../practice/food-chain/.meta/tests.toml | 40 +++++ .../practice/food-chain/food-chain-test.el | 158 ++++++++++++++++++ exercises/practice/food-chain/food-chain.el | 14 ++ 7 files changed, 349 insertions(+) create mode 100644 exercises/practice/food-chain/.docs/instructions.md create mode 100644 exercises/practice/food-chain/.meta/config.json create mode 100644 exercises/practice/food-chain/.meta/example.el create mode 100644 exercises/practice/food-chain/.meta/tests.toml create mode 100644 exercises/practice/food-chain/food-chain-test.el create mode 100644 exercises/practice/food-chain/food-chain.el diff --git a/config.json b/config.json index 1a2f8f7a..e6c53294 100644 --- a/config.json +++ b/config.json @@ -814,6 +814,14 @@ "practices": [], "prerequisites": [], "difficulty": 5 + }, + { + "slug": "food-chain", + "name": "Food Chain", + "uuid": "ac1c0246-0fed-46e7-819a-0b013b2b4585", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, diff --git a/exercises/practice/food-chain/.docs/instructions.md b/exercises/practice/food-chain/.docs/instructions.md new file mode 100644 index 00000000..125820e3 --- /dev/null +++ b/exercises/practice/food-chain/.docs/instructions.md @@ -0,0 +1,64 @@ +# Instructions + +Generate the lyrics of the song 'I Know an Old Lady Who Swallowed a Fly'. + +While you could copy/paste the lyrics, or read them from a file, this problem is much more interesting if you approach it algorithmically. + +This is a [cumulative song][cumulative-song] of unknown origin. + +This is one of many common variants. + +```text +I know an old lady who swallowed a fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a spider. +It wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a bird. +How absurd to swallow a bird! +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a cat. +Imagine that, to swallow a cat! +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a dog. +What a hog, to swallow a dog! +She swallowed the dog to catch the cat. +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a goat. +Just opened her throat and swallowed a goat! +She swallowed the goat to catch the dog. +She swallowed the dog to catch the cat. +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a cow. +I don't know how she swallowed a cow! +She swallowed the cow to catch the goat. +She swallowed the goat to catch the dog. +She swallowed the dog to catch the cat. +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a horse. +She's dead, of course! +``` + +[cumulative-song]: https://en.wikipedia.org/wiki/Cumulative_song diff --git a/exercises/practice/food-chain/.meta/config.json b/exercises/practice/food-chain/.meta/config.json new file mode 100644 index 00000000..cbd54696 --- /dev/null +++ b/exercises/practice/food-chain/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "food-chain.el" + ], + "test": [ + "food-chain-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Generate the lyrics of the song 'I Know an Old Lady Who Swallowed a Fly'.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/There_Was_an_Old_Lady_Who_Swallowed_a_Fly" +} diff --git a/exercises/practice/food-chain/.meta/example.el b/exercises/practice/food-chain/.meta/example.el new file mode 100644 index 00000000..579526b2 --- /dev/null +++ b/exercises/practice/food-chain/.meta/example.el @@ -0,0 +1,46 @@ +;;; food-chain.el --- Food Chain (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(defvar +creatures+ ["fly" "spider" "bird" "cat" "dog" "goat" "cow" "horse"]) +(defvar +unique-lines+ ["I don't know why she swallowed the fly. Perhaps she'll die." + "It wriggled and jiggled and tickled inside her." + "How absurd to swallow a bird!" + "Imagine that, to swallow a cat!" + "What a hog, to swallow a dog!" + "Just opened her throat and swallowed a goat!" + "I don't know how she swallowed a cow!" + "She's dead, of course!"]) + +(defun verse-end-p (index) + (or (= 7 index) (zerop index))) + +(defun add-lines (index) + (if (verse-end-p index) + (list (aref +unique-lines+ index)) + (let* ((spider (if (= 2 index) " that wriggled and jiggled and tickled inside her" "")) + (creature (aref +creatures+ index)) + (next-creature (aref +creatures+ (1- index))) + (line (format "She swallowed the %s to catch the %s%s." creature next-creature spider))) + (cons line (add-lines (1- index)))))) + +(defun single-verse (index) + (let* ((start-line (format "I know an old lady who swallowed a %s." (aref +creatures+ index))) + (second-line (unless (verse-end-p index) (aref +unique-lines+ index))) + (verse-block (add-lines index))) + (if second-line + (cons start-line (cons second-line verse-block)) + (cons start-line verse-block)))) + + +(defun recite (start-verse end-verse) + (let (output) + (cl-loop for index from (1- start-verse) below end-verse + do (setq output (append output (single-verse index) '("")))) + (butlast output 1))) ;; Remove the last empty string added + +(provide 'food-chain) +;;; food-chain.el ends here + diff --git a/exercises/practice/food-chain/.meta/tests.toml b/exercises/practice/food-chain/.meta/tests.toml new file mode 100644 index 00000000..30c5b980 --- /dev/null +++ b/exercises/practice/food-chain/.meta/tests.toml @@ -0,0 +1,40 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[751dce68-9412-496e-b6e8-855998c56166] +description = "fly" + +[6c56f861-0c5e-4907-9a9d-b2efae389379] +description = "spider" + +[3edf5f33-bef1-4e39-ae67-ca5eb79203fa] +description = "bird" + +[e866a758-e1ff-400e-9f35-f27f28cc288f] +description = "cat" + +[3f02c30e-496b-4b2a-8491-bc7e2953cafb] +description = "dog" + +[4b3fd221-01ea-46e0-825b-5734634fbc59] +description = "goat" + +[1b707da9-7001-4fac-941f-22ad9c7a65d4] +description = "cow" + +[3cb10d46-ae4e-4d2c-9296-83c9ffc04cdc] +description = "horse" + +[22b863d5-17e4-4d1e-93e4-617329a5c050] +description = "multiple verses" + +[e626b32b-745c-4101-bcbd-3b13456893db] +description = "full song" diff --git a/exercises/practice/food-chain/food-chain-test.el b/exercises/practice/food-chain/food-chain-test.el new file mode 100644 index 00000000..ad394759 --- /dev/null +++ b/exercises/practice/food-chain/food-chain-test.el @@ -0,0 +1,158 @@ +;;; food-chain-test.el --- Food Chain (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "food-chain.el") +(declare-function recite "food-chain.el" (start-verse end-verse)) + + +(ert-deftest fly () + (let ((expected '("I know an old lady who swallowed a fly." + "I don't know why she swallowed the fly. Perhaps she'll die."))) + (should (equal (recite 1 1) expected)))) + +(ert-deftest spider () + (let ((expected '("I know an old lady who swallowed a spider." + "It wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die."))) + (should (equal (recite 2 2) expected)))) + + +(ert-deftest bird () + (let ((expected '("I know an old lady who swallowed a bird." + "How absurd to swallow a bird!" + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die."))) + (should (equal (recite 3 3) expected)))) + + +(ert-deftest cat () + (let ((expected '("I know an old lady who swallowed a cat." + "Imagine that, to swallow a cat!" + "She swallowed the cat to catch the bird." + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die."))) + (should (equal (recite 4 4) expected)))) + + +(ert-deftest dog () + (let ((expected '("I know an old lady who swallowed a dog." + "What a hog, to swallow a dog!" + "She swallowed the dog to catch the cat." + "She swallowed the cat to catch the bird." + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die."))) + (should (equal (recite 5 5) expected)))) + + +(ert-deftest goat () + (let ((expected '("I know an old lady who swallowed a goat." + "Just opened her throat and swallowed a goat!" + "She swallowed the goat to catch the dog." + "She swallowed the dog to catch the cat." + "She swallowed the cat to catch the bird." + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die."))) + (should (equal (recite 6 6) expected)))) + + +(ert-deftest cow () + (let ((expected '("I know an old lady who swallowed a cow." + "I don't know how she swallowed a cow!" + "She swallowed the cow to catch the goat." + "She swallowed the goat to catch the dog." + "She swallowed the dog to catch the cat." + "She swallowed the cat to catch the bird." + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die."))) + (should (equal (recite 7 7) expected)))) + + +(ert-deftest horse () + (let ((expected '("I know an old lady who swallowed a horse." + "She's dead, of course!"))) + (should (equal (recite 8 8) expected)))) + + +(ert-deftest multiple-verses () + (let ((expected '("I know an old lady who swallowed a fly." + "I don't know why she swallowed the fly. Perhaps she'll die." + "" + "I know an old lady who swallowed a spider." + "It wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die." + "" + "I know an old lady who swallowed a bird." + "How absurd to swallow a bird!" + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die."))) + (should (equal (recite 1 3) expected)))) + + +(ert-deftest full-song () + (let ((expected '("I know an old lady who swallowed a fly." + "I don't know why she swallowed the fly. Perhaps she'll die." + "" + "I know an old lady who swallowed a spider." + "It wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die." + "" + "I know an old lady who swallowed a bird." + "How absurd to swallow a bird!" + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die." + "" + "I know an old lady who swallowed a cat." + "Imagine that, to swallow a cat!" + "She swallowed the cat to catch the bird." + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die." + "" + "I know an old lady who swallowed a dog." + "What a hog, to swallow a dog!" + "She swallowed the dog to catch the cat." + "She swallowed the cat to catch the bird." + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die." + "" + "I know an old lady who swallowed a goat." + "Just opened her throat and swallowed a goat!" + "She swallowed the goat to catch the dog." + "She swallowed the dog to catch the cat." + "She swallowed the cat to catch the bird." + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die." + "" + "I know an old lady who swallowed a cow." + "I don't know how she swallowed a cow!" + "She swallowed the cow to catch the goat." + "She swallowed the goat to catch the dog." + "She swallowed the dog to catch the cat." + "She swallowed the cat to catch the bird." + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her." + "She swallowed the spider to catch the fly." + "I don't know why she swallowed the fly. Perhaps she'll die." + "" + "I know an old lady who swallowed a horse." + "She's dead, of course!"))) + (should (equal (recite 1 8) expected)))) + + +(provide 'food-chain-test) +;;; food-chain-test.el ends here diff --git a/exercises/practice/food-chain/food-chain.el b/exercises/practice/food-chain/food-chain.el new file mode 100644 index 00000000..2e6df614 --- /dev/null +++ b/exercises/practice/food-chain/food-chain.el @@ -0,0 +1,14 @@ +;;; food-chain.el --- Food Chain (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun recite (end-verse start-verse) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'food-chain) +;;; food-chain.el ends here + From ab13a46a6bb4e0f94647973f419c62b976c31a0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:43:37 -0700 Subject: [PATCH 103/162] Bump actions/checkout from 4.1.6 to 4.1.7 (#404) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.6 to 4.1.7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/a5ac7e51b41094c92402da3b24376905380afc29...692973e3d937129bcbf40652eb9f2f61becf3332) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/configlet-sync.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b33276f1..20ba2a9b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: with: version: 28.2 - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.0.0 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.0.0 - name: Run exercism/emacs-lisp ci (runs tests) for all exercises run: | diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index 31117f00..4274bdd1 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.0.0 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.0.0 - name: Fetch configlet uses: exercism/github-actions/configlet-ci@main From 7f74b092406dbf49fea4ac6aae90d9df4d0b4f7a Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Thu, 13 Jun 2024 08:04:52 -0500 Subject: [PATCH 104/162] add circular-buffer, part of 48 in 24 (#400) --- config.json | 8 ++ .../circular-buffer/.docs/instructions.md | 58 ++++++++ .../circular-buffer/.meta/config.json | 19 +++ .../practice/circular-buffer/.meta/example.el | 74 ++++++++++ .../practice/circular-buffer/.meta/tests.toml | 52 +++++++ .../circular-buffer/circular-buffer-test.el | 132 ++++++++++++++++++ .../circular-buffer/circular-buffer.el | 19 +++ 7 files changed, 362 insertions(+) create mode 100644 exercises/practice/circular-buffer/.docs/instructions.md create mode 100644 exercises/practice/circular-buffer/.meta/config.json create mode 100644 exercises/practice/circular-buffer/.meta/example.el create mode 100644 exercises/practice/circular-buffer/.meta/tests.toml create mode 100644 exercises/practice/circular-buffer/circular-buffer-test.el create mode 100644 exercises/practice/circular-buffer/circular-buffer.el diff --git a/config.json b/config.json index e6c53294..a8040b26 100644 --- a/config.json +++ b/config.json @@ -822,6 +822,14 @@ "practices": [], "prerequisites": [], "difficulty": 5 + }, + { + "slug": "circular-buffer", + "name": "Circular Buffer", + "uuid": "d2eaa3fa-42b3-4287-9b87-714a73ac0c65", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, diff --git a/exercises/practice/circular-buffer/.docs/instructions.md b/exercises/practice/circular-buffer/.docs/instructions.md new file mode 100644 index 00000000..2ba1fda2 --- /dev/null +++ b/exercises/practice/circular-buffer/.docs/instructions.md @@ -0,0 +1,58 @@ +# Instructions + +A circular buffer, cyclic buffer or ring buffer is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end. + +A circular buffer first starts empty and of some predefined length. +For example, this is a 7-element buffer: + +```text +[ ][ ][ ][ ][ ][ ][ ] +``` + +Assume that a 1 is written into the middle of the buffer (exact starting location does not matter in a circular buffer): + +```text +[ ][ ][ ][1][ ][ ][ ] +``` + +Then assume that two more elements are added — 2 & 3 — which get appended after the 1: + +```text +[ ][ ][ ][1][2][3][ ] +``` + +If two elements are then removed from the buffer, the oldest values inside the buffer are removed. +The two elements removed, in this case, are 1 & 2, leaving the buffer with just a 3: + +```text +[ ][ ][ ][ ][ ][3][ ] +``` + +If the buffer has 7 elements then it is completely full: + +```text +[5][6][7][8][9][3][4] +``` + +When the buffer is full an error will be raised, alerting the client that further writes are blocked until a slot becomes free. + +When the buffer is full, the client can opt to overwrite the oldest data with a forced write. +In this case, two more elements — A & B — are added and they overwrite the 3 & 4: + +```text +[5][6][7][8][9][A][B] +``` + +3 & 4 have been replaced by A & B making 5 now the oldest data in the buffer. +Finally, if two elements are removed then what would be returned is 5 & 6 yielding the buffer: + +```text +[ ][ ][7][8][9][A][B] +``` + +Because there is space available, if the client again uses overwrite to store C & D then the space where 5 & 6 were stored previously will be used not the location of 7 & 8. +7 is still the oldest element and the buffer is once again full. + +```text +[C][D][7][8][9][A][B] +``` diff --git a/exercises/practice/circular-buffer/.meta/config.json b/exercises/practice/circular-buffer/.meta/config.json new file mode 100644 index 00000000..b840c6a0 --- /dev/null +++ b/exercises/practice/circular-buffer/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "circular-buffer.el" + ], + "test": [ + "circular-buffer-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "A data structure that uses a single, fixed-size buffer as if it were connected end-to-end.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Circular_buffer" +} diff --git a/exercises/practice/circular-buffer/.meta/example.el b/exercises/practice/circular-buffer/.meta/example.el new file mode 100644 index 00000000..96c1321f --- /dev/null +++ b/exercises/practice/circular-buffer/.meta/example.el @@ -0,0 +1,74 @@ +;;; circular-buffer.el --- Circular Buffer (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(define-error 'empty-buffer-error "buffer is empty") + +(define-error 'full-buffer-error "buffer is full") + +(defclass circular-buffer () + ((capacity :initarg :capacity :initform 10) + (buf-modulus :initform 20) + (data :initform nil) + (front :initform 0) + (back :initform 0)) + :documentation "Circular buffer class") + + +(cl-defmethod initialize-instance :after ((buf circular-buffer) &rest _) + (with-slots (capacity buf-modulus data) buf + (setf buf-modulus (* 2 capacity) + data (make-vector capacity nil)))) + +(cl-defmethod buf-empty-p ((buf circular-buffer)) + (with-slots (front back) buf + (= front back))) + +(cl-defmethod buf-full-p ((buf circular-buffer)) + (with-slots (front back buf-modulus capacity) buf + (= (mod (- back front) buf-modulus) capacity))) + +(cl-defmethod next-spot ((buf circular-buffer) s) + (with-slots (buf-modulus) buf + (mod (1+ s) buf-modulus))) + +(cl-defmethod advance-front ((buf circular-buffer)) + (with-slots (front) buf + (setf front (next-spot buf front)))) + +(cl-defmethod advance-back ((buf circular-buffer)) + (with-slots (back) buf + (setf back (next-spot buf back)))) + +(cl-defmethod clear ((buf circular-buffer)) + (with-slots (front back) buf + (setf front back))) + +(cl-defmethod read-buff ((buf circular-buffer)) + (with-slots (front data capacity) buf + (if (buf-empty-p buf) + (signal 'empty-buffer-error nil) + (let ((v (aref data (mod front capacity)))) + (advance-front buf) + v)))) + +(cl-defmethod write ((buf circular-buffer) v) + (with-slots (back data capacity) buf + (if (buf-full-p buf) + (signal 'full-buffer-error nil) + (progn + (aset data (mod back capacity) v) + (advance-back buf))))) + +(cl-defmethod overwrite ((buf circular-buffer) v) + (with-slots (front) buf + (when (buf-full-p buf) + (advance-front buf)) + (write buf v))) + +(provide 'circular-buffer) +;;; circular-buffer.el ends here + diff --git a/exercises/practice/circular-buffer/.meta/tests.toml b/exercises/practice/circular-buffer/.meta/tests.toml new file mode 100644 index 00000000..0fb3143d --- /dev/null +++ b/exercises/practice/circular-buffer/.meta/tests.toml @@ -0,0 +1,52 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[28268ed4-4ff3-45f3-820e-895b44d53dfa] +description = "reading empty buffer should fail" + +[2e6db04a-58a1-425d-ade8-ac30b5f318f3] +description = "can read an item just written" + +[90741fe8-a448-45ce-be2b-de009a24c144] +description = "each item may only be read once" + +[be0e62d5-da9c-47a8-b037-5db21827baa7] +description = "items are read in the order they are written" + +[2af22046-3e44-4235-bfe6-05ba60439d38] +description = "full buffer can't be written to" + +[547d192c-bbf0-4369-b8fa-fc37e71f2393] +description = "a read frees up capacity for another write" + +[04a56659-3a81-4113-816b-6ecb659b4471] +description = "read position is maintained even across multiple writes" + +[60c3a19a-81a7-43d7-bb0a-f07242b1111f] +description = "items cleared out of buffer can't be read" + +[45f3ae89-3470-49f3-b50e-362e4b330a59] +description = "clear frees up capacity for another write" + +[e1ac5170-a026-4725-bfbe-0cf332eddecd] +description = "clear does nothing on empty buffer" + +[9c2d4f26-3ec7-453f-a895-7e7ff8ae7b5b] +description = "overwrite acts like write on non-full buffer" + +[880f916b-5039-475c-bd5c-83463c36a147] +description = "overwrite replaces the oldest item on full buffer" + +[bfecab5b-aca1-4fab-a2b0-cd4af2b053c3] +description = "overwrite replaces the oldest item remaining in buffer following a read" + +[9cebe63a-c405-437b-8b62-e3fdc1ecec5a] +description = "initial clear does not affect wrapping around" diff --git a/exercises/practice/circular-buffer/circular-buffer-test.el b/exercises/practice/circular-buffer/circular-buffer-test.el new file mode 100644 index 00000000..96b7225a --- /dev/null +++ b/exercises/practice/circular-buffer/circular-buffer-test.el @@ -0,0 +1,132 @@ +;;; circular-buffer-test.el --- Circular Buffer (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(require 'eieio) + +(load-file "circular-buffer.el") + +(defun create-test-buffer (capacity) + "Helper function to create a circular buffer with the given capacity." + (circular-buffer :capacity capacity)) + +(ert-deftest reading-empty-buffer-should-fail () + (let ((buf (create-test-buffer 1))) + (should-error (read-buff buf) :type 'empty-buffer-error))) + + +(ert-deftest can-read-an-item-just-written () + (let ((buf (create-test-buffer 1))) + (write buf 1) + (should (equal (read-buff buf) 1)))) + + +(ert-deftest each-item-may-only-be-read-once () + (let ((buf (create-test-buffer 1))) + (write buf 1) + (should (equal (read-buff buf) 1)) + (should-error (read-buff buf) :type 'empty-buffer-error))) + + +(ert-deftest items-are-read-in-the-order-they-are-written () + (let ((buf (create-test-buffer 2))) + (write buf 1) + (write buf 2) + (should (equal (read-buff buf) 1)) + (should (equal (read-buff buf) 2)))) + + +(ert-deftest full-buffer-cant-be-written-to () + (let ((buf (create-test-buffer 1))) + (write buf 1) + (should-error (write buf 2) :type 'full-buffer-error))) + + +(ert-deftest a-read-frees-up-capacity-for-another-write () + (let ((buf (create-test-buffer 1))) + (write buf 1) + (should (equal (read-buff buf) 1)) + (write buf 2) + (should (equal (read-buff buf) 2)))) + + +(ert-deftest read-position-is-maintained-even-across-multiple-writes () + (let ((buf (create-test-buffer 3))) + (write buf 1) + (write buf 2) + (should (equal (read-buff buf) 1)) + (write buf 3) + (should (equal (read-buff buf) 2)) + (should (equal (read-buff buf) 3)))) + + +(ert-deftest items-cleared-out-of-buffer-cant-be-read () + (let ((buf (create-test-buffer 1))) + (write buf 1) + (clear buf) + (should-error (read-buff buf) :type 'empty-buffer-error))) + + +(ert-deftest clear-frees-up-capacity-for-another-write () + (let ((buf (create-test-buffer 1))) + (write buf 1) + (clear buf) + (write buf 2) + (should (equal (read-buff buf) 2)))) + + +(ert-deftest clear-does-nothing-on-empty-buffer () + (let ((buf (create-test-buffer 1))) + (clear buf) + (write buf 1) + (should (equal (read-buff buf) 1)))) + + +(ert-deftest overwrite-acts-like-write-on-non-full-buffer () + (let ((buf (create-test-buffer 2))) + (write buf 1) + (overwrite buf 2) + (should (equal (read-buff buf) 1)) + (should (equal (read-buff buf) 2)))) + + +(ert-deftest overwrite-replaces-the-oldest-item-on-full-buffer () + (let ((buf (create-test-buffer 2))) + (write buf 1) + (write buf 2) + (overwrite buf 3) + (should (equal (read-buff buf) 2)) + (should (equal (read-buff buf) 3)))) + + +(ert-deftest overwrite-replaces-the-oldest-item-remaining-in-buffer-following-a-read () + (let ((buf (create-test-buffer 3))) + (write buf 1) + (write buf 2) + (write buf 3) + (should (equal (read-buff buf) 1)) + (write buf 4) + (overwrite buf 5) + (should (equal (read-buff buf) 3)) + (should (equal (read-buff buf) 4)) + (should (equal (read-buff buf) 5)))) + + +(ert-deftest initial-clear-does-not-affect-wrapping-around () + (let ((buf (create-test-buffer 2))) + (clear buf) + (write buf 1) + (write buf 2) + (overwrite buf 3) + (overwrite buf 4) + (should (equal (read-buff buf) 3)) + (should (equal (read-buff buf) 4)) + (should-error (read-buff buf) :type 'empty-buffer-error))) + + +(provide 'circular-buffer-test) +;;; circular-buffer-test.el ends here + diff --git a/exercises/practice/circular-buffer/circular-buffer.el b/exercises/practice/circular-buffer/circular-buffer.el new file mode 100644 index 00000000..4e680241 --- /dev/null +++ b/exercises/practice/circular-buffer/circular-buffer.el @@ -0,0 +1,19 @@ +;;; circular-buffer.el --- Circular Buffer (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(define-error 'empty-buffer-error + (error "Delete this S-Expression and write your own implementation")) + +(define-error 'full-buffer-error + (error "Delete this S-Expression and write your own implementation")) + +(defclass circular-buffer () + (error "Delete this S-Expression and write your own implementation")) + +(provide 'circular-buffer) +;;; circular-buffer.el ends here + From 6bbbe1515f6a44b5cb229a668284b661a5ab4cde Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Thu, 13 Jun 2024 08:35:36 -0500 Subject: [PATCH 105/162] add bank-account (#401) --- config.json | 8 + .../bank-account/.docs/instructions.md | 10 ++ .../bank-account/.docs/introduction.md | 20 +++ .../practice/bank-account/.meta/config.json | 17 +++ .../practice/bank-account/.meta/example.el | 94 ++++++++++++ .../practice/bank-account/.meta/tests.toml | 61 ++++++++ .../bank-account/bank-account-test.el | 142 ++++++++++++++++++ .../practice/bank-account/bank-account.el | 22 +++ 8 files changed, 374 insertions(+) create mode 100644 exercises/practice/bank-account/.docs/instructions.md create mode 100644 exercises/practice/bank-account/.docs/introduction.md create mode 100644 exercises/practice/bank-account/.meta/config.json create mode 100644 exercises/practice/bank-account/.meta/example.el create mode 100644 exercises/practice/bank-account/.meta/tests.toml create mode 100644 exercises/practice/bank-account/bank-account-test.el create mode 100644 exercises/practice/bank-account/bank-account.el diff --git a/config.json b/config.json index a8040b26..a1375fff 100644 --- a/config.json +++ b/config.json @@ -830,6 +830,14 @@ "practices": [], "prerequisites": [], "difficulty": 5 + }, + { + "slug": "bank-account", + "name": "Bank Account", + "uuid": "edc5fa4b-35b3-4313-b4c3-16153708f0ac", + "practices": [], + "prerequisites": [], + "difficulty": 8 } ] }, diff --git a/exercises/practice/bank-account/.docs/instructions.md b/exercises/practice/bank-account/.docs/instructions.md new file mode 100644 index 00000000..0955520b --- /dev/null +++ b/exercises/practice/bank-account/.docs/instructions.md @@ -0,0 +1,10 @@ +# Instructions + +Your task is to implement bank accounts supporting opening/closing, withdrawals, and deposits of money. + +As bank accounts can be accessed in many different ways (internet, mobile phones, automatic charges), your bank software must allow accounts to be safely accessed from multiple threads/processes (terminology depends on your programming language) in parallel. +For example, there may be many deposits and withdrawals occurring in parallel; you need to ensure there is no [race conditions][wikipedia] between when you read the account balance and set the new balance. + +It should be possible to close an account; operations against a closed account must fail. + +[wikipedia]: https://en.wikipedia.org/wiki/Race_condition#In_software diff --git a/exercises/practice/bank-account/.docs/introduction.md b/exercises/practice/bank-account/.docs/introduction.md new file mode 100644 index 00000000..650b5d9c --- /dev/null +++ b/exercises/practice/bank-account/.docs/introduction.md @@ -0,0 +1,20 @@ +# Introduction + +After years of filling out forms and waiting, you've finally acquired your banking license. +This means you are now officially eligible to open your own bank, hurray! + +Your first priority is to get the IT systems up and running. +After a day of hard work, you can already open and close accounts, as well as handle withdrawals and deposits. + +Since you couldn't be bothered writing tests, you invite some friends to help test the system. +However, after just five minutes, one of your friends claims they've lost money! +While you're confident your code is bug-free, you start looking through the logs to investigate. + +Ah yes, just as you suspected, your friend is at fault! +They shared their test credentials with another friend, and together they conspired to make deposits and withdrawals from the same account _in parallel_. +Who would do such a thing? + +While you argue that it's physically _impossible_ for someone to access their account in parallel, your friend smugly notifies you that the banking rules _require_ you to support this. +Thus, no parallel banking support, no go-live signal. +Sighing, you create a mental note to work on this tomorrow. +This will set your launch date back at _least_ one more day, but well... diff --git a/exercises/practice/bank-account/.meta/config.json b/exercises/practice/bank-account/.meta/config.json new file mode 100644 index 00000000..fef55850 --- /dev/null +++ b/exercises/practice/bank-account/.meta/config.json @@ -0,0 +1,17 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "bank-account.el" + ], + "test": [ + "bank-account-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Simulate a bank account supporting opening/closing, withdraws, and deposits of money. Watch out for concurrent transactions!" +} diff --git a/exercises/practice/bank-account/.meta/example.el b/exercises/practice/bank-account/.meta/example.el new file mode 100644 index 00000000..981aa6a9 --- /dev/null +++ b/exercises/practice/bank-account/.meta/example.el @@ -0,0 +1,94 @@ +;;; bank-account.el --- Bank Account (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'eieio) + +(define-error 'account-closed "account not open") +(define-error 'account-open "account already open") +(define-error 'account-overdraw "amount must be less than balance") +(define-error 'account-negative-transaction "amount must be greater than 0") + +(defclass bank-account () + ((open + :initarg :open + :initform nil + :type boolean + :documentation "Is the account open?") + (funds + :initarg :funds + :initform 0 + :type number + :documentation "Amount of funds in the account") + (lock + :initarg :lock + :initform (bank-account--make-semaphore) + :documentation "Semaphore lock for the account")) + "Class representing a bank account.") + +(defun bank-account--make-semaphore () + (list 0 (make-mutex))) + +(defun bank-account--semaphore-post (semaphore) + (let ((count (car semaphore)) + (mutex (cadr semaphore))) + (with-mutex mutex + (setcar semaphore (1+ count))))) + +(defun bank-account--semaphore-wait (semaphore) + (let ((count (car semaphore)) + (mutex (cadr semaphore))) + (with-mutex mutex + (while (<= count 0) + (setq count (car semaphore))) + (setcar semaphore (1- count))))) + +(cl-defmethod check-open ((account bank-account)) + (unless (oref account open) + (signal 'account-closed nil))) + +(cl-defmethod check-positive ((account bank-account) amount) + (unless (> amount 0) + (signal 'account-negative-transaction nil))) + +(cl-defmethod open-account ((account bank-account)) + (if (oref account open) + (signal 'account-open nil) + (oset account open t) + (oset account funds 0) + (bank-account--semaphore-post (oref account lock)))) + +(cl-defmethod close-account ((account bank-account)) + (check-open account) + (bank-account--semaphore-wait (oref account lock)) + (oset account open nil) + (bank-account--semaphore-post (oref account lock))) + +(cl-defmethod deposit ((account bank-account) amount) + (check-open account) + (check-positive account amount) + (bank-account--semaphore-wait (oref account lock)) + (oset account funds (+ (oref account funds) amount)) + (bank-account--semaphore-post (oref account lock))) + +(cl-defmethod withdraw ((account bank-account) amount) + (check-open account) + (check-positive account amount) + (if (> amount (oref account funds)) + (signal 'account-overdraw nil) + (bank-account--semaphore-wait (oref account lock)) + (oset account funds (- (oref account funds) amount)) + (bank-account--semaphore-post (oref account lock)))) + +(cl-defmethod balance ((account bank-account)) + (check-open account) + (oref account funds)) + +(defun make-new-bank-account () + (bank-account :open nil :funds 0 :lock (bank-account--make-semaphore))) + + +(provide 'bank-account) +;;; bank-account.el ends here diff --git a/exercises/practice/bank-account/.meta/tests.toml b/exercises/practice/bank-account/.meta/tests.toml new file mode 100644 index 00000000..4e42d4dc --- /dev/null +++ b/exercises/practice/bank-account/.meta/tests.toml @@ -0,0 +1,61 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[983a1528-4ceb-45e5-8257-8ce01aceb5ed] +description = "Newly opened account has zero balance" + +[e88d4ec3-c6bf-4752-8e59-5046c44e3ba7] +description = "Single deposit" + +[3d9147d4-63f4-4844-8d2b-1fee2e9a2a0d] +description = "Multiple deposits" + +[08f1af07-27ae-4b38-aa19-770bde558064] +description = "Withdraw once" + +[6f6d242f-8c31-4ac6-8995-a90d42cad59f] +description = "Withdraw twice" + +[45161c94-a094-4c77-9cec-998b70429bda] +description = "Can do multiple operations sequentially" + +[f9facfaa-d824-486e-8381-48832c4bbffd] +description = "Cannot check balance of closed account" + +[7a65ba52-e35c-4fd2-8159-bda2bde6e59c] +description = "Cannot deposit into closed account" + +[a0a1835d-faae-4ad4-a6f3-1fcc2121380b] +description = "Cannot deposit into unopened account" + +[570dfaa5-0532-4c1f-a7d3-0f65c3265608] +description = "Cannot withdraw from closed account" + +[c396d233-1c49-4272-98dc-7f502dbb9470] +description = "Cannot close an account that was not opened" + +[c06f534f-bdc2-4a02-a388-1063400684de] +description = "Cannot open an already opened account" + +[0722d404-6116-4f92-ba3b-da7f88f1669c] +description = "Reopened account does not retain balance" + +[ec42245f-9361-4341-8231-a22e8d19c52f] +description = "Cannot withdraw more than deposited" + +[4f381ef8-10ef-4507-8e1d-0631ecc8ee72] +description = "Cannot withdraw negative" + +[d45df9ea-1db0-47f3-b18c-d365db49d938] +description = "Cannot deposit negative" + +[ba0c1e0b-0f00-416f-8097-a7dfc97871ff] +description = "Can handle concurrent transactions" diff --git a/exercises/practice/bank-account/bank-account-test.el b/exercises/practice/bank-account/bank-account-test.el new file mode 100644 index 00000000..efc588d7 --- /dev/null +++ b/exercises/practice/bank-account/bank-account-test.el @@ -0,0 +1,142 @@ +;;; bank-account-test.el --- Bank Account (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "bank-account.el") + +(require 'eieio) + +(ert-deftest newly-opened-account-has-zero-balance () + (let ((account (make-new-bank-account))) + (open-account account) + (should (= (balance account) 0)))) + + +(ert-deftest single-deposit () + (let ((account (make-new-bank-account))) + (open-account account) + (deposit account 100) + (should (= (balance account) 100)))) + + +(ert-deftest multiple-deposits () + (let ((account (make-new-bank-account))) + (open-account account) + (deposit account 100) + (deposit account 50) + (should (= (balance account) 150)))) + + +(ert-deftest withdraw-once () + (let ((account (make-new-bank-account))) + (open-account account) + (deposit account 100) + (withdraw account 75) + (should (= (balance account) 25)))) + + +(ert-deftest withdraw-twice () + (let ((account (make-new-bank-account))) + (open-account account) + (deposit account 100) + (withdraw account 80) + (withdraw account 20) + (should (= (balance account) 0)))) + + +(ert-deftest can-do-multiple-operations-sequentially () + (let ((account (make-new-bank-account))) + (open-account account) + (deposit account 100) + (deposit account 110) + (withdraw account 200) + (deposit account 60) + (withdraw account 50) + (should (= (balance account) 20)))) + + +(ert-deftest cannot-check-balance-of-closed-account () + (let ((account (make-new-bank-account))) + (open-account account) + (close-account account) + (should-error (balance account) :type 'account-closed))) + + +(ert-deftest cannot-deposit-into-closed-account () + (let ((account (make-new-bank-account))) + (open-account account) + (close-account account) + (should-error (deposit account 50) :type 'account-closed))) + + +(ert-deftest cannot-deposit-into-unopened-account () + (let ((account (make-new-bank-account))) + (should-error (deposit account 50) :type 'account-closed))) + + +(ert-deftest cannot-withdraw-from-closed-account () + (let ((account (make-new-bank-account))) + (open-account account) + (close-account account) + (should-error (withdraw account 50) :type 'account-closed))) + + +(ert-deftest cannot-close-an-account-that-was-not-opened () + (let ((account (make-new-bank-account))) + (should-error (close-account account) :type 'account-closed))) + + +(ert-deftest cannot-open-an-already-opened-account () + (let ((account (make-new-bank-account))) + (open-account account) + (should-error (open-account account) :type 'account-open))) + + +(ert-deftest reopened-account-does-not-retain-balance () + (let ((account (make-new-bank-account))) + (open-account account) + (deposit account 50) + (close-account account) + (open-account account) + (should (= (balance account) 0)))) + + +(ert-deftest cannot-withdraw-more-than-deposited () + (let ((account (make-new-bank-account))) + (open-account account) + (deposit account 25) + (should-error (withdraw account 50) :type 'account-overdraw))) + + +(ert-deftest cannot-withdraw-negative () + (let ((account (make-new-bank-account))) + (open-account account) + (deposit account 100) + (should-error (withdraw account -50) :type 'account-negative-transaction))) + + +(ert-deftest cannot-deposit-negative () + (let ((account (make-new-bank-account))) + (open-account account) + (should-error (deposit account -50) :type 'account-negative-transaction))) + + +(ert-deftest can-handle-concurrent-transactions () + (let ((account (make-new-bank-account))) + (open-account account) + (defun concurrent-operation () + (deposit account 1) + (withdraw account 1)) + (let ((threads ())) + (dotimes (_ 1000) + (push (make-thread #'concurrent-operation) threads)) + (dolist (thread threads) + (thread-join thread))) + (should (= (balance account ) 0)))) + + +(provide 'bank-account-test) +;;; bank-account-test.el ends here diff --git a/exercises/practice/bank-account/bank-account.el b/exercises/practice/bank-account/bank-account.el new file mode 100644 index 00000000..d62e3211 --- /dev/null +++ b/exercises/practice/bank-account/bank-account.el @@ -0,0 +1,22 @@ +;;; bank-account.el --- Bank Account (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(define-error 'account-closed + (error "Delete this S-Expression and write your own implementation")) +(define-error 'account-open + (error "Delete this S-Expression and write your own implementation")) +(define-error 'account-overdraw + (error "Delete this S-Expression and write your own implementation")) +(define-error 'account-negative-transaction + (error "Delete this S-Expression and write your own implementation")) + +(defclass bank-account (operations) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'bank-account) +;;; bank-account.el ends here From b21ffaa634121c4230b78547f0ce05d5a4bd2a71 Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Fri, 14 Jun 2024 12:21:56 -0500 Subject: [PATCH 106/162] add yacht (#406) --- config.json | 8 ++ .../practice/yacht/.docs/instructions.md | 30 ++++ .../practice/yacht/.docs/introduction.md | 11 ++ exercises/practice/yacht/.meta/config.json | 19 +++ exercises/practice/yacht/.meta/example.el | 58 ++++++++ exercises/practice/yacht/.meta/tests.toml | 97 +++++++++++++ exercises/practice/yacht/yacht-test.el | 129 ++++++++++++++++++ exercises/practice/yacht/yacht.el | 14 ++ 8 files changed, 366 insertions(+) create mode 100644 exercises/practice/yacht/.docs/instructions.md create mode 100644 exercises/practice/yacht/.docs/introduction.md create mode 100644 exercises/practice/yacht/.meta/config.json create mode 100644 exercises/practice/yacht/.meta/example.el create mode 100644 exercises/practice/yacht/.meta/tests.toml create mode 100644 exercises/practice/yacht/yacht-test.el create mode 100644 exercises/practice/yacht/yacht.el diff --git a/config.json b/config.json index a1375fff..68294d3c 100644 --- a/config.json +++ b/config.json @@ -838,6 +838,14 @@ "practices": [], "prerequisites": [], "difficulty": 8 + }, + { + "slug": "yacht", + "name": "Yacht", + "uuid": "5d06fd6e-2ca7-425d-a3dd-892cb3f7bf65", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, diff --git a/exercises/practice/yacht/.docs/instructions.md b/exercises/practice/yacht/.docs/instructions.md new file mode 100644 index 00000000..519b7a68 --- /dev/null +++ b/exercises/practice/yacht/.docs/instructions.md @@ -0,0 +1,30 @@ +# Instructions + +Given five dice and a category, calculate the score of the dice for that category. + +~~~~exercism/note +You'll always be presented with five dice. +Each dice's value will be between one and six inclusively. +The dice may be unordered. +~~~~ + +## Scores in Yacht + +| Category | Score | Description | Example | +| --------------- | ---------------------- | ---------------------------------------- | ------------------- | +| Ones | 1 × number of ones | Any combination | 1 1 1 4 5 scores 3 | +| Twos | 2 × number of twos | Any combination | 2 2 3 4 5 scores 4 | +| Threes | 3 × number of threes | Any combination | 3 3 3 3 3 scores 15 | +| Fours | 4 × number of fours | Any combination | 1 2 3 3 5 scores 0 | +| Fives | 5 × number of fives | Any combination | 5 1 5 2 5 scores 15 | +| Sixes | 6 × number of sixes | Any combination | 2 3 4 5 6 scores 6 | +| Full House | Total of the dice | Three of one number and two of another | 3 3 3 5 5 scores 19 | +| Four of a Kind | Total of the four dice | At least four dice showing the same face | 4 4 4 4 6 scores 16 | +| Little Straight | 30 points | 1-2-3-4-5 | 1 2 3 4 5 scores 30 | +| Big Straight | 30 points | 2-3-4-5-6 | 2 3 4 5 6 scores 30 | +| Choice | Sum of the dice | Any combination | 2 3 3 4 6 scores 18 | +| Yacht | 50 points | All five dice showing the same face | 4 4 4 4 4 scores 50 | + +If the dice do **not** satisfy the requirements of a category, the score is zero. +If, for example, _Four Of A Kind_ is entered in the _Yacht_ category, zero points are scored. +A _Yacht_ scores zero if entered in the _Full House_ category. diff --git a/exercises/practice/yacht/.docs/introduction.md b/exercises/practice/yacht/.docs/introduction.md new file mode 100644 index 00000000..5b541f56 --- /dev/null +++ b/exercises/practice/yacht/.docs/introduction.md @@ -0,0 +1,11 @@ +# Introduction + +Each year, something new is "all the rage" in your high school. +This year it is a dice game: [Yacht][yacht]. + +The game of Yacht is from the same family as Poker Dice, Generala and particularly Yahtzee, of which it is a precursor. +The game consists of twelve rounds. +In each, five dice are rolled and the player chooses one of twelve categories. +The chosen category is then used to score the throw of the dice. + +[yacht]: https://en.wikipedia.org/wiki/Yacht_(dice_game) diff --git a/exercises/practice/yacht/.meta/config.json b/exercises/practice/yacht/.meta/config.json new file mode 100644 index 00000000..16bd1671 --- /dev/null +++ b/exercises/practice/yacht/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "yacht.el" + ], + "test": [ + "yacht-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Score a single throw of dice in the game Yacht.", + "source": "James Kilfiger, using Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Yacht_(dice_game)" +} diff --git a/exercises/practice/yacht/.meta/example.el b/exercises/practice/yacht/.meta/example.el new file mode 100644 index 00000000..b939ed4e --- /dev/null +++ b/exercises/practice/yacht/.meta/example.el @@ -0,0 +1,58 @@ +;;; yacht.el --- Yacht (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun hash-values (ht) + (let (vals) + (maphash (lambda (_ v) (push v vals)) ht) + (reverse vals))) + +(defun frequencies (sequence) + (let ((occurrences (make-hash-table :test 'equal))) + (dolist (n sequence) + (puthash n (1+ (gethash n occurrences 0)) occurrences)) + occurrences)) + +(defun full-house (occurrences) + (let ((vals (sort (hash-values occurrences) #'<))) + (equal vals '(2 3)))) + +(defun four-of-a-kind-dice (occurrences) + (let (pair) + (maphash (lambda (key val) + (when (>= val 4) + (setq pair key))) + occurrences) + pair)) + +(defun score (scores category) + (pcase category + (:ones (cl-count 1 scores)) + (:twos (* 2 (cl-count 2 scores))) + (:threes (* 3 (cl-count 3 scores))) + (:fours (* 4 (cl-count 4 scores))) + (:fives (* 5 (cl-count 5 scores))) + (:sixes (* 6 (cl-count 6 scores))) + (:full-house (if (full-house (frequencies scores)) + (cl-reduce '+ scores) + 0)) + (:four-of-a-kind (let ((dice (four-of-a-kind-dice (frequencies scores)))) + (if dice (* 4 dice) 0))) + (:little-straight (if (equal '(1 2 3 4 5) (sort scores #'<)) + 30 + 0)) + (:big-straight (if (equal '(2 3 4 5 6) (sort scores #'<)) + 30 + 0)) + (:choice (cl-reduce '+ scores)) + (:yacht (if (= 1 (hash-table-count (frequencies scores))) + 50 + 0)) + (_ 0))) + + +(provide 'yacht) +;;; yacht.el ends here diff --git a/exercises/practice/yacht/.meta/tests.toml b/exercises/practice/yacht/.meta/tests.toml new file mode 100644 index 00000000..b9d92037 --- /dev/null +++ b/exercises/practice/yacht/.meta/tests.toml @@ -0,0 +1,97 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[3060e4a5-4063-4deb-a380-a630b43a84b6] +description = "Yacht" + +[15026df2-f567-482f-b4d5-5297d57769d9] +description = "Not Yacht" + +[36b6af0c-ca06-4666-97de-5d31213957a4] +description = "Ones" + +[023a07c8-6c6e-44d0-bc17-efc5e1b8205a] +description = "Ones, out of order" + +[7189afac-cccd-4a74-8182-1cb1f374e496] +description = "No ones" + +[793c4292-dd14-49c4-9707-6d9c56cee725] +description = "Twos" + +[dc41bceb-d0c5-4634-a734-c01b4233a0c6] +description = "Fours" + +[f6125417-5c8a-4bca-bc5b-b4b76d0d28c8] +description = "Yacht counted as threes" + +[464fc809-96ed-46e4-acb8-d44e302e9726] +description = "Yacht of 3s counted as fives" + +[d054227f-3a71-4565-a684-5c7e621ec1e9] +description = "Fives" + +[e8a036e0-9d21-443a-8b5f-e15a9e19a761] +description = "Sixes" + +[51cb26db-6b24-49af-a9ff-12f53b252eea] +description = "Full house two small, three big" + +[1822ca9d-f235-4447-b430-2e8cfc448f0c] +description = "Full house three small, two big" + +[b208a3fc-db2e-4363-a936-9e9a71e69c07] +description = "Two pair is not a full house" + +[b90209c3-5956-445b-8a0b-0ac8b906b1c2] +description = "Four of a kind is not a full house" + +[32a3f4ee-9142-4edf-ba70-6c0f96eb4b0c] +description = "Yacht is not a full house" + +[b286084d-0568-4460-844a-ba79d71d79c6] +description = "Four of a Kind" + +[f25c0c90-5397-4732-9779-b1e9b5f612ca] +description = "Yacht can be scored as Four of a Kind" + +[9f8ef4f0-72bb-401a-a871-cbad39c9cb08] +description = "Full house is not Four of a Kind" + +[b4743c82-1eb8-4a65-98f7-33ad126905cd] +description = "Little Straight" + +[7ac08422-41bf-459c-8187-a38a12d080bc] +description = "Little Straight as Big Straight" + +[97bde8f7-9058-43ea-9de7-0bc3ed6d3002] +description = "Four in order but not a little straight" + +[cef35ff9-9c5e-4fd2-ae95-6e4af5e95a99] +description = "No pairs but not a little straight" + +[fd785ad2-c060-4e45-81c6-ea2bbb781b9d] +description = "Minimum is 1, maximum is 5, but not a little straight" + +[35bd74a6-5cf6-431a-97a3-4f713663f467] +description = "Big Straight" + +[87c67e1e-3e87-4f3a-a9b1-62927822b250] +description = "Big Straight as little straight" + +[c1fa0a3a-40ba-4153-a42d-32bc34d2521e] +description = "No pairs but not a big straight" + +[207e7300-5d10-43e5-afdd-213e3ac8827d] +description = "Choice" + +[b524c0cf-32d2-4b40-8fb3-be3500f3f135] +description = "Yacht as choice" diff --git a/exercises/practice/yacht/yacht-test.el b/exercises/practice/yacht/yacht-test.el new file mode 100644 index 00000000..f0cd72bc --- /dev/null +++ b/exercises/practice/yacht/yacht-test.el @@ -0,0 +1,129 @@ +;;; yacht-test.el --- Yacht (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "yacht.el") +(declare-function score "yacht.el" (scores category)) + + +(ert-deftest yacht () + (should (equal (score '(5 5 5 5 5) :yacht) 50))) + + +(ert-deftest not-yacht () + (should (equal (score '(1 3 3 2 5) :yacht) 0))) + + +(ert-deftest ones () + (should (equal (score '(1 1 1 3 5) :ones) 3))) + + +(ert-deftest ones-out-of-order () + (should (equal (score '(3 1 1 5 1) :ones) 3))) + + +(ert-deftest no-ones () + (should (equal (score '(4 3 6 5 5) :ones) 0))) + + +(ert-deftest twos () + (should (equal (score '(2 3 4 5 6) :twos) 2))) + + +(ert-deftest fours () + (should (equal (score '(1 4 1 4 1) :fours) 8))) + + +(ert-deftest yacht-counted-as-threes () + (should (equal (score '(3 3 3 3 3) :threes) 15))) + + +(ert-deftest yacht-of-3s-counted-as-fives () + (should (equal (score '(3 3 3 3 3) :fives) 0))) + + +(ert-deftest fives () + (should (equal (score '(1 5 3 5 3) :fives) 10))) + + +(ert-deftest sixes () + (should (equal (score '(2 3 4 5 6) :sixes) 6))) + + +(ert-deftest full-house-two-small-three-big () + (should (equal (score '(2 2 4 4 4) :full-house) 16))) + + +(ert-deftest full-house-three-small-two-big () + (should (equal (score '(5 3 3 5 3) :full-house) 19))) + + +(ert-deftest two-pair-is-not-a-full-house () + (should (equal (score '(2 2 4 4 5) :full-house) 0))) + + +(ert-deftest four-of-a-kind-is-not-a-full-house () + (should (equal (score '(1 4 4 4 4) :full-house) 0))) + + +(ert-deftest yacht-is-not-a-full-house () + (should (equal (score '(2 2 2 2 2) :full-house) 0))) + + +(ert-deftest four-of-a-kind () + (should (equal (score '(6 6 4 6 6) :four-of-a-kind) 24))) + + +(ert-deftest yacht-can-be-scored-as-four-of-a-kind () + (should (equal (score '(3 3 3 3 3 ) :four-of-a-kind) 12))) + + +(ert-deftest full-house-is-not-four-of-a-kind () + (should (equal (score '(3 3 3 5 5) :four-of-a-kind) 0))) + + +(ert-deftest little-straight () + (should (equal (score '(3 5 4 1 2) :little-straight) 30))) + + +(ert-deftest little-straight-as-big-straight () + (should (equal (score '(1 2 3 4 5) :big-straight) 0))) + + +(ert-deftest four-in-order-but-not-a-little-straight () + (should (equal (score '(1 1 2 3 4) :little-straight) 0))) + + +(ert-deftest no-pairs-but-not-a-little-straight () + (should (equal (score '(1 2 3 4 6) :little-straight) 0))) + + +(ert-deftest minimum-is-1-maximum-is-5-but-not-a-little-straight () + (should (equal (score '(1 1 3 4 5) :little-straight) 0))) + + +(ert-deftest big-straight () + (should (equal (score '(4 6 2 5 3) :big-straight) 30))) + + +(ert-deftest big-straight-as-little-straight () + (should (equal (score '(6 5 4 3 2) :little-straight) 0))) + + +(ert-deftest no-pairs-but-not-a-big-straight () + (should (equal (score '(6 5 4 3 1) :big-straight) 0))) + + +(ert-deftest choice () + (should (equal (score '(3 3 5 6 6) :choice) 23))) + + +(ert-deftest yacht-as-choice () + (should (equal (score '(2 2 2 2 2) :choice) 10))) + + +(provide 'yacht-test) +;;; yacht-test.el ends here diff --git a/exercises/practice/yacht/yacht.el b/exercises/practice/yacht/yacht.el new file mode 100644 index 00000000..09a5dc92 --- /dev/null +++ b/exercises/practice/yacht/yacht.el @@ -0,0 +1,14 @@ +;;; yacht.el --- Yacht (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun score (scores category) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'yacht) +;;; yacht.el ends here + From ef5dce3cdf6b627edd0741642511f32d449a4b21 Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Fri, 14 Jun 2024 19:31:20 -0500 Subject: [PATCH 107/162] add accumulate exercise (#407) --- config.json | 8 ++++ .../practice/accumulate/.docs/instructions.md | 22 ++++++++++ .../practice/accumulate/.meta/config.json | 19 ++++++++ .../practice/accumulate/.meta/example.el | 15 +++++++ .../practice/accumulate/.meta/tests.toml | 30 +++++++++++++ .../practice/accumulate/accumulate-test.el | 43 +++++++++++++++++++ exercises/practice/accumulate/accumulate.el | 13 ++++++ 7 files changed, 150 insertions(+) create mode 100644 exercises/practice/accumulate/.docs/instructions.md create mode 100644 exercises/practice/accumulate/.meta/config.json create mode 100644 exercises/practice/accumulate/.meta/example.el create mode 100644 exercises/practice/accumulate/.meta/tests.toml create mode 100644 exercises/practice/accumulate/accumulate-test.el create mode 100644 exercises/practice/accumulate/accumulate.el diff --git a/config.json b/config.json index 68294d3c..cb944adc 100644 --- a/config.json +++ b/config.json @@ -846,6 +846,14 @@ "practices": [], "prerequisites": [], "difficulty": 5 + }, + { + "slug": "accumulate", + "name": "Accumulate", + "uuid": "093463bf-e8df-4dd9-b6e3-b5ec007cb781", + "practices": [], + "prerequisites": [], + "difficulty": 2 } ] }, diff --git a/exercises/practice/accumulate/.docs/instructions.md b/exercises/practice/accumulate/.docs/instructions.md new file mode 100644 index 00000000..c25a03fa --- /dev/null +++ b/exercises/practice/accumulate/.docs/instructions.md @@ -0,0 +1,22 @@ +# Instructions + +Implement the `accumulate` operation, which, given a collection and an operation to perform on each element of the collection, returns a new collection containing the result of applying that operation to each element of the input collection. + +Given the collection of numbers: + +- 1, 2, 3, 4, 5 + +And the operation: + +- square a number (`x => x * x`) + +Your code should be able to produce the collection of squares: + +- 1, 4, 9, 16, 25 + +Check out the test suite to see the expected function signature. + +## Restrictions + +Keep your hands off that collect/map/fmap/whatchamacallit functionality provided by your standard library! +Solve this one yourself using other basic tools instead. diff --git a/exercises/practice/accumulate/.meta/config.json b/exercises/practice/accumulate/.meta/config.json new file mode 100644 index 00000000..884c92ba --- /dev/null +++ b/exercises/practice/accumulate/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "accumulate.el" + ], + "test": [ + "accumulate-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Implement the `accumulate` operation, which, given a collection and an operation to perform on each element of the collection, returns a new collection containing the result of applying that operation to each element of the input collection.", + "source": "Conversation with James Edward Gray II", + "source_url": "http://graysoftinc.com/" +} diff --git a/exercises/practice/accumulate/.meta/example.el b/exercises/practice/accumulate/.meta/example.el new file mode 100644 index 00000000..b0c8d080 --- /dev/null +++ b/exercises/practice/accumulate/.meta/example.el @@ -0,0 +1,15 @@ +;;; accumulate.el --- Accumulate (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun accumulate (lst op) + (cond + ((null lst) lst) + (t (cons (funcall op (car lst)) (accumulate (cdr lst) op))))) + + +(provide 'accumulate) +;;; accumulate.el ends here diff --git a/exercises/practice/accumulate/.meta/tests.toml b/exercises/practice/accumulate/.meta/tests.toml new file mode 100644 index 00000000..d7858e07 --- /dev/null +++ b/exercises/practice/accumulate/.meta/tests.toml @@ -0,0 +1,30 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[64d97c14-36dd-44a8-9621-2cecebd6ed23] +description = "accumulate empty" + +[00008ed2-4651-4929-8c08-8b4dbd70872e] +description = "accumulate squares" + +[551016da-4396-4cae-b0ec-4c3a1a264125] +description = "accumulate upcases" + +[cdf95597-b6ec-4eac-a838-3480d13d0d05] +description = "accumulate reversed strings" + +[bee8e9b6-b16f-4cd2-be3b-ccf7457e50bb] +description = "accumulate recursively" +include = false + +[0b357334-4cad-49e1-a741-425202edfc7c] +description = "accumulate recursively" +reimplements = "bee8e9b6-b16f-4cd2-be3b-ccf7457e50bb" diff --git a/exercises/practice/accumulate/accumulate-test.el b/exercises/practice/accumulate/accumulate-test.el new file mode 100644 index 00000000..25a8dc6b --- /dev/null +++ b/exercises/practice/accumulate/accumulate-test.el @@ -0,0 +1,43 @@ +;;; accumulate-test.el --- Accumulate (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "accumulate.el") +(declare-function accumulate "accumulate.el" (lst op)) + + +(ert-deftest accumulate-empty () + (let ((result (accumulate '() (lambda (x) (* x x))))) + (should (equal result '())))) + + +(ert-deftest accumulate-square () + (let ((result (accumulate '(1 2 3 4) (lambda (x) (* x x))))) + (should (equal result '(1 4 9 16))))) + + +(ert-deftest accumulate-upcases () + (let ((result (accumulate '("Hello" "world") 'upcase))) + (should (equal result '("HELLO" "WORLD"))))) + + +(ert-deftest accumulate-reversed-strings () + (let ((result (accumulate '("the" "quick" "brown" "fox" "etc") (lambda (x) (apply #'string (reverse (string-to-list x))))))) + (should (equal result '("eht" "kciuq" "nworb" "xof" "cte"))))) + + +(ert-deftest accumulate-recursively () + (let* ((inner-list '("1" "2" "3")) + (result (accumulate '("a" "b" "c") + (lambda (x) + (mapcar (lambda (y) (concat x y)) inner-list))))) + (should (equal result '(("a1" "a2" "a3") + ("b1" "b2" "b3") + ("c1" "c2" "c3")))))) + + +(provide 'accumulate-test) +;;; accumulate-test.el ends here diff --git a/exercises/practice/accumulate/accumulate.el b/exercises/practice/accumulate/accumulate.el new file mode 100644 index 00000000..098d060d --- /dev/null +++ b/exercises/practice/accumulate/accumulate.el @@ -0,0 +1,13 @@ +;;; accumulate.el --- Accumulate (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun accumulate (lst op) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'accumulate) +;;; accumulate.el ends here From 787cfaaf6620a042b6299b658620da4f5157fa8c Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Fri, 14 Jun 2024 19:48:57 -0500 Subject: [PATCH 108/162] fix [Improve Practice Exercise] Atbash Cipher #386 (#403) --- .../practice/atbash-cipher/.meta/config.json | 3 +- .../practice/atbash-cipher/.meta/example.el | 4 +++ .../atbash-cipher/atbash-cipher-test.el | 36 ++++++++++++++----- .../practice/atbash-cipher/atbash-cipher.el | 6 ++++ 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/exercises/practice/atbash-cipher/.meta/config.json b/exercises/practice/atbash-cipher/.meta/config.json index 1c24ea9a..7bcaa351 100644 --- a/exercises/practice/atbash-cipher/.meta/config.json +++ b/exercises/practice/atbash-cipher/.meta/config.json @@ -3,7 +3,8 @@ "canweriotnow" ], "contributors": [ - "vermiculus" + "vermiculus", + "kmarker1101" ], "files": { "solution": [ diff --git a/exercises/practice/atbash-cipher/.meta/example.el b/exercises/practice/atbash-cipher/.meta/example.el index a133fcf4..3fb8eaba 100644 --- a/exercises/practice/atbash-cipher/.meta/example.el +++ b/exercises/practice/atbash-cipher/.meta/example.el @@ -12,6 +12,10 @@ "Encode PLAINTEXT to atbash-cipher encoding." (to-string (group (to-cipher-seq plaintext)))) +(defun decode (ciphertext) + "Decode CIPHERTEXT from atbash-cipher encoding." + (to-string (cleanup-ciphered-seq (cl-map 'list #'encipher ciphertext)))) + (defun to-string (seq) "Convert SEQ of characters to a string." (cl-concatenate 'string seq)) diff --git a/exercises/practice/atbash-cipher/atbash-cipher-test.el b/exercises/practice/atbash-cipher/atbash-cipher-test.el index 01f449ab..d923ba50 100644 --- a/exercises/practice/atbash-cipher/atbash-cipher-test.el +++ b/exercises/practice/atbash-cipher/atbash-cipher-test.el @@ -7,37 +7,57 @@ (require 'cl-lib) (load-file "atbash-cipher.el") + (declare-function encode "atbash-cipher.el" (plaintext)) +(declare-function decode "atbash-cipher.el" (plaintext)) (ert-deftest encode-no () - (should (equal "ml" (encode "no")))) + (should (string= "ml" (encode "no")))) (ert-deftest encode-yes () - (should (equal "bvh" (encode "yes")))) + (should (string= "bvh" (encode "yes")))) (ert-deftest encode-OMG () - (should (equal "lnt" (encode "OMG")))) + (should (string= "lnt" (encode "OMG")))) (ert-deftest encode-O-M-G () - (should (equal "lnt" (encode "O M G")))) + (should (string= "lnt" (encode "O M G")))) (ert-deftest encode-long-word () - (should (equal "nrmwy oldrm tob" + (should (string= "nrmwy oldrm tob" (encode "mindblowingly")))) (ert-deftest encode-numbers () - (should (equal "gvhgr mt123 gvhgr mt" + (should (string= "gvhgr mt123 gvhgr mt" (encode "Testing, 1 2 3, testing.")))) (ert-deftest encode-sentence () - (should (equal "gifgs rhurx grlm" + (should (string= "gifgs rhurx grlm" (encode "Truth is fiction.")))) (ert-deftest encode-all-the-things () (let ((plaintext "The quick brown fox jumps over the lazy dog.") (ciphertext "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt")) - (should (equal ciphertext + (should (string= ciphertext (encode plaintext))))) +(ert-deftest decode-exercism () + (should (string= "exercism" (decode "vcvix rhn")))) + +(ert-deftest decode-a-sentence () + (should (string= "anobstacleisoftenasteppingstone" (decode "zmlyh gzxov rhlug vmzhg vkkrm thglm v")))) + +(ert-deftest decode-numbers () + (should (string= "testing123testing" (decode "gvhgr mt123 gvhgr mt")))) + +(ert-deftest decode-all-the-letters () + (should (string= "thequickbrownfoxjumpsoverthelazydog" (decode "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt")))) + +(ert-deftest decode-with-two-many-spaces () + (should (string= "exercism" (decode "vc vix r hn")))) + +(ert-deftest decode-with-no-spaces () + (should (string= "anobstacleisoftenasteppingstone" (decode "zmlyhgzxovrhlugvmzhgvkkrmthglmv")))) + (provide 'atbash-cipher-test) ;;; atbash-cipher-test.el ends here diff --git a/exercises/practice/atbash-cipher/atbash-cipher.el b/exercises/practice/atbash-cipher/atbash-cipher.el index 3017d19d..e2148961 100644 --- a/exercises/practice/atbash-cipher/atbash-cipher.el +++ b/exercises/practice/atbash-cipher/atbash-cipher.el @@ -7,5 +7,11 @@ ;;; Code: ) +(defun decode (plaintext) + "Decode atbash-cipher encoding to PLAINTEXT." + ;;; Code: +) + + (provide 'atbash-cipher) ;;; atbash-cipher.el ends here From 4d947868fc0813a39b1f28c154963f43ff9b8933 Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Sun, 16 Jun 2024 09:34:51 -0500 Subject: [PATCH 109/162] update docs fix #364 (#411) --- .../bank-account/.docs/instructions.md | 2 +- .../resistor-color-duo/.docs/instructions.md | 2 +- .../scrabble-score/.docs/instructions.md | 47 +++++++------------ .../scrabble-score/.docs/introduction.md | 7 +++ .../spiral-matrix/.docs/instructions.md | 2 +- .../spiral-matrix/.docs/introduction.md | 11 +++++ 6 files changed, 37 insertions(+), 34 deletions(-) create mode 100644 exercises/practice/scrabble-score/.docs/introduction.md create mode 100644 exercises/practice/spiral-matrix/.docs/introduction.md diff --git a/exercises/practice/bank-account/.docs/instructions.md b/exercises/practice/bank-account/.docs/instructions.md index 0955520b..7398fbea 100644 --- a/exercises/practice/bank-account/.docs/instructions.md +++ b/exercises/practice/bank-account/.docs/instructions.md @@ -3,7 +3,7 @@ Your task is to implement bank accounts supporting opening/closing, withdrawals, and deposits of money. As bank accounts can be accessed in many different ways (internet, mobile phones, automatic charges), your bank software must allow accounts to be safely accessed from multiple threads/processes (terminology depends on your programming language) in parallel. -For example, there may be many deposits and withdrawals occurring in parallel; you need to ensure there is no [race conditions][wikipedia] between when you read the account balance and set the new balance. +For example, there may be many deposits and withdrawals occurring in parallel; you need to ensure there are no [race conditions][wikipedia] between when you read the account balance and set the new balance. It should be possible to close an account; operations against a closed account must fail. diff --git a/exercises/practice/resistor-color-duo/.docs/instructions.md b/exercises/practice/resistor-color-duo/.docs/instructions.md index bdcd549b..18ee4078 100644 --- a/exercises/practice/resistor-color-duo/.docs/instructions.md +++ b/exercises/practice/resistor-color-duo/.docs/instructions.md @@ -29,5 +29,5 @@ The band colors are encoded as follows: - White: 9 From the example above: -brown-green should return 15 +brown-green should return 15, and brown-green-violet should return 15 too, ignoring the third color. diff --git a/exercises/practice/scrabble-score/.docs/instructions.md b/exercises/practice/scrabble-score/.docs/instructions.md index 3f986c94..738f928c 100644 --- a/exercises/practice/scrabble-score/.docs/instructions.md +++ b/exercises/practice/scrabble-score/.docs/instructions.md @@ -1,40 +1,25 @@ # Instructions -Given a word, compute the Scrabble score for that word. +Your task is to compute a word's Scrabble score by summing the values of its letters. -## Letter Values +The letters are valued as follows: -You'll need these: +| Letter | Value | +| ---------------------------- | ----- | +| A, E, I, O, U, L, N, R, S, T | 1 | +| D, G | 2 | +| B, C, M, P | 3 | +| F, H, V, W, Y | 4 | +| K | 5 | +| J, X | 8 | +| Q, Z | 10 | -```text -Letter Value -A, E, I, O, U, L, N, R, S, T 1 -D, G 2 -B, C, M, P 3 -F, H, V, W, Y 4 -K 5 -J, X 8 -Q, Z 10 -``` - -## Examples - -"cabbage" should be scored as worth 14 points: +For example, the word "cabbage" is worth 14 points: - 3 points for C -- 1 point for A, twice -- 3 points for B, twice +- 1 point for A +- 3 points for B +- 3 points for B +- 1 point for A - 2 points for G - 1 point for E - -And to total: - -- `3 + 2*1 + 2*3 + 2 + 1` -- = `3 + 2 + 6 + 3` -- = `5 + 9` -- = 14 - -## Extensions - -- You can play a double or a triple letter. -- You can play a double or a triple word. diff --git a/exercises/practice/scrabble-score/.docs/introduction.md b/exercises/practice/scrabble-score/.docs/introduction.md new file mode 100644 index 00000000..8821f240 --- /dev/null +++ b/exercises/practice/scrabble-score/.docs/introduction.md @@ -0,0 +1,7 @@ +# Introduction + +[Scrabble][wikipedia] is a word game where players place letter tiles on a board to form words. +Each letter has a value. +A word's score is the sum of its letters' values. + +[wikipedia]: https://en.wikipedia.org/wiki/Scrabble diff --git a/exercises/practice/spiral-matrix/.docs/instructions.md b/exercises/practice/spiral-matrix/.docs/instructions.md index ba99e12c..01e8a77f 100644 --- a/exercises/practice/spiral-matrix/.docs/instructions.md +++ b/exercises/practice/spiral-matrix/.docs/instructions.md @@ -1,6 +1,6 @@ # Instructions -Given the size, return a square matrix of numbers in spiral order. +Your task is to return a square matrix of a given size. The matrix should be filled with natural numbers, starting from 1 in the top-left corner, increasing in an inward, clockwise spiral order, like these examples: diff --git a/exercises/practice/spiral-matrix/.docs/introduction.md b/exercises/practice/spiral-matrix/.docs/introduction.md new file mode 100644 index 00000000..25c7eb59 --- /dev/null +++ b/exercises/practice/spiral-matrix/.docs/introduction.md @@ -0,0 +1,11 @@ +# Introduction + +In a small village near an ancient forest, there was a legend of a hidden treasure buried deep within the woods. +Despite numerous attempts, no one had ever succeeded in finding it. +This was about to change, however, thanks to a young explorer named Elara. +She had discovered an old document containing instructions on how to locate the treasure. +Using these instructions, Elara was able to draw a map that revealed the path to the treasure. + +To her surprise, the path followed a peculiar clockwise spiral. +It was no wonder no one had been able to find the treasure before! +With the map in hand, Elara embarks on her journey to uncover the hidden treasure. From f6df3347f67272784debf5de4ef2a10312935ffd Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:32:51 +0200 Subject: [PATCH 110/162] Run CI jobs on Ubuntu 24.04 (#410) --- .github/workflows/ci.yml | 2 +- .github/workflows/configlet-sync.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20ba2a9b..782c71c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ on: jobs: ci: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: purcell/setup-emacs@c851e5408f2d2f657fa80375bbe3fb35029aa488 diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index 4274bdd1..5fe9728b 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -9,7 +9,7 @@ jobs: configlet: if: github.repository_owner == 'exercism' # Stops this job from running on forks timeout-minutes: 30 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.0.0 From 8c8a50cbebd95d6aa42c7d5eb872ce17a3850861 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:33:51 +0200 Subject: [PATCH 111/162] `bin/test-examples`: Copy instead of move to make script idempotent (#409) Executing this script locally required a `git reset` after execution without this change. --- bin/test-examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/test-examples b/bin/test-examples index ee25cba5..5d2c1236 100755 --- a/bin/test-examples +++ b/bin/test-examples @@ -12,7 +12,7 @@ pushd exercises/practice > /dev/null for exercise in *; do pushd $exercise mv "${exercise}.el" "${exercise}.el.bak" - mv .meta/example.el "${exercise}.el" + cp .meta/example.el "${exercise}.el" emacs -batch -l ert -l "${exercise}-test.el" -f ert-run-tests-batch-and-exit let "err_cnt += $?" mv "${exercise}.el.bak" "${exercise}.el" From d89d711fe5ed56a6d69b42cd7cbd4b4df7c49c9a Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Sun, 16 Jun 2024 19:05:59 +0200 Subject: [PATCH 112/162] Upgrade CI test run to Emacs 29.3 (#408) * Upgrade CI test run to Emacs 29.3 * Fix failing tests because ERT now fails when redefining tests > *** Redefining an ERT test in batch mode now signals an error. > Executing 'ert-deftest' with the same name as an existing test causes > the previous definition to be discarded, which was probably not > intended when this occurs in batch mode. To remedy the error, rename > tests so that they all have unique names. - https://github.com/emacs-mirror/emacs/blob/2c201bbba5c43328979bf139330684cacfa074f3/etc/NEWS.29#L933-L937 --- .github/workflows/ci.yml | 2 +- README.md | 2 +- exercises/practice/triangle/triangle-test.el | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 782c71c8..965e6e63 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: purcell/setup-emacs@c851e5408f2d2f657fa80375bbe3fb35029aa488 with: - version: 28.2 + version: 29.3 - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.0.0 diff --git a/README.md b/README.md index 1ce0bbe6..64f4b532 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This repo holds all the instructions, tests, code, & support files for Emacs Lisp _exercises_ currently under development or implemented & available for students. If you haven't already, you can check out and study the live language track [here][exercism-emacs-lisp-track]. -🌟   The test runner is currently running Emacs 28.2 +🌟   The test runner is currently running Emacs 29.3 Currently the Emacs Lisp track doesn't feature a syllabus, so it only contains practice exercises. Practice exercises are open-ended problems that allow you to build and test your knowledge of a programming language. You can find the practice exercises referenced in the [config.json][config-json] and the files in the [`exercises/practice`][emacs-lisp-exercises-practice-dir] directory. The practice exercises are shared between tracks. You can find the canonical problem description in the [problem specifications repository][problem-specifications-repository]. diff --git a/exercises/practice/triangle/triangle-test.el b/exercises/practice/triangle/triangle-test.el index 550ac12b..8628f696 100644 --- a/exercises/practice/triangle/triangle-test.el +++ b/exercises/practice/triangle/triangle-test.el @@ -10,7 +10,7 @@ (declare-function scalenep "triangle.el" (sides)) -(ert-deftest all-sides-are-equal () +(ert-deftest all-sides-are-equal-1 () (should (equilateralp '(2 2 2)))) @@ -18,7 +18,7 @@ (should-not (equilateralp '(2 3 2)))) -(ert-deftest no-sides-are-equal () +(ert-deftest no-sides-are-equal-1 () (should-not (equilateralp '(5 4 6)))) @@ -26,7 +26,7 @@ (should-not (equilateralp '(0 0 0)))) -(ert-deftest sides-may-be-floats () +(ert-deftest sides-may-be-floats-1 () (should (equilateralp '(0.5 0.5 0.5)))) @@ -46,7 +46,7 @@ (should (isoscelesp '(4 4 4)))) -(ert-deftest no-sides-are-equal () +(ert-deftest no-sides-are-equal-2 () (should-not (isoscelesp '(2 3 4)))) @@ -62,15 +62,15 @@ (should-not (isoscelesp '(3 1 1)))) -(ert-deftest sides-may-be-floats () +(ert-deftest sides-may-be-floats-2 () (should (isoscelesp '(0.5 0.4 0.5)))) -(ert-deftest no-sides-are-equal () +(ert-deftest no-sides-are-equal-3 () (should (scalenep '(5 4 6)))) -(ert-deftest all-sides-are-equal () +(ert-deftest all-sides-are-equal-2 () (should-not (scalenep '(4 4 4)))) @@ -90,7 +90,7 @@ (should-not (scalenep '(7 3 2)))) -(ert-deftest sides-may-be-floats () +(ert-deftest sides-may-be-floats-3 () (should (scalenep '(0.5 0.4 0.6)))) (provide 'triangle-test) From 8ae637747426292ac15a254f6ac5eec5aa4be220 Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Sun, 16 Jun 2024 13:07:00 -0500 Subject: [PATCH 113/162] sync anagram tests --- exercises/practice/anagram/.meta/tests.toml | 6 ++++++ exercises/practice/anagram/anagram-test.el | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/exercises/practice/anagram/.meta/tests.toml b/exercises/practice/anagram/.meta/tests.toml index 9b6126a3..b40a89e2 100644 --- a/exercises/practice/anagram/.meta/tests.toml +++ b/exercises/practice/anagram/.meta/tests.toml @@ -77,3 +77,9 @@ include = false [33d3f67e-fbb9-49d3-a90e-0beb00861da7] description = "words other than themselves can be anagrams" reimplements = "a0705568-628c-4b55-9798-82e4acde51ca" + +[a6854f66-eec1-4afd-a137-62ef2870c051] +description = "handles case of greek letters" + +[fd3509e5-e3ba-409d-ac3d-a9ac84d13296] +description = "different characters may have the same bytes" diff --git a/exercises/practice/anagram/anagram-test.el b/exercises/practice/anagram/anagram-test.el index 74234aee..27fd230d 100644 --- a/exercises/practice/anagram/anagram-test.el +++ b/exercises/practice/anagram/anagram-test.el @@ -90,5 +90,13 @@ '("Silent")))) +(ert-deftest test-handles-case-of-greek-letters () + (should (equal (anagrams-for "ΑΒΓ" '("ΒΓΑ" "ΒΓΔ" "γβα" "αβγ")) + '("ΒΓΑ" "γβα")))) + +(ert-deftest different-characters-may-have-the-same-bytes () + (should (equal (anagrams-for "a⬂" '("€a")) + '()))) + (provide 'anagram-test) ;;; anagram-test.el ends here From a11e5fad7325b5760d27672d50ffd153621a5280 Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Sun, 16 Jun 2024 13:08:29 -0500 Subject: [PATCH 114/162] add grade-school #405 --- config.json | 8 + .../grade-school/.docs/instructions.md | 21 +++ .../practice/grade-school/.meta/config.json | 18 ++ .../practice/grade-school/.meta/example.el | 36 ++++ .../practice/grade-school/.meta/tests.toml | 86 +++++++++ .../grade-school/grade-school-test.el | 170 ++++++++++++++++++ .../practice/grade-school/grade-school.el | 20 +++ 7 files changed, 359 insertions(+) create mode 100644 exercises/practice/grade-school/.docs/instructions.md create mode 100644 exercises/practice/grade-school/.meta/config.json create mode 100644 exercises/practice/grade-school/.meta/example.el create mode 100644 exercises/practice/grade-school/.meta/tests.toml create mode 100644 exercises/practice/grade-school/grade-school-test.el create mode 100644 exercises/practice/grade-school/grade-school.el diff --git a/config.json b/config.json index cb944adc..62bae0dd 100644 --- a/config.json +++ b/config.json @@ -854,6 +854,14 @@ "practices": [], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "grade-school", + "name": "Grade School", + "uuid": "e5ab14bd-9eeb-4c63-8143-55e1e56b4ac1", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, diff --git a/exercises/practice/grade-school/.docs/instructions.md b/exercises/practice/grade-school/.docs/instructions.md new file mode 100644 index 00000000..9a63e398 --- /dev/null +++ b/exercises/practice/grade-school/.docs/instructions.md @@ -0,0 +1,21 @@ +# Instructions + +Given students' names along with the grade that they are in, create a roster for the school. + +In the end, you should be able to: + +- Add a student's name to the roster for a grade + - "Add Jim to grade 2." + - "OK." +- Get a list of all students enrolled in a grade + - "Which students are in grade 2?" + - "We've only got Jim just now." +- Get a sorted list of all students in all grades. + Grades should sort as 1, 2, 3, etc., and students within a grade should be sorted alphabetically by name. + - "Who all is enrolled in school right now?" + - "Let me think. + We have Anna, Barb, and Charlie in grade 1, Alex, Peter, and Zoe in grade 2 and Jim in grade 5. + So the answer is: Anna, Barb, Charlie, Alex, Peter, Zoe and Jim" + +Note that all our students only have one name (It's a small town, what do you want?) and each student cannot be added more than once to a grade or the roster. +In fact, when a test attempts to add the same student more than once, your implementation should indicate that this is incorrect. diff --git a/exercises/practice/grade-school/.meta/config.json b/exercises/practice/grade-school/.meta/config.json new file mode 100644 index 00000000..a11f7a13 --- /dev/null +++ b/exercises/practice/grade-school/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "grade-school.el" + ], + "test": [ + "grade-school-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given students' names along with the grade that they are in, create a roster for the school.", + "source": "A pairing session with Phil Battos at gSchool" +} diff --git a/exercises/practice/grade-school/.meta/example.el b/exercises/practice/grade-school/.meta/example.el new file mode 100644 index 00000000..765ab6d7 --- /dev/null +++ b/exercises/practice/grade-school/.meta/example.el @@ -0,0 +1,36 @@ +;;; grade-school.el --- Grade School (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(require 'cl-lib) + +(cl-defstruct school (roster (make-hash-table :test 'equal))) + +(defun add (school name grade) + (let ((current-roster (school-roster school))) + (if (cl-loop for g being the hash-keys of current-roster + thereis (member name (gethash g current-roster))) + nil + (puthash grade (sort (cons name (gethash grade current-roster)) #'string<) current-roster) + t))) + +(defun roster (school) + (let ((grades-and-names (list))) + (maphash (lambda (grade names) (push (cons grade names) grades-and-names)) + (school-roster school)) + (apply #'append + (mapcar #'cdr + (sort grades-and-names (lambda (a b) (< (car a) (car b)))))))) + +(defun grade (school grade) + (gethash grade (school-roster school))) + +(defun set-grade (school grade newval) + (puthash grade (sort newval #'string<) (school-roster school))) + + +(provide 'grade-school) +;;; grade-school.el ends here diff --git a/exercises/practice/grade-school/.meta/tests.toml b/exercises/practice/grade-school/.meta/tests.toml new file mode 100644 index 00000000..50c9e2e5 --- /dev/null +++ b/exercises/practice/grade-school/.meta/tests.toml @@ -0,0 +1,86 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[a3f0fb58-f240-4723-8ddc-e644666b85cc] +description = "Roster is empty when no student is added" + +[9337267f-7793-4b90-9b4a-8e3978408824] +description = "Add a student" + +[6d0a30e4-1b4e-472e-8e20-c41702125667] +description = "Student is added to the roster" + +[73c3ca75-0c16-40d7-82f5-ed8fe17a8e4a] +description = "Adding multiple students in the same grade in the roster" + +[233be705-dd58-4968-889d-fb3c7954c9cc] +description = "Multiple students in the same grade are added to the roster" + +[87c871c1-6bde-4413-9c44-73d59a259d83] +description = "Cannot add student to same grade in the roster more than once" + +[c125dab7-2a53-492f-a99a-56ad511940d8] +description = "A student can't be in two different grades" +include = false + +[a0c7b9b8-0e89-47f8-8b4a-c50f885e79d1] +description = "A student can only be added to the same grade in the roster once" +include = false +reimplements = "c125dab7-2a53-492f-a99a-56ad511940d8" + +[d7982c4f-1602-49f6-a651-620f2614243a] +description = "Student not added to same grade in the roster more than once" +reimplements = "a0c7b9b8-0e89-47f8-8b4a-c50f885e79d1" + +[e70d5d8f-43a9-41fd-94a4-1ea0fa338056] +description = "Adding students in multiple grades" + +[75a51579-d1d7-407c-a2f8-2166e984e8ab] +description = "Students in multiple grades are added to the roster" + +[7df542f1-57ce-433c-b249-ff77028ec479] +description = "Cannot add same student to multiple grades in the roster" + +[6a03b61e-1211-4783-a3cc-fc7f773fba3f] +description = "A student cannot be added to more than one grade in the sorted roster" +include = false +reimplements = "c125dab7-2a53-492f-a99a-56ad511940d8" + +[c7ec1c5e-9ab7-4d3b-be5c-29f2f7a237c5] +description = "Student not added to multiple grades in the roster" +reimplements = "6a03b61e-1211-4783-a3cc-fc7f773fba3f" + +[d9af4f19-1ba1-48e7-94d0-dabda4e5aba6] +description = "Students are sorted by grades in the roster" + +[d9fb5bea-f5aa-4524-9d61-c158d8906807] +description = "Students are sorted by name in the roster" + +[180a8ff9-5b94-43fc-9db1-d46b4a8c93b6] +description = "Students are sorted by grades and then by name in the roster" + +[5e67aa3c-a3c6-4407-a183-d8fe59cd1630] +description = "Grade is empty if no students in the roster" + +[1e0cf06b-26e0-4526-af2d-a2e2df6a51d6] +description = "Grade is empty if no students in that grade" + +[2bfc697c-adf2-4b65-8d0f-c46e085f796e] +description = "Student not added to same grade more than once" + +[66c8e141-68ab-4a04-a15a-c28bc07fe6b9] +description = "Student not added to multiple grades" + +[c9c1fc2f-42e0-4d2c-b361-99271f03eda7] +description = "Student not added to other grade for multiple grades" + +[1bfbcef1-e4a3-49e8-8d22-f6f9f386187e] +description = "Students are sorted by name in a grade" diff --git a/exercises/practice/grade-school/grade-school-test.el b/exercises/practice/grade-school/grade-school-test.el new file mode 100644 index 00000000..e173b439 --- /dev/null +++ b/exercises/practice/grade-school/grade-school-test.el @@ -0,0 +1,170 @@ +;;; grade-school-test.el --- Grade School (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "grade-school.el") +(declare-function roster "grade-school.el" (students)) +(declare-function add "grade-school.el" (students)) +(declare-function grade "grade-school.el" (desired-grade students)) + + +(ert-deftest roster-is-empty-when-no-student-is-added () + (let ((test-school (make-school))) + (should (equal (roster test-school) '())))) + + +(ert-deftest add-a-student () + (let ((test-school (make-school))) + (should (add test-school "Aimee" 2)))) + + +(ert-deftest student-is-added-to-the-roster () + (let ((test-school (make-school))) + (add test-school "Aimee" 2) + (should (equal (roster test-school) '("Aimee"))))) + + +(ert-deftest adding-multiple-students-in-the-same-grade-in-the-roster () + (let ((test-school (make-school))) + (should (add test-school "Blair" 2)) + (should (add test-school "James" 2)) + (should (add test-school "Paul" 2)))) + + +(ert-deftest multiple-students-in-the-same-grade-are-added-to-the-roster () + (let ((test-school (make-school))) + (add test-school "Blair" 2) + (add test-school "James" 2) + (add test-school "Paul" 2) + (should (equal (roster test-school) '("Blair" "James" "Paul"))))) + + +(ert-deftest cannot-add-student-to-same-grade-in-the-roster-more-than-once () + (let ((test-school (make-school))) + (should (add test-school "Blair" 2)) + (should (add test-school "James" 2)) + (should-not (add test-school "James" 2)) + (should (add test-school "Paul" 2)))) + + +(ert-deftest student-not-added-to-same-grade-in-the-roster-more-than-once () + (let ((test-school (make-school))) + (add test-school "Blair" 2) + (add test-school "James" 2) + (add test-school "James" 2) + (add test-school "Paul" 2) + (should (equal (roster test-school) '("Blair" "James" "Paul"))))) + + +(ert-deftest adding-students-in-multiple-grades () + (let ((test-school (make-school))) + (should (add test-school "Chelsea" 3)) + (should (add test-school "Loagan" 7)))) + + +(ert-deftest students-in-multiple-grades-are-added-to-the-roster () + (let ((test-school (make-school))) + (add test-school "Chelsea" 3) + (add test-school "Logan" 7) + (should (equal (roster test-school) '("Chelsea" "Logan"))))) + + +(ert-deftest cannot-add-same-student-to-multiple-grades-in-the-roster () + (let ((test-school (make-school))) + (should (add test-school "Blair" 2)) + (should (add test-school "James" 2)) + (should-not (add test-school "James" 3)) + (should (add test-school "Paul" 3)))) + + +(ert-deftest student-not-added-to-multiple-grades-in-the-roster () + (let ((test-school (make-school))) + (add test-school "Blair" 2) + (add test-school "James" 2) + (add test-school "James" 3) + (add test-school "Paul" 3) + (should (equal (roster test-school) '("Blair" "James" "Paul"))))) + + +(ert-deftest students-are-sorted-by-grades-in-the-roster () + (let ((test-school (make-school))) + (add test-school "Jim" 3) + (add test-school "Peter" 2) + (add test-school "Anna" 1) + (should (equal (roster test-school) '("Anna" "Peter" "Jim"))))) + + +(ert-deftest students-are-sorted-by-name-in-the-roster () + (let ((test-school (make-school))) + (add test-school "Peter" 2) + (add test-school "Zoe" 2) + (add test-school "Alex" 2) + (should (equal (roster test-school) '("Alex" "Peter" "Zoe"))))) + + +(ert-deftest students-are-sorted-by-grades-and-then-by-name-in-the-roster () + (let ((test-school (make-school))) + (add test-school "Peter" 2) + (add test-school "Anna" 1) + (add test-school "Barb" 1) + (add test-school "Zoe" 2) + (add test-school "Alex" 2) + (add test-school "Jim" 3) + (add test-school "Charlie" 1) + (should (equal (roster test-school) '("Anna" "Barb" "Charlie" "Alex" "Peter" "Zoe" "Jim"))))) + + +(ert-deftest grade-is-empty-if-no-students-in-the-roster () + (let ((test-school (make-school))) + (should (equal (grade test-school 1) '())))) + + +(ert-deftest grade-is-empty-if-no-students-in-that-grade () + (let ((test-school (make-school))) + (add test-school "Peter" 2) + (add test-school "Zoe" 2) + (add test-school "Alex" 2) + (add test-school "Jim" 3) + (should (equal (grade test-school 1) '())))) + + +(ert-deftest student-not-added-to-same-grade-more-than-once () + (let ((test-school (make-school))) + (add test-school "Blair" 2) + (add test-school "James" 2) + (add test-school "James" 2) + (add test-school "Paul" 2) + (should (equal (grade test-school 2) '("Blair" "James" "Paul"))))) + + +(ert-deftest student-not-added-to-multiple-grades () + (let ((test-school (make-school))) + (add test-school "Blair" 2) + (add test-school "James" 2) + (add test-school "James" 3) + (add test-school "Paul" 3) + (should (equal (grade test-school 2) '("Blair" "James"))))) + + +(ert-deftest student-not-added-to-other-grade-for-multiple-grades () + (let ((test-school (make-school))) + (add test-school "Blair" 2) + (add test-school "James" 2) + (add test-school "James" 3) + (add test-school "Paul" 3) + (should (equal (grade test-school 3) '("Paul"))))) + + +(ert-deftest students-are-sorted-by-name-in-a-grade () + (let ((test-school (make-school))) + (add test-school "Franklin" 5) + (add test-school "Bradley" 5) + (add test-school "Jeff" 1) + (should (equal (grade test-school 5) '("Bradley" "Franklin"))))) + + +(provide 'grade-school-test) +;;; grade-school-test.el ends here diff --git a/exercises/practice/grade-school/grade-school.el b/exercises/practice/grade-school/grade-school.el new file mode 100644 index 00000000..784cae79 --- /dev/null +++ b/exercises/practice/grade-school/grade-school.el @@ -0,0 +1,20 @@ +;;; grade-school.el --- Grade School (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun roster (students) + (error "Delete this S-Expression and write your own implementation")) + +(defun add (students) + (error "Delete this S-Expression and write your own implementation")) + +(defun grade (desired-grade students) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'grade-school) +;;; grade-school.el ends here + From b104f307946bb78568f4b554e1c8bc4949d5fdea Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Sun, 16 Jun 2024 18:49:19 -0500 Subject: [PATCH 115/162] sync reverse-string tests #364 (#414) --- config.json | 2 +- .../practice/reverse-string/.meta/config.json | 3 ++ .../practice/reverse-string/.meta/example.el | 28 +++++++++++++++++-- .../practice/reverse-string/.meta/tests.toml | 9 ++++++ .../reverse-string/reverse-string-test.el | 9 ++++++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/config.json b/config.json index 62bae0dd..8ad75291 100644 --- a/config.json +++ b/config.json @@ -364,7 +364,7 @@ "uuid": "59c6319b-2799-4e4c-bef1-e28626878446", "practices": [], "prerequisites": [], - "difficulty": 2 + "difficulty": 4 }, { "slug": "roman-numerals", diff --git a/exercises/practice/reverse-string/.meta/config.json b/exercises/practice/reverse-string/.meta/config.json index 34a81d6c..94ff37fe 100644 --- a/exercises/practice/reverse-string/.meta/config.json +++ b/exercises/practice/reverse-string/.meta/config.json @@ -2,6 +2,9 @@ "authors": [ "fapdash" ], + "contributors": [ + "kmarker1101" + ], "files": { "solution": [ "reverse-string.el" diff --git a/exercises/practice/reverse-string/.meta/example.el b/exercises/practice/reverse-string/.meta/example.el index 73fab7ac..16465ba6 100644 --- a/exercises/practice/reverse-string/.meta/example.el +++ b/exercises/practice/reverse-string/.meta/example.el @@ -5,9 +5,33 @@ ;;; Code: -(defun reverse-string (value) - (reverse value)) +(require 'cl-lib) +(require 'ucs-normalize) + +(defun combining-mark-p (char) + (let ((category (get-char-code-property char 'general-category))) + (or (string= category "Mn") ; Nonspacing_Mark + (string= category "Mc") ; Spacing_Mark + (string= category "Me")))) ; Enclosing_Mark +(defun split-grapheme-clusters (str) + (let ((clusters '()) + (i 0) + (len (length str))) + (while (< i len) + (let ((start i) + (char (aref str i))) + (setq i (1+ i)) + (while (and (< i len) + (combining-mark-p (aref str i))) + (setq i (1+ i))) + (push (substring str start i) clusters))) + (nreverse clusters))) + +(defun reverse-string (value) + (let* ((decomposed (ucs-normalize-NFD-string value)) + (clusters (split-grapheme-clusters decomposed))) + (apply #'concat (reverse clusters)))) (provide 'reverse-string) ;;; reverse-string.el ends here diff --git a/exercises/practice/reverse-string/.meta/tests.toml b/exercises/practice/reverse-string/.meta/tests.toml index 0b04c4cd..0c313cc5 100644 --- a/exercises/practice/reverse-string/.meta/tests.toml +++ b/exercises/practice/reverse-string/.meta/tests.toml @@ -26,3 +26,12 @@ description = "a palindrome" [b9e7dec1-c6df-40bd-9fa3-cd7ded010c4c] description = "an even-sized word" + +[1bed0f8a-13b0-4bd3-9d59-3d0593326fa2] +description = "wide characters" + +[93d7e1b8-f60f-4f3c-9559-4056e10d2ead] +description = "grapheme cluster with pre-combined form" + +[1028b2c1-6763-4459-8540-2da47ca512d9] +description = "grapheme clusters" diff --git a/exercises/practice/reverse-string/reverse-string-test.el b/exercises/practice/reverse-string/reverse-string-test.el index dc0535e4..41e4093c 100644 --- a/exercises/practice/reverse-string/reverse-string-test.el +++ b/exercises/practice/reverse-string/reverse-string-test.el @@ -32,6 +32,15 @@ (ert-deftest an-even-sized-word () (should (string= (reverse-string "drawer") "reward"))) +(ert-deftest wide-characters () + (should (string= (reverse-string "子猫") "猫子"))) + +(ert-deftest grapheme-cluster-with-pre-combined-form () + (should (string= (reverse-string "Würstchenstand") "dnatsnehctsrüW"))) + +(ert-deftest grapheme-cluster () + (should (string= (reverse-string "ผู้เขียนโปรแกรม") "มรกแรปโนยขีเผู้"))) + (provide 'reverse-string-test) ;;; reverse-string-test.el ends here From 881e4516af6c9ffe1836c6f2272646a0c9fadfcf Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Tue, 18 Jun 2024 13:36:01 -0500 Subject: [PATCH 116/162] add meetup (#415) --- config.json | 8 + .../practice/meetup/.docs/instructions.md | 34 ++ .../practice/meetup/.docs/introduction.md | 29 ++ exercises/practice/meetup/.meta/config.json | 18 + exercises/practice/meetup/.meta/example.el | 61 +++ exercises/practice/meetup/.meta/tests.toml | 295 +++++++++++++ exercises/practice/meetup/meetup-test.el | 393 ++++++++++++++++++ exercises/practice/meetup/meetup.el | 14 + 8 files changed, 852 insertions(+) create mode 100644 exercises/practice/meetup/.docs/instructions.md create mode 100644 exercises/practice/meetup/.docs/introduction.md create mode 100644 exercises/practice/meetup/.meta/config.json create mode 100644 exercises/practice/meetup/.meta/example.el create mode 100644 exercises/practice/meetup/.meta/tests.toml create mode 100644 exercises/practice/meetup/meetup-test.el create mode 100644 exercises/practice/meetup/meetup.el diff --git a/config.json b/config.json index 8ad75291..9256b48e 100644 --- a/config.json +++ b/config.json @@ -862,6 +862,14 @@ "practices": [], "prerequisites": [], "difficulty": 5 + }, + { + "slug": "meetup", + "name": "Meetup", + "uuid": "80000759-8ca8-4ff8-a88f-34c4244ac6c5", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, diff --git a/exercises/practice/meetup/.docs/instructions.md b/exercises/practice/meetup/.docs/instructions.md new file mode 100644 index 00000000..000de2fd --- /dev/null +++ b/exercises/practice/meetup/.docs/instructions.md @@ -0,0 +1,34 @@ +# Instructions + +Your task is to find the exact date of a meetup, given a month, year, weekday and week. + +There are five week values to consider: `first`, `second`, `third`, `fourth`, `last`, `teenth`. + +For example, you might be asked to find the date for the meetup on the first Monday in January 2018 (January 1, 2018). + +Similarly, you might be asked to find: + +- the third Tuesday of August 2019 (August 20, 2019) +- the teenth Wednesday of May 2020 (May 13, 2020) +- the fourth Sunday of July 2021 (July 25, 2021) +- the last Thursday of November 2022 (November 24, 2022) +- the teenth Saturday of August 1953 (August 15, 1953) + +## Teenth + +The teenth week refers to the seven days in a month that end in '-teenth' (13th, 14th, 15th, 16th, 17th, 18th and 19th). + +If asked to find the teenth Saturday of August, 1953, we check its calendar: + +```plaintext + August 1953 +Su Mo Tu We Th Fr Sa + 1 + 2 3 4 5 6 7 8 + 9 10 11 12 13 14 15 +16 17 18 19 20 21 22 +23 24 25 26 27 28 29 +30 31 +``` + +From this we find that the teenth Saturday is August 15, 1953. diff --git a/exercises/practice/meetup/.docs/introduction.md b/exercises/practice/meetup/.docs/introduction.md new file mode 100644 index 00000000..29170ef1 --- /dev/null +++ b/exercises/practice/meetup/.docs/introduction.md @@ -0,0 +1,29 @@ +# Introduction + +Every month, your partner meets up with their best friend. +Both of them have very busy schedules, making it challenging to find a suitable date! +Given your own busy schedule, your partner always double-checks potential meetup dates with you: + +- "Can I meet up on the first Friday of next month?" +- "What about the third Wednesday?" +- "Maybe the last Sunday?" + +In this month's call, your partner asked you this question: + +- "I'd like to meet up on the teenth Thursday; is that okay?" + +Confused, you ask what a "teenth" day is. +Your partner explains that a teenth day, a concept they made up, refers to the days in a month that end in '-teenth': + +- 13th (thirteenth) +- 14th (fourteenth) +- 15th (fifteenth) +- 16th (sixteenth) +- 17th (seventeenth) +- 18th (eighteenth) +- 19th (nineteenth) + +As there are also seven weekdays, it is guaranteed that each day of the week has _exactly one_ teenth day each month. + +Now that you understand the concept of a teenth day, you check your calendar. +You don't have anything planned on the teenth Thursday, so you happily confirm the date with your partner. diff --git a/exercises/practice/meetup/.meta/config.json b/exercises/practice/meetup/.meta/config.json new file mode 100644 index 00000000..b1ca414e --- /dev/null +++ b/exercises/practice/meetup/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "meetup.el" + ], + "test": [ + "meetup-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Calculate the date of meetups.", + "source": "Jeremy Hinegardner mentioned a Boulder meetup that happens on the Wednesteenth of every month" +} diff --git a/exercises/practice/meetup/.meta/example.el b/exercises/practice/meetup/.meta/example.el new file mode 100644 index 00000000..5ceeb9c0 --- /dev/null +++ b/exercises/practice/meetup/.meta/example.el @@ -0,0 +1,61 @@ +;;; meetup.el --- Meetup (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'calendar) + +(defconst +days-of-the-week+ + '((:sunday . 0) + (:monday . 1) + (:tuesday . 2) + (:wednesday . 3) + (:thursday . 4) + (:friday . 5) + (:saturday . 6))) + +(defconst +schedules+ + '((:first . 1) + (:second . 8) + (:third . 15) + (:teenth . 13) + (:fourth . 22) + (:last . -7))) + +(defun last-day-of (month year) + (calendar-last-day-of-month month year)) + +(defun find-dow-near-date (target-dow start-day month year direction) + (let* ((direction-factor (if (eq direction :before) -1 1)) + (current-day start-day) + (found-day nil)) + (while (and (not found-day) + (<= 1 current-day (last-day-of month year))) + (let ((current-dow (calendar-day-of-week (list month current-day year)))) + (when (= current-dow target-dow) + (setq found-day current-day))) + (setq current-day (+ current-day direction-factor))) + (list year month found-day))) + +(defun meetup (year month dayofweek schedule) + (let* ((target-dow (cdr (assoc dayofweek +days-of-the-week+))) + (first-day-of-month (calendar-day-of-week (list month 1 year))) + (schedule-offset (cdr (assoc schedule +schedules+))) + (first-target-dow (+ 1 (- target-dow first-day-of-month))) + (first-occurrence (if (>= first-target-dow 1) + first-target-dow + (+ first-target-dow 7))) + (start-day (cond + ((eq schedule :last) + (last-day-of month year)) + ((eq schedule :teenth) + 13) + (t + (+ first-occurrence (* (/ (1- schedule-offset) 7) 7)))))) + (if (eq schedule :last) + (find-dow-near-date target-dow start-day month year :before) + (find-dow-near-date target-dow start-day month year :after)))) + +(provide 'meetup) +;;; meetup.el ends here diff --git a/exercises/practice/meetup/.meta/tests.toml b/exercises/practice/meetup/.meta/tests.toml new file mode 100644 index 00000000..1e5b84d0 --- /dev/null +++ b/exercises/practice/meetup/.meta/tests.toml @@ -0,0 +1,295 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[d7f8eadd-d4fc-46ee-8a20-e97bd3fd01c8] +description = "when teenth Monday is the 13th, the first day of the teenth week" + +[f78373d1-cd53-4a7f-9d37-e15bf8a456b4] +description = "when teenth Monday is the 19th, the last day of the teenth week" + +[8c78bea7-a116-425b-9c6b-c9898266d92a] +description = "when teenth Monday is some day in the middle of the teenth week" + +[cfef881b-9dc9-4d0b-8de4-82d0f39fc271] +description = "when teenth Tuesday is the 19th, the last day of the teenth week" + +[69048961-3b00-41f9-97ee-eb6d83a8e92b] +description = "when teenth Tuesday is some day in the middle of the teenth week" + +[d30bade8-3622-466a-b7be-587414e0caa6] +description = "when teenth Tuesday is the 13th, the first day of the teenth week" + +[8db4b58b-92f3-4687-867b-82ee1a04f851] +description = "when teenth Wednesday is some day in the middle of the teenth week" + +[6c27a2a2-28f8-487f-ae81-35d08c4664f7] +description = "when teenth Wednesday is the 13th, the first day of the teenth week" + +[008a8674-1958-45b5-b8e6-c2c9960d973a] +description = "when teenth Wednesday is the 19th, the last day of the teenth week" + +[e4abd5e3-57cb-4091-8420-d97e955c0dbd] +description = "when teenth Thursday is some day in the middle of the teenth week" + +[85da0b0f-eace-4297-a6dd-63588d5055b4] +description = "when teenth Thursday is the 13th, the first day of the teenth week" + +[ecf64f9b-8413-489b-bf6e-128045f70bcc] +description = "when teenth Thursday is the 19th, the last day of the teenth week" + +[ac4e180c-7d0a-4d3d-b05f-f564ebb584ca] +description = "when teenth Friday is the 19th, the last day of the teenth week" + +[b79101c7-83ad-4f8f-8ec8-591683296315] +description = "when teenth Friday is some day in the middle of the teenth week" + +[6ed38b9f-0072-4901-bd97-7c8b8b0ef1b8] +description = "when teenth Friday is the 13th, the first day of the teenth week" + +[dfae03ed-9610-47de-a632-655ab01e1e7c] +description = "when teenth Saturday is some day in the middle of the teenth week" + +[ec02e3e1-fc72-4a3c-872f-a53fa8ab358e] +description = "when teenth Saturday is the 13th, the first day of the teenth week" + +[d983094b-7259-4195-b84e-5d09578c89d9] +description = "when teenth Saturday is the 19th, the last day of the teenth week" + +[d84a2a2e-f745-443a-9368-30051be60c2e] +description = "when teenth Sunday is the 19th, the last day of the teenth week" + +[0e64bc53-92a3-4f61-85b2-0b7168c7ce5a] +description = "when teenth Sunday is some day in the middle of the teenth week" + +[de87652c-185e-4854-b3ae-04cf6150eead] +description = "when teenth Sunday is the 13th, the first day of the teenth week" + +[2cbfd0f5-ba3a-46da-a8cc-0fe4966d3411] +description = "when first Monday is some day in the middle of the first week" + +[a6168c7c-ed95-4bb3-8f92-c72575fc64b0] +description = "when first Monday is the 1st, the first day of the first week" + +[1bfc620f-1c54-4bbd-931f-4a1cd1036c20] +description = "when first Tuesday is the 7th, the last day of the first week" + +[12959c10-7362-4ca0-a048-50cf1c06e3e2] +description = "when first Tuesday is some day in the middle of the first week" + +[1033dc66-8d0b-48a1-90cb-270703d59d1d] +description = "when first Wednesday is some day in the middle of the first week" + +[b89185b9-2f32-46f4-a602-de20b09058f6] +description = "when first Wednesday is the 7th, the last day of the first week" + +[53aedc4d-b2c8-4dfb-abf7-a8dc9cdceed5] +description = "when first Thursday is some day in the middle of the first week" + +[b420a7e3-a94c-4226-870a-9eb3a92647f0] +description = "when first Thursday is another day in the middle of the first week" + +[61df3270-28b4-4713-bee2-566fa27302ca] +description = "when first Friday is the 1st, the first day of the first week" + +[cad33d4d-595c-412f-85cf-3874c6e07abf] +description = "when first Friday is some day in the middle of the first week" + +[a2869b52-5bba-44f0-a863-07bd1f67eadb] +description = "when first Saturday is some day in the middle of the first week" + +[3585315a-d0db-4ea1-822e-0f22e2a645f5] +description = "when first Saturday is another day in the middle of the first week" + +[c49e9bd9-8ccf-4cf2-947a-0ccd4e4f10b1] +description = "when first Sunday is some day in the middle of the first week" + +[1513328b-df53-4714-8677-df68c4f9366c] +description = "when first Sunday is the 7th, the last day of the first week" + +[49e083af-47ec-4018-b807-62ef411efed7] +description = "when second Monday is some day in the middle of the second week" + +[6cb79a73-38fe-4475-9101-9eec36cf79e5] +description = "when second Monday is the 8th, the first day of the second week" + +[4c39b594-af7e-4445-aa03-bf4f8effd9a1] +description = "when second Tuesday is the 14th, the last day of the second week" + +[41b32c34-2e39-40e3-b790-93539aaeb6dd] +description = "when second Tuesday is some day in the middle of the second week" + +[90a160c5-b5d9-4831-927f-63a78b17843d] +description = "when second Wednesday is some day in the middle of the second week" + +[23b98ce7-8dd5-41a1-9310-ef27209741cb] +description = "when second Wednesday is the 14th, the last day of the second week" + +[447f1960-27ca-4729-bc3f-f36043f43ed0] +description = "when second Thursday is some day in the middle of the second week" + +[c9aa2687-300c-4e79-86ca-077849a81bde] +description = "when second Thursday is another day in the middle of the second week" + +[a7e11ef3-6625-4134-acda-3e7195421c09] +description = "when second Friday is the 8th, the first day of the second week" + +[8b420e5f-9290-4106-b5ae-022f3e2a3e41] +description = "when second Friday is some day in the middle of the second week" + +[80631afc-fc11-4546-8b5f-c12aaeb72b4f] +description = "when second Saturday is some day in the middle of the second week" + +[e34d43ac-f470-44c2-aa5f-e97b78ecaf83] +description = "when second Saturday is another day in the middle of the second week" + +[a57d59fd-1023-47ad-b0df-a6feb21b44fc] +description = "when second Sunday is some day in the middle of the second week" + +[a829a8b0-abdd-4ad1-b66c-5560d843c91a] +description = "when second Sunday is the 14th, the last day of the second week" + +[501a8a77-6038-4fc0-b74c-33634906c29d] +description = "when third Monday is some day in the middle of the third week" + +[49e4516e-cf32-4a58-8bbc-494b7e851c92] +description = "when third Monday is the 15th, the first day of the third week" + +[4db61095-f7c7-493c-85f1-9996ad3012c7] +description = "when third Tuesday is the 21st, the last day of the third week" + +[714fc2e3-58d0-4b91-90fd-61eefd2892c0] +description = "when third Tuesday is some day in the middle of the third week" + +[b08a051a-2c80-445b-9b0e-524171a166d1] +description = "when third Wednesday is some day in the middle of the third week" + +[80bb9eff-3905-4c61-8dc9-bb03016d8ff8] +description = "when third Wednesday is the 21st, the last day of the third week" + +[fa52a299-f77f-4784-b290-ba9189fbd9c9] +description = "when third Thursday is some day in the middle of the third week" + +[f74b1bc6-cc5c-4bf1-ba69-c554a969eb38] +description = "when third Thursday is another day in the middle of the third week" + +[8900f3b0-801a-466b-a866-f42d64667abd] +description = "when third Friday is the 15th, the first day of the third week" + +[538ac405-a091-4314-9ccd-920c4e38e85e] +description = "when third Friday is some day in the middle of the third week" + +[244db35c-2716-4fa0-88ce-afd58e5cf910] +description = "when third Saturday is some day in the middle of the third week" + +[dd28544f-f8fa-4f06-9bcd-0ad46ce68e9e] +description = "when third Saturday is another day in the middle of the third week" + +[be71dcc6-00d2-4b53-a369-cbfae55b312f] +description = "when third Sunday is some day in the middle of the third week" + +[b7d2da84-4290-4ee6-a618-ee124ae78be7] +description = "when third Sunday is the 21st, the last day of the third week" + +[4276dc06-a1bd-4fc2-b6c2-625fee90bc88] +description = "when fourth Monday is some day in the middle of the fourth week" + +[ddbd7976-2deb-4250-8a38-925ac1a8e9a2] +description = "when fourth Monday is the 22nd, the first day of the fourth week" + +[eb714ef4-1656-47cc-913c-844dba4ebddd] +description = "when fourth Tuesday is the 28th, the last day of the fourth week" + +[16648435-7937-4d2d-b118-c3e38fd084bd] +description = "when fourth Tuesday is some day in the middle of the fourth week" + +[de062bdc-9484-437a-a8c5-5253c6f6785a] +description = "when fourth Wednesday is some day in the middle of the fourth week" + +[c2ce6821-169c-4832-8d37-690ef5d9514a] +description = "when fourth Wednesday is the 28th, the last day of the fourth week" + +[d462c631-2894-4391-a8e3-dbb98b7a7303] +description = "when fourth Thursday is some day in the middle of the fourth week" + +[9ff1f7b6-1b72-427d-9ee9-82b5bb08b835] +description = "when fourth Thursday is another day in the middle of the fourth week" + +[83bae8ba-1c49-49bc-b632-b7c7e1d7e35f] +description = "when fourth Friday is the 22nd, the first day of the fourth week" + +[de752d2a-a95e-48d2-835b-93363dac3710] +description = "when fourth Friday is some day in the middle of the fourth week" + +[eedd90ad-d581-45db-8312-4c6dcf9cf560] +description = "when fourth Saturday is some day in the middle of the fourth week" + +[669fedcd-912e-48c7-a0a1-228b34af91d0] +description = "when fourth Saturday is another day in the middle of the fourth week" + +[648e3849-ea49-44a5-a8a3-9f2a43b3bf1b] +description = "when fourth Sunday is some day in the middle of the fourth week" + +[f81321b3-99ab-4db6-9267-69c5da5a7823] +description = "when fourth Sunday is the 28th, the last day of the fourth week" + +[1af5e51f-5488-4548-aee8-11d7d4a730dc] +description = "last Monday in a month with four Mondays" + +[f29999f2-235e-4ec7-9dab-26f137146526] +description = "last Monday in a month with five Mondays" + +[31b097a0-508e-48ac-bf8a-f63cdcf6dc41] +description = "last Tuesday in a month with four Tuesdays" + +[8c022150-0bb5-4a1f-80f9-88b2e2abcba4] +description = "last Tuesday in another month with four Tuesdays" + +[0e762194-672a-4bdf-8a37-1e59fdacef12] +description = "last Wednesday in a month with five Wednesdays" + +[5016386a-f24e-4bd7-b439-95358f491b66] +description = "last Wednesday in a month with four Wednesdays" + +[12ead1a5-cdf9-4192-9a56-2229e93dd149] +description = "last Thursday in a month with four Thursdays" + +[7db89e11-7fbe-4e57-ae3c-0f327fbd7cc7] +description = "last Thursday in a month with five Thursdays" + +[e47a739e-b979-460d-9c8a-75c35ca2290b] +description = "last Friday in a month with five Fridays" + +[5bed5aa9-a57a-4e5d-8997-2cc796a5b0ec] +description = "last Friday in a month with four Fridays" + +[61e54cba-76f3-4772-a2b1-bf443fda2137] +description = "last Saturday in a month with four Saturdays" + +[8b6a737b-2fa9-444c-b1a2-80ce7a2ec72f] +description = "last Saturday in another month with four Saturdays" + +[0b63e682-f429-4d19-9809-4a45bd0242dc] +description = "last Sunday in a month with five Sundays" + +[5232307e-d3e3-4afc-8ba6-4084ad987c00] +description = "last Sunday in a month with four Sundays" + +[0bbd48e8-9773-4e81-8e71-b9a51711e3c5] +description = "when last Wednesday in February in a leap year is the 29th" + +[fe0936de-7eee-4a48-88dd-66c07ab1fefc] +description = "last Wednesday in December that is also the last day of the year" + +[2ccf2488-aafc-4671-a24e-2b6effe1b0e2] +description = "when last Sunday in February in a non-leap year is not the 29th" + +[00c3ce9f-cf36-4b70-90d8-92b32be6830e] +description = "when first Friday is the 7th, the last day of the first week" diff --git a/exercises/practice/meetup/meetup-test.el b/exercises/practice/meetup/meetup-test.el new file mode 100644 index 00000000..167857d2 --- /dev/null +++ b/exercises/practice/meetup/meetup-test.el @@ -0,0 +1,393 @@ +;;; meetup-test.el --- Meetup (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "meetup.el") +(declare-function meetup "meetup.el" (year month dayofweek schedule)) + + +(ert-deftest when-teenth-monday-is-the-13th-the-first-day-of-the-teenth-week () + (should (equal (meetup 2013 5 :monday :teenth) '(2013 5 13)))) + + +(ert-deftest when-teenth-monday-is-the-19th-the-last-day-of-the-teenth-week () + (should (equal (meetup 2013 8 :monday :teenth) '(2013 8 19)))) + + +(ert-deftest when-teenth-monday-is-some-day-in-the-middle-of-the-teenth-week () + (should (equal (meetup 2013 9 :monday :teenth) '(2013 9 16)))) + + +(ert-deftest when-teenth-tuesday-is-the-19th-the-last-day-of-the-teenth-week () + (should (equal (meetup 2013 3 :tuesday :teenth) '(2013 3 19)))) + + +(ert-deftest when-teenth-tuesday-is-some-day-in-the-middle-of-the-teenth-week () + (should (equal (meetup 2013 4 :tuesday :teenth) '(2013 4 16)))) + + +(ert-deftest when-teenth-tuesday-is-the-13th-the-first-day-of-the-teenth-week () + (should (equal (meetup 2013 8 :tuesday :teenth) '(2013 8 13)))) + + +(ert-deftest when-teenth-wednesday-is-some-day-in-the-middle-of-the-teenth-week () + (should (equal (meetup 2013 1 :wednesday :teenth) '(2013 1 16)))) + + +(ert-deftest when-teenth-wednesday-is-the-13th-the-first-day-of-the-teenth-week () + (should (equal (meetup 2013 2 :wednesday :teenth) '(2013 2 13)))) + + +(ert-deftest when-teenth-wednesday-is-the-19th-the-last-day-of-the-teenth-week () + (should (equal (meetup 2013 6 :wednesday :teenth) '(2013 6 19)))) + + +(ert-deftest when-teenth-thursday-is-some-day-in-the-middle-of-the-teenth-week () + (should (equal (meetup 2013 5 :thursday :teenth) '(2013 5 16)))) + + +(ert-deftest when-teenth-thursday-is-the-13th-the-first-day-of-the-teenth-week () + (should (equal (meetup 2013 6 :thursday :teenth) '(2013 6 13)))) + + +(ert-deftest when-teenth-thursday-is-the-19th-the-last-day-of-the-teenth-week () + (should (equal (meetup 2013 9 :thursday :teenth) '(2013 9 19)))) + + +(ert-deftest when-teenth-friday-is-the-19th-the-last-day-of-the-teenth-week () + (should (equal (meetup 2013 4 :friday :teenth) '(2013 4 19)))) + + +(ert-deftest when-teenth-friday-is-some-day-in-the-middle-of-the-teenth-week () + (should (equal (meetup 2013 8 :friday :teenth) '(2013 8 16)))) + + +(ert-deftest when-teenth-friday-is-the-13th-the-first-day-of-the-teenth-week () + (should (equal (meetup 2013 9 :friday :teenth) '(2013 9 13)))) + + +(ert-deftest when-teenth-saturday-is-some-day-in-the-middle-of-the-teenth-week () + (should (equal (meetup 2013 2 :saturday :teenth) '(2013 2 16)))) + + +(ert-deftest when-teenth-saturday-is-the-13th-the-first-day-of-the-teenth-week () + (should (equal (meetup 2013 4 :saturday :teenth) '(2013 4 13)))) + + +(ert-deftest when-teenth-saturday-is-the-19th-the-last-day-of-the-teenth-week () + (should (equal (meetup 2013 10 :saturday :teenth) '(2013 10 19)))) + + +(ert-deftest when-teenth-sunday-is-the-19th-the-last-day-of-the-teenth-week () + (should (equal (meetup 2013 5 :sunday :teenth) '(2013 5 19)))) + + +(ert-deftest when-teenth-sunday-is-some-day-in-the-middle-of-the-teenth-week () + (should (equal (meetup 2013 6 :sunday :teenth) '(2013 6 16)))) + + +(ert-deftest when-teenth-sunday-is-the-13th-the-first-day-of-the-teenth-week () + (should (equal (meetup 2013 10 :sunday :teenth) '(2013 10 13)))) + + +(ert-deftest when-first-monday-is-some-day-in-the-middle-of-the-first-week () + (should (equal (meetup 2013 3 :monday :first) '(2013 3 4)))) + + +(ert-deftest when-first-monday-is-the-1st-the-first-day-of-the-first-week () + (should (equal (meetup 2013 4 :monday :first) '(2013 4 1)))) + + +(ert-deftest when-first-tuesday-is-the-7th-the-last-day-of-the-first-week () + (should (equal (meetup 2013 5 :tuesday :first) '(2013 5 7)))) + + +(ert-deftest when-first-tuesday-is-some-day-in-the-middle-of-the-first-week () + (should (equal (meetup 2013 6 :tuesday :first) '(2013 6 4)))) + + +(ert-deftest when-first-wednesday-is-some-day-in-the-middle-of-the-first-week () + (should (equal (meetup 2013 7 :wednesday :first) '(2013 7 3)))) + + +(ert-deftest when-first-wednesday-is-the-7th-the-last-day-of-the-first-week () + (should (equal (meetup 2013 8 :wednesday :first) '(2013 8 7)))) + + +(ert-deftest when-first-thursday-is-some-day-in-the-middle-of-the-first-week () + (should (equal (meetup 2013 9 :thursday :first) '(2013 9 5)))) + + +(ert-deftest when-first-thursday-is-another-day-in-the-middle-of-the-first-week () + (should (equal (meetup 2013 10 :thursday :first) '(2013 10 3)))) + + +(ert-deftest when-first-friday-is-the-1st-the-first-day-of-the-first-week () + (should (equal (meetup 2013 11 :friday :first) '(2013 11 1)))) + + +(ert-deftest when-first-friday-is-some-day-in-the-middle-of-the-first-week () + (should (equal (meetup 2013 12 :friday :first) '(2013 12 6)))) + + +(ert-deftest when-first-saturday-is-some-day-in-the-middle-of-the-first-week () + (should (equal (meetup 2013 1 :saturday :first) '(2013 1 5)))) + + +(ert-deftest when-first-saturday-is-another-day-in-the-middle-of-the-first-week () + (should (equal (meetup 2013 2 :saturday :first) '(2013 2 2)))) + + +(ert-deftest when-first-sunday-is-some-day-in-the-middle-of-the-first-week () + (should (equal (meetup 2013 3 :sunday :first) '(2013 3 3)))) + + +(ert-deftest when-first-sunday-is-the-7th-the-last-day-of-the-first-week () + (should (equal (meetup 2013 4 :sunday :first) '(2013 4 7)))) + + +(ert-deftest when-second-monday-is-some-day-in-the-middle-of-the-second-week () + (should (equal (meetup 2013 3 :monday :second) '(2013 3 11)))) + + +(ert-deftest when-second-monday-is-the-8th-the-first-day-of-the-second-week () + (should (equal (meetup 2013 4 :monday :second) '(2013 4 8)))) + + +(ert-deftest when-second-tuesday-is-the-14th-the-last-day-of-the-second-week () + (should (equal (meetup 2013 5 :tuesday :second) '(2013 5 14)))) + + +(ert-deftest when-second-tuesday-is-some-day-in-the-middle-of-the-second-week () + (should (equal (meetup 2013 6 :tuesday :second) '(2013 6 11)))) + + +(ert-deftest when-second-wednesday-is-some-day-in-the-middle-of-the-second-week () + (should (equal (meetup 2013 7 :wednesday :second) '(2013 7 10)))) + + +(ert-deftest when-second-wednesday-is-the-14th-the-last-day-of-the-second-week () + (should (equal (meetup 2013 8 :wednesday :second) '(2013 8 14)))) + + +(ert-deftest when-second-thursday-is-some-day-in-the-middle-of-the-second-week () + (should (equal (meetup 2013 9 :thursday :second) '(2013 9 12)))) + + +(ert-deftest when-second-thursday-is-another-day-in-the-middle-of-the-second-week () + (should (equal (meetup 2013 10 :thursday :second) '(2013 10 10)))) + + +(ert-deftest when-second-friday-is-the-8th-the-first-day-of-the-second-week () + (should (equal (meetup 2013 11 :friday :second) '(2013 11 8)))) + + +(ert-deftest when-second-friday-is-some-day-in-the-middle-of-the-second-week () + (should (equal (meetup 2013 12 :friday :second) '(2013 12 13)))) + + +(ert-deftest when-second-saturday-is-some-day-in-the-middle-of-the-second-week () + (should (equal (meetup 2013 1 :saturday :second) '(2013 1 12)))) + + +(ert-deftest when-second-saturday-is-another-day-in-the-middle-of-the-second-week () + (should (equal (meetup 2013 2 :saturday :second) '(2013 2 9)))) + + +(ert-deftest when-second-sunday-is-some-day-in-the-middle-of-the-second-week () + (should (equal (meetup 2013 3 :sunday :second) '(2013 3 10)))) + + +(ert-deftest when-second-sunday-is-the-14th-the-last-day-of-the-second-week () + (should (equal (meetup 2013 4 :sunday :second) '(2013 4 14)))) + + +(ert-deftest when-third-monday-is-some-day-in-the-middle-of-the-third-week () + (should (equal (meetup 2013 3 :monday :third) '(2013 3 18)))) + + +(ert-deftest when-third-monday-is-the-15th-the-first-day-of-the-third-week () + (should (equal (meetup 2013 4 :monday :third) '(2013 4 15)))) + + +(ert-deftest when-third-tuesday-is-the-21st-the-last-day-of-the-third-week () + (should (equal (meetup 2013 5 :tuesday :third) '(2013 5 21)))) + + +(ert-deftest when-third-tuesday-is-some-day-in-the-middle-of-the-third-week () + (should (equal (meetup 2013 6 :tuesday :third) '(2013 6 18)))) + + +(ert-deftest when-third-wednesday-is-some-day-in-the-middle-of-the-third-week () + (should (equal (meetup 2013 7 :wednesday :third) '(2013 7 17)))) + + +(ert-deftest when-third-wednesday-is-the-21st-the-last-day-of-the-third-week () + (should (equal (meetup 2013 8 :wednesday :third) '(2013 8 21)))) + + +(ert-deftest when-third-thursday-is-some-day-in-the-middle-of-the-third-week () + (should (equal (meetup 2013 9 :thursday :third) '(2013 9 19)))) + + +(ert-deftest when-third-thursday-is-another-day-in-the-middle-of-the-third-week () + (should (equal (meetup 2013 10 :thursday :third) '(2013 10 17)))) + + +(ert-deftest when-third-friday-is-the-15th-the-first-day-of-the-third-week () + (should (equal (meetup 2013 11 :friday :third) '(2013 11 15)))) + + +(ert-deftest when-third-friday-is-some-day-in-the-middle-of-the-third-week () + (should (equal (meetup 2013 12 :friday :third) '(2013 12 20)))) + + +(ert-deftest when-third-saturday-is-some-day-in-the-middle-of-the-third-week () + (should (equal (meetup 2013 1 :saturday :third) '(2013 1 19)))) + + +(ert-deftest when-third-saturday-is-another-day-in-the-middle-of-the-third-week () + (should (equal (meetup 2013 2 :saturday :third) '(2013 2 16)))) + + +(ert-deftest when-third-sunday-is-some-day-in-the-middle-of-the-third-week () + (should (equal (meetup 2013 3 :sunday :third) '(2013 3 17)))) + + +(ert-deftest when-third-sunday-is-the-21st-the-last-day-of-the-third-week () + (should (equal (meetup 2013 4 :sunday :third) '(2013 4 21)))) + + +(ert-deftest when-fourth-monday-is-some-day-in-the-middle-of-the-fourth-week () + (should (equal (meetup 2013 3 :monday :fourth) '(2013 3 25)))) + + +(ert-deftest when-fourth-monday-is-the-22nd-the-first-day-of-the-fourth-week () + (should (equal (meetup 2013 4 :monday :fourth) '(2013 4 22)))) + + +(ert-deftest when-fourth-tuesday-is-the-28th-the-last-day-of-the-fourth-week () + (should (equal (meetup 2013 5 :tuesday :fourth) '(2013 5 28)))) + + +(ert-deftest when-fourth-tuesday-is-some-day-in-the-middle-of-the-fourth-week () + (should (equal (meetup 2013 6 :tuesday :fourth) '(2013 6 25)))) + + +(ert-deftest when-fourth-wednesday-is-some-day-in-the-middle-of-the-fourth-week () + (should (equal (meetup 2013 7 :wednesday :fourth) '(2013 7 24)))) + + +(ert-deftest when-fourth-wednesday-is-the-28th-the-last-day-of-the-fourth-week () + (should (equal (meetup 2013 8 :wednesday :fourth) '(2013 8 28)))) + + +(ert-deftest when-fourth-thursday-is-some-day-in-the-middle-of-the-fourth-week () + (should (equal (meetup 2013 9 :thursday :fourth) '(2013 9 26)))) + + +(ert-deftest when-fourth-thursday-is-another-day-in-the-middle-of-the-fourth-week () + (should (equal (meetup 2013 10 :thursday :fourth) '(2013 10 24)))) + + +(ert-deftest when-fourth-friday-is-the-22nd-the-first-day-of-the-fourth-week () + (should (equal (meetup 2013 11 :friday :fourth) '(2013 11 22)))) + + +(ert-deftest when-fourth-friday-is-some-day-in-the-middle-of-the-fourth-week () + (should (equal (meetup 2013 12 :friday :fourth) '(2013 12 27)))) + + +(ert-deftest when-fourth-saturday-is-some-day-in-the-middle-of-the-fourth-week () + (should (equal (meetup 2013 1 :saturday :fourth) '(2013 1 26)))) + + +(ert-deftest when-fourth-saturday-is-another-day-in-the-middle-of-the-fourth-week () + (should (equal (meetup 2013 2 :saturday :fourth) '(2013 2 23)))) + + +(ert-deftest when-fourth-sunday-is-some-day-in-the-middle-of-the-fourth-week () + (should (equal (meetup 2013 3 :sunday :fourth) '(2013 3 24)))) + + +(ert-deftest when-fourth-sunday-is-the-28th-the-last-day-of-the-fourth-week () + (should (equal (meetup 2013 4 :sunday :fourth) '(2013 4 28)))) + + +(ert-deftest last-monday-in-a-month-with-four-mondays () + (should (equal (meetup 2013 3 :monday :last) '(2013 3 25)))) + + +(ert-deftest last-monday-in-a-month-with-five-mondays () + (should (equal (meetup 2013 4 :monday :last) '(2013 4 29)))) + + +(ert-deftest last-tuesday-in-a-month-with-four-tuesdays () + (should (equal (meetup 2013 5 :tuesday :last) '(2013 5 28)))) + + +(ert-deftest last-tuesday-in-another-month-with-four-tuesdays () + (should (equal (meetup 2013 6 :tuesday :last) '(2013 6 25)))) + + +(ert-deftest last-wednesday-in-a-month-with-five-wednesdays () + (should (equal (meetup 2013 7 :wednesday :last) '(2013 7 31)))) + + +(ert-deftest last-wednesday-in-a-month-with-four-wednesdays () + (should (equal (meetup 2013 8 :wednesday :last) '(2013 8 28)))) + + +(ert-deftest last-thursday-in-a-month-with-four-thursdays () + (should (equal (meetup 2013 9 :thursday :last) '(2013 9 26)))) + + +(ert-deftest last-thursday-in-a-month-with-five-thursdays () + (should (equal (meetup 2013 10 :thursday :last) '(2013 10 31)))) + + +(ert-deftest last-friday-in-a-month-with-five-fridays () + (should (equal (meetup 2013 11 :friday :last) '(2013 11 29)))) + + +(ert-deftest last-friday-in-a-month-with-four-fridays () + (should (equal (meetup 2013 12 :friday :last) '(2013 12 27)))) + + +(ert-deftest last-saturday-in-a-month-with-four-saturdays () + (should (equal (meetup 2013 1 :saturday :last) '(2013 1 26)))) + + +(ert-deftest last-saturday-in-another-month-with-four-saturdays () + (should (equal (meetup 2013 2 :saturday :last) '(2013 2 23)))) + + +(ert-deftest last-sunday-in-a-month-with-five-sundays () + (should (equal (meetup 2013 3 :sunday :last) '(2013 3 31)))) + + +(ert-deftest last-sunday-in-a-month-with-four-sundays () + (should (equal (meetup 2013 4 :sunday :last) '(2013 4 28)))) + + +(ert-deftest when-last-wednesday-in-february-in-a-leap-year-is-the-29th () + (should (equal (meetup 2012 2 :wednesday :last) '(2012 2 29)))) + + +(ert-deftest last-wednesday-in-december-that-is-also-the-last-day-of-the-year () + (should (equal (meetup 2014 12 :wednesday :last) '(2014 12 31)))) + + +(ert-deftest when-last-sunday-in-february-in-a-non-leap-year-is-not-the-29th () + (should (equal (meetup 2015 2 :sunday :last) '(2015 2 22)))) + + +(ert-deftest when-first-friday-is-the-7th-the-last-day-of-the-first-week () + (should (equal (meetup 2012 12 :friday :first) '(2012 12 7)))) + + +(provide 'meetup-test) +;;; meetup-test.el ends here diff --git a/exercises/practice/meetup/meetup.el b/exercises/practice/meetup/meetup.el new file mode 100644 index 00000000..010f0c97 --- /dev/null +++ b/exercises/practice/meetup/meetup.el @@ -0,0 +1,14 @@ +;;; meetup.el --- Meetup (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun meetup (year month dayofweek schedule) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'meetup) +;;; meetup.el ends here + From 4532007cbf69fda9450839a6c4386d80ad9c6323 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Wed, 19 Jun 2024 06:15:10 +0200 Subject: [PATCH 117/162] Clean up grade-school exercise (#417) * grade-school: Remove unused function from example.el * grade-school: Fix stubs arguments - use school instead of students in line with exercise description and `example.el` - fix `add` function stub missing two arguments - fix `grade` function stub having wrong order of arguments * grade-school: Fix flycheck warnings in tests * grade-school: Provide stub for `make-school` function called by test If we provide stubs then the students will reasonably expect us to provide stubs for all the functions expected / called by the test code. --- exercises/practice/grade-school/.meta/example.el | 3 --- exercises/practice/grade-school/grade-school-test.el | 7 ++++--- exercises/practice/grade-school/grade-school.el | 8 +++++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/exercises/practice/grade-school/.meta/example.el b/exercises/practice/grade-school/.meta/example.el index 765ab6d7..9dc2f7c0 100644 --- a/exercises/practice/grade-school/.meta/example.el +++ b/exercises/practice/grade-school/.meta/example.el @@ -28,9 +28,6 @@ (defun grade (school grade) (gethash grade (school-roster school))) -(defun set-grade (school grade newval) - (puthash grade (sort newval #'string<) (school-roster school))) - (provide 'grade-school) ;;; grade-school.el ends here diff --git a/exercises/practice/grade-school/grade-school-test.el b/exercises/practice/grade-school/grade-school-test.el index e173b439..1d275368 100644 --- a/exercises/practice/grade-school/grade-school-test.el +++ b/exercises/practice/grade-school/grade-school-test.el @@ -6,9 +6,10 @@ (load-file "grade-school.el") -(declare-function roster "grade-school.el" (students)) -(declare-function add "grade-school.el" (students)) -(declare-function grade "grade-school.el" (desired-grade students)) +(declare-function make-school "grade-school.el") +(declare-function roster "grade-school.el" (school)) +(declare-function add "grade-school.el" (school name grade)) +(declare-function grade "grade-school.el" (school grade)) (ert-deftest roster-is-empty-when-no-student-is-added () diff --git a/exercises/practice/grade-school/grade-school.el b/exercises/practice/grade-school/grade-school.el index 784cae79..9c52d21d 100644 --- a/exercises/practice/grade-school/grade-school.el +++ b/exercises/practice/grade-school/grade-school.el @@ -4,14 +4,16 @@ ;;; Code: +(defun make-school () + (error "Delete this S-Expression and write your own implementation")) -(defun roster (students) +(defun roster (school) (error "Delete this S-Expression and write your own implementation")) -(defun add (students) +(defun add (school name grade) (error "Delete this S-Expression and write your own implementation")) -(defun grade (desired-grade students) +(defun grade (school grade) (error "Delete this S-Expression and write your own implementation")) From 19823ab546255616d9b0abb355fe6e5b34eff741 Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Wed, 19 Jun 2024 09:36:54 -0500 Subject: [PATCH 118/162] add two-bucket (#416) --- config.json | 8 ++ .../practice/two-bucket/.docs/instructions.md | 46 +++++++++++ .../practice/two-bucket/.meta/config.json | 19 +++++ .../practice/two-bucket/.meta/example.el | 68 ++++++++++++++++ .../practice/two-bucket/.meta/tests.toml | 37 +++++++++ .../practice/two-bucket/two-bucket-test.el | 77 +++++++++++++++++++ exercises/practice/two-bucket/two-bucket.el | 17 ++++ 7 files changed, 272 insertions(+) create mode 100644 exercises/practice/two-bucket/.docs/instructions.md create mode 100644 exercises/practice/two-bucket/.meta/config.json create mode 100644 exercises/practice/two-bucket/.meta/example.el create mode 100644 exercises/practice/two-bucket/.meta/tests.toml create mode 100644 exercises/practice/two-bucket/two-bucket-test.el create mode 100644 exercises/practice/two-bucket/two-bucket.el diff --git a/config.json b/config.json index 9256b48e..06fec252 100644 --- a/config.json +++ b/config.json @@ -870,6 +870,14 @@ "practices": [], "prerequisites": [], "difficulty": 5 + }, + { + "slug": "two-bucket", + "name": "Two Bucket", + "uuid": "2eb39d6e-52de-4822-8cd1-ef789c1f5e22", + "practices": [], + "prerequisites": [], + "difficulty": 6 } ] }, diff --git a/exercises/practice/two-bucket/.docs/instructions.md b/exercises/practice/two-bucket/.docs/instructions.md new file mode 100644 index 00000000..30d779aa --- /dev/null +++ b/exercises/practice/two-bucket/.docs/instructions.md @@ -0,0 +1,46 @@ +# Instructions + +Given two buckets of different size and which bucket to fill first, determine how many actions are required to measure an exact number of liters by strategically transferring fluid between the buckets. + +There are some rules that your solution must follow: + +- You can only do one action at a time. +- There are only 3 possible actions: + 1. Pouring one bucket into the other bucket until either: + a) the first bucket is empty + b) the second bucket is full + 2. Emptying a bucket and doing nothing to the other. + 3. Filling a bucket and doing nothing to the other. +- After an action, you may not arrive at a state where the initial starting bucket is empty and the other bucket is full. + +Your program will take as input: + +- the size of bucket one +- the size of bucket two +- the desired number of liters to reach +- which bucket to fill first, either bucket one or bucket two + +Your program should determine: + +- the total number of actions it should take to reach the desired number of liters, including the first fill of the starting bucket +- which bucket should end up with the desired number of liters - either bucket one or bucket two +- how many liters are left in the other bucket + +Note: any time a change is made to either or both buckets counts as one (1) action. + +Example: +Bucket one can hold up to 7 liters, and bucket two can hold up to 11 liters. +Let's say at a given step, bucket one is holding 7 liters and bucket two is holding 8 liters (7,8). +If you empty bucket one and make no change to bucket two, leaving you with 0 liters and 8 liters respectively (0,8), that counts as one action. +Instead, if you had poured from bucket one into bucket two until bucket two was full, resulting in 4 liters in bucket one and 11 liters in bucket two (4,11), that would also only count as one action. + +Another Example: +Bucket one can hold 3 liters, and bucket two can hold up to 5 liters. +You are told you must start with bucket one. +So your first action is to fill bucket one. +You choose to empty bucket one for your second action. +For your third action, you may not fill bucket two, because this violates the third rule -- you may not end up in a state after any action where the starting bucket is empty and the other bucket is full. + +Written with <3 at [Fullstack Academy][fullstack] by Lindsay Levine. + +[fullstack]: https://www.fullstackacademy.com/ diff --git a/exercises/practice/two-bucket/.meta/config.json b/exercises/practice/two-bucket/.meta/config.json new file mode 100644 index 00000000..c7adf309 --- /dev/null +++ b/exercises/practice/two-bucket/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "two-bucket.el" + ], + "test": [ + "two-bucket-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given two buckets of different size, demonstrate how to measure an exact number of liters.", + "source": "Water Pouring Problem", + "source_url": "https://demonstrations.wolfram.com/WaterPouringProblem/" +} diff --git a/exercises/practice/two-bucket/.meta/example.el b/exercises/practice/two-bucket/.meta/example.el new file mode 100644 index 00000000..dd4f8d01 --- /dev/null +++ b/exercises/practice/two-bucket/.meta/example.el @@ -0,0 +1,68 @@ +;;; two-bucket.el --- Two Bucket (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(define-error 'goal-not-possible "impossible") + +(cl-defstruct (bucket (:constructor make-bucket (capacity name)) + (:copier nil)) + capacity + (amount 0) + name) + +(defun empty (bucket) + (setf (bucket-amount bucket) 0)) + +(defun fill (bucket) + (setf (bucket-amount bucket) (bucket-capacity bucket))) + +(defun fullp (bucket) + (= (bucket-amount bucket) (bucket-capacity bucket))) + +(defun overflowingp (bucket) + (when (> (bucket-amount bucket) (bucket-capacity bucket)) + (- (bucket-amount bucket) (bucket-capacity bucket)))) + +(defun transfer (from-bucket to-bucket) + (cl-incf (bucket-amount to-bucket) (bucket-amount from-bucket)) + (empty from-bucket) + (when-let ((excess (overflowingp to-bucket))) + (setf (bucket-amount from-bucket) excess) + (fill to-bucket))) + +(defun unsolvablep (bucket-one bucket-two goal) + (or (cl-plusp (% goal (cl-gcd bucket-one bucket-two))) + (and (> goal bucket-one) (> goal bucket-two)))) + +(defun retrieve-results (bucket-one bucket-two goal) + (if (= goal (bucket-amount bucket-one)) + (list (bucket-name bucket-one) (bucket-amount bucket-two)) + (list (bucket-name bucket-two) (bucket-amount bucket-one)))) + +(defun iterate-through-puzzle (start-bucket other-bucket goal) + (fill start-bucket) + (cl-loop for moves from 1 + until (or (= goal (bucket-amount start-bucket)) + (= goal (bucket-amount other-bucket))) + do (cond + ((= goal (bucket-capacity other-bucket)) (fill other-bucket)) + ((fullp other-bucket) (empty other-bucket)) + ((zerop (bucket-amount start-bucket)) (fill start-bucket)) + (t (transfer start-bucket other-bucket))) + finally (return (cons moves (retrieve-results start-bucket other-bucket goal))))) + +(defun measure (bucket-one bucket-two goal start-bucket) + (if (unsolvablep bucket-one bucket-two goal) + (signal 'goal-not-possible nil) + (let* ((first-bucket (make-bucket bucket-one 'one)) + (second-bucket (make-bucket bucket-two 'two)) + (results (if (eq start-bucket 'one) + (iterate-through-puzzle first-bucket second-bucket goal) + (iterate-through-puzzle second-bucket first-bucket goal)))) + (cons (car results) (cdr results))))) + + +(provide 'two-bucket) +;;; two-bucket.el ends here diff --git a/exercises/practice/two-bucket/.meta/tests.toml b/exercises/practice/two-bucket/.meta/tests.toml new file mode 100644 index 00000000..d6ff02f5 --- /dev/null +++ b/exercises/practice/two-bucket/.meta/tests.toml @@ -0,0 +1,37 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[a6f2b4ba-065f-4dca-b6f0-e3eee51cb661] +description = "Measure using bucket one of size 3 and bucket two of size 5 - start with bucket one" + +[6c4ea451-9678-4926-b9b3-68364e066d40] +description = "Measure using bucket one of size 3 and bucket two of size 5 - start with bucket two" + +[3389f45e-6a56-46d5-9607-75aa930502ff] +description = "Measure using bucket one of size 7 and bucket two of size 11 - start with bucket one" + +[fe0ff9a0-3ea5-4bf7-b17d-6d4243961aa1] +description = "Measure using bucket one of size 7 and bucket two of size 11 - start with bucket two" + +[0ee1f57e-da84-44f7-ac91-38b878691602] +description = "Measure one step using bucket one of size 1 and bucket two of size 3 - start with bucket two" + +[eb329c63-5540-4735-b30b-97f7f4df0f84] +description = "Measure using bucket one of size 2 and bucket two of size 3 - start with bucket one and end with bucket two" + +[449be72d-b10a-4f4b-a959-ca741e333b72] +description = "Not possible to reach the goal" + +[aac38b7a-77f4-4d62-9b91-8846d533b054] +description = "With the same buckets but a different goal, then it is possible" + +[74633132-0ccf-49de-8450-af4ab2e3b299] +description = "Goal larger than both buckets is impossible" diff --git a/exercises/practice/two-bucket/two-bucket-test.el b/exercises/practice/two-bucket/two-bucket-test.el new file mode 100644 index 00000000..8fda0003 --- /dev/null +++ b/exercises/practice/two-bucket/two-bucket-test.el @@ -0,0 +1,77 @@ +;;; two-bucket-test.el --- Two Bucket (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "two-bucket.el") +(declare-function measure "two-bucket.el" (bucket-one bucket-two goal start-bucket)) + + +(ert-deftest measure-using-bucket-one-of-size-3-and-bucket-two-of-size-5-start-with-bucket-one () + ;; Function under test: measure + ;; Input: {"bucketOne":3,"bucketTwo":5,"goal":1,"startBucket":"one"} + ;; Expected: {"moves":4,"goalBucket":"one","otherBucket":5} + (should (equal (measure 3 5 1 'one) '(4 one 5)))) + + +(ert-deftest measure-using-bucket-one-of-size-3-and-bucket-two-of-size-5-start-with-bucket-two () + ;; Function under test: measure + ;; Input: {"bucketOne":3,"bucketTwo":5,"goal":1,"startBucket":"two"} + ;; Expected: {"moves":8,"goalBucket":"two","otherBucket":3} + (should (equal (measure 3 5 1 'two) '(8 two 3)))) + + +(ert-deftest measure-using-bucket-one-of-size-7-and-bucket-two-of-size-11-start-with-bucket-one () + ;; Function under test: measure + ;; Input: {"bucketOne":7,"bucketTwo":11,"goal":2,"startBucket":"one"} + ;; Expected: {"moves":14,"goalBucket":"one","otherBucket":11} + (should (equal (measure 7 11 2 'one) '(14 one 11)))) + + +(ert-deftest measure-using-bucket-one-of-size-7-and-bucket-two-of-size-11-start-with-bucket-two () + ;; Function under test: measure + ;; Input: {"bucketOne":7,"bucketTwo":11,"goal":2,"startBucket":"two"} + ;; Expected: {"moves":18,"goalBucket":"two","otherBucket":7} + (should (equal (measure 7 11 2 'two) '(18 two 7)))) + + +(ert-deftest measure-one-step-using-bucket-one-of-size-1-and-bucket-two-of-size-3-start-with-bucket-two () + ;; Function under test: measure + ;; Input: {"bucketOne":1,"bucketTwo":3,"goal":3,"startBucket":"two"} + ;; Expected: {"moves":1,"goalBucket":"two","otherBucket":0} + (should (equal (measure 1 3 3 'two) '(1 two 0)))) + + +(ert-deftest measure-using-bucket-one-of-size-2-and-bucket-two-of-size-3-start-with-bucket-one-and-end-with-bucket-two () + ;; Function under test: measure + ;; Input: {"bucketOne":2,"bucketTwo":3,"goal":3,"startBucket":"one"} + ;; Expected: {"moves":2,"goalBucket":"two","otherBucket":2} + (should (equal (measure 2 3 3 'one) '(2 two 2)))) + + +(ert-deftest not-possible-to-reach-the-goal () + ;; Function under test: measure + ;; Input: {"bucketOne":6,"bucketTwo":15,"goal":5,"startBucket":"one"} + ;; Expected: {"error":"impossible"} + (should-error (measure 6 15 5 'one) :type 'goal-not-possible)) + + +(ert-deftest with-the-same-buckets-but-a-different-goal-then-it-is-possible () + ;; Function under test: measure + ;; Input: {"bucketOne":6,"bucketTwo":15,"goal":9,"startBucket":"one"} + ;; Expected: {"moves":10,"goalBucket":"two","otherBucket":0} + (should (equal (measure 6 15 9 'one) '(10 two 0)))) + + +(ert-deftest goal-larger-than-both-buckets-is-impossible () + ;; Function under test: measure + ;; Input: {"bucketOne":5,"bucketTwo":7,"goal":8,"startBucket":"one"} + ;; Expected: {"error":"impossible"} + (should-error (measure 5 7 8 'one) :type 'goal-not-possible)) + + +(provide 'two-bucket-test) +;;; two-bucket-test.el ends here + diff --git a/exercises/practice/two-bucket/two-bucket.el b/exercises/practice/two-bucket/two-bucket.el new file mode 100644 index 00000000..58a1fadd --- /dev/null +++ b/exercises/practice/two-bucket/two-bucket.el @@ -0,0 +1,17 @@ +;;; two-bucket.el --- Two Bucket (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(define-error 'goal-not-possible + (error "Delete this S-Expression and write your own implementation")) + +(defun measure (bucket-one bucket-two goal start-bucket) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'two-bucket) +;;; two-bucket.el ends here + From f55df54a64696ccb77ee24f2411e22ec915e1581 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Wed, 19 Jun 2024 22:44:00 +0200 Subject: [PATCH 119/162] practice-exercise-generator: Don't include commas in test names (#420) fixes #419 --- tools/practice-exercise-generator.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/practice-exercise-generator.el b/tools/practice-exercise-generator.el index 09548633..5b4d7862 100644 --- a/tools/practice-exercise-generator.el +++ b/tools/practice-exercise-generator.el @@ -171,7 +171,9 @@ Each hash-table has the keys: ("test-name" (string-inflection-kebab-case-function (replace-regexp-in-string - "[ |_]" "-" (gethash "description" elem)))) + "," "" + (replace-regexp-in-string + "[ |_]" "-" (gethash "description" elem))))) ("uuid" (gethash "uuid" elem)) ("reimplements" (gethash "reimplements" elem)) ("function-under-test" From bfde2aab4cd60302fd8a198e1e5307425a23a11e Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Sun, 23 Jun 2024 10:04:57 -0500 Subject: [PATCH 120/162] add zebra-puzzle (#418) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add zebra-puzzle, part of 48 in 24 * Remove test comments * Remove extra EOL * Consistent spacing --------- Co-authored-by: András B Nagy <20251272+BNAndras@users.noreply.github.com> --- config.json | 8 + .../zebra-puzzle/.docs/instructions.md | 32 ++++ .../zebra-puzzle/.docs/introduction.md | 15 ++ .../practice/zebra-puzzle/.meta/config.json | 19 +++ .../practice/zebra-puzzle/.meta/example.el | 157 ++++++++++++++++++ .../practice/zebra-puzzle/.meta/tests.toml | 16 ++ .../zebra-puzzle/zebra-puzzle-test.el | 22 +++ .../practice/zebra-puzzle/zebra-puzzle.el | 18 ++ 8 files changed, 287 insertions(+) create mode 100644 exercises/practice/zebra-puzzle/.docs/instructions.md create mode 100644 exercises/practice/zebra-puzzle/.docs/introduction.md create mode 100644 exercises/practice/zebra-puzzle/.meta/config.json create mode 100644 exercises/practice/zebra-puzzle/.meta/example.el create mode 100644 exercises/practice/zebra-puzzle/.meta/tests.toml create mode 100644 exercises/practice/zebra-puzzle/zebra-puzzle-test.el create mode 100644 exercises/practice/zebra-puzzle/zebra-puzzle.el diff --git a/config.json b/config.json index 06fec252..65770b9b 100644 --- a/config.json +++ b/config.json @@ -878,6 +878,14 @@ "practices": [], "prerequisites": [], "difficulty": 6 + }, + { + "slug": "zebra-puzzle", + "name": "Zebra Puzzle", + "uuid": "bd7c4195-2d89-436b-918f-24224a95610d", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, diff --git a/exercises/practice/zebra-puzzle/.docs/instructions.md b/exercises/practice/zebra-puzzle/.docs/instructions.md new file mode 100644 index 00000000..c666e33c --- /dev/null +++ b/exercises/practice/zebra-puzzle/.docs/instructions.md @@ -0,0 +1,32 @@ +# Instructions + +Your task is to solve the Zebra Puzzle to find the answer to these two questions: + +- Which of the residents drinks water? +- Who owns the zebra? + +## Puzzle + +The following 15 statements are all known to be true: + +1. There are five houses. +2. The Englishman lives in the red house. +3. The Spaniard owns the dog. +4. Coffee is drunk in the green house. +5. The Ukrainian drinks tea. +6. The green house is immediately to the right of the ivory house. +7. The Old Gold smoker owns snails. +8. Kools are smoked in the yellow house. +9. Milk is drunk in the middle house. +10. The Norwegian lives in the first house. +11. The man who smokes Chesterfields lives in the house next to the man with the fox. +12. Kools are smoked in the house next to the house where the horse is kept. +13. The Lucky Strike smoker drinks orange juice. +14. The Japanese smokes Parliaments. +15. The Norwegian lives next to the blue house. + +Additionally, each of the five houses is painted a different color, and their inhabitants are of different national extractions, own different pets, drink different beverages and smoke different brands of cigarettes. + +~~~~exercism/note +There are 24 billion (5!⁵ = 24,883,200,000) possible solutions, so try ruling out as many solutions as possible. +~~~~ diff --git a/exercises/practice/zebra-puzzle/.docs/introduction.md b/exercises/practice/zebra-puzzle/.docs/introduction.md new file mode 100644 index 00000000..33d688fd --- /dev/null +++ b/exercises/practice/zebra-puzzle/.docs/introduction.md @@ -0,0 +1,15 @@ +# Introduction + +The Zebra Puzzle is a famous logic puzzle in which there are five houses, each painted a different color. +The houses have different inhabitants, who have different nationalities, own different pets, drink different beverages and smoke different brands of cigarettes. + +To help you solve the puzzle, you're given 15 statements describing the solution. +However, only by combining the information in _all_ statements will you be able to find the solution to the puzzle. + +~~~~exercism/note +The Zebra Puzzle is a [Constraint satisfaction problem (CSP)][constraint-satisfaction-problem]. +In such a problem, you have a set of possible values and a set of constraints that limit which values are valid. +Another well-known CSP is Sudoku. + +[constraint-satisfaction-problem]: https://en.wikipedia.org/wiki/Constraint_satisfaction_problem +~~~~ diff --git a/exercises/practice/zebra-puzzle/.meta/config.json b/exercises/practice/zebra-puzzle/.meta/config.json new file mode 100644 index 00000000..37ac3db7 --- /dev/null +++ b/exercises/practice/zebra-puzzle/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "zebra-puzzle.el" + ], + "test": [ + "zebra-puzzle-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Solve the zebra puzzle.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Zebra_Puzzle" +} diff --git a/exercises/practice/zebra-puzzle/.meta/example.el b/exercises/practice/zebra-puzzle/.meta/example.el new file mode 100644 index 00000000..c7694221 --- /dev/null +++ b/exercises/practice/zebra-puzzle/.meta/example.el @@ -0,0 +1,157 @@ +;;; zebra-puzzle.el --- Zebra Puzzle (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + +(defvar all-houses nil) + +(defvar house-constraints nil) + +(defvar feasible-houses nil) + +(defvar street-constraints nil) + +(defvar two-house-constraints nil) + +(defvar feasible-streets nil) + +(defvar all-streets nil) + +(defvar houses-by-number nil) + +(cl-defstruct house + number color owner pet drink smokes) + +(setq all-houses + (cl-loop for n in '(1 2 3 4 5) + append (cl-loop for c in '(red green ivory yellow blue) + append (cl-loop for o in '(Englishman Spaniard Ukrainian Norwegian Japanese) + append (cl-loop for p in '(dog snails fox horse zebra) + append (cl-loop for d in '(coffee tea milk orange-juice water) + append (cl-loop for s in '(Old-Gold Kools Chesterfields Lucky-Strike Parliaments) + collect (make-house :number n :color c :owner o :pet p :drink d :smokes s)))))))) + +(setq house-constraints + (list + (lambda (h) (equal (equal (house-owner h) 'Englishman) + (equal (house-color h) 'red))) + (lambda (h) (equal (equal (house-owner h) 'Spaniard) + (equal (house-pet h) 'dog))) + (lambda (h) (equal (equal (house-drink h) 'coffee) + (equal (house-color h) 'green))) + (lambda (h) (equal (equal (house-owner h) 'Ukrainian) + (equal (house-drink h) 'tea))) + (lambda (h) (equal (equal (house-smokes h) 'Old-Gold) + (equal (house-pet h) 'snails))) + (lambda (h) (equal (equal (house-smokes h) 'Kools) + (equal (house-color h) 'yellow))) + (lambda (h) (equal (equal (house-drink h) 'milk) + (= (house-number h) 3))) + (lambda (h) (equal (equal (house-owner h) 'Norwegian) + (= (house-number h) 1))) + (lambda (h) (equal (equal (house-smokes h) 'Lucky-Strike) + (equal (house-drink h) 'orange-juice))) + (lambda (h) (equal (equal (house-owner h) 'Japanese) + (equal (house-smokes h) 'Parliaments))) + (lambda (h) (equal (= (house-number h) 2) + (equal (house-color h) 'blue))) + (lambda (h) (if (equal (house-color h) 'green) + (not (= (house-number h) 1)) + t)) + (lambda (h) (if (equal (house-color h) 'ivory) + (not (= (house-number h) 5)) + t)))) + +(defun apply-constraints (constraints items) + "Apply a list of CONSTRAINTS to a list of ITEMS." + (cl-loop for constraint in constraints + do (setq items (cl-remove-if-not constraint items)) + finally return items)) + +(setq feasible-houses + (apply-constraints house-constraints all-houses)) + +(defun next-door? (h1 h2) + "Check if two houses, H1 and H2, are next to each other." + (= (abs (- (house-number h1) (house-number h2))) 1)) + +(setq two-house-constraints + (list + (lambda (h1 h2) + (if (and (equal (house-color h1) 'green) + (equal (house-color h2) 'ivory)) + (= (house-number h1) (1+ (house-number h2))) + t)) + (lambda (h1 h2) + (if (and (equal (house-smokes h1) 'Chesterfields) + (equal (house-pet h2) 'fox)) + (next-door? h1 h2) + t)) + (lambda (h1 h2) + (if (and (equal (house-smokes h1) 'Kools) + (equal (house-pet h2) 'horse)) + (next-door? h1 h2) + t)))) + +(defun check-street (constraint street) + "Check if all pairs of houses in STREET satisfy CONSTRAINT." + (cl-loop for h1 in street + always (cl-loop for h2 in street + always (funcall constraint h1 h2)))) + +(setq street-constraints + (mapcar (lambda (c) + (lambda (s) (check-street c s))) + two-house-constraints)) + +(setq houses-by-number + (cl-loop for n in '(1 2 3 4 5) + collect (cl-remove-if-not (lambda (h) (= n (house-number h))) feasible-houses))) + +(defun disjoint? (h1 h2) + "Check if two houses, H1 and H2, are disjoint in terms of their attributes." + (not (or (equal (house-color h1) (house-color h2)) + (equal (house-owner h1) (house-owner h2)) + (equal (house-pet h1) (house-pet h2)) + (equal (house-drink h1) (house-drink h2)) + (equal (house-smokes h1) (house-smokes h2))))) + +(defun extends? (street h) + "Check if a house, H, can be added to a STREET." + (cl-every (lambda (h1) (disjoint? h h1)) street)) + +(defun build-streets (houses street) + "Recursively build all possible STREET with HOUSES." + (if (null houses) + (list street) + (cl-loop for h in (car houses) + when (extends? street h) + append (build-streets (cdr houses) (cons h street))))) + +(setq all-streets + (build-streets houses-by-number '())) + +(setq feasible-streets + (apply-constraints street-constraints all-streets)) + +(defun find-owner (condition) + "Find the owner of a house based on a CONDITION." + (if (= 1 (length feasible-streets)) + (cl-loop for h in (car feasible-streets) + if (funcall condition h) + return (house-owner h)) + nil)) + +(defun owns-zebra () + "Find the owner of the zebra." + (find-owner (lambda (h) (equal (house-pet h) 'zebra)))) + +(defun drinks-water () + "Find the owner of the house where water is drunk." + (find-owner (lambda (h) (equal (house-drink h) 'water)))) + +(provide 'zebra-puzzle) +;;; zebra-puzzle.el ends here diff --git a/exercises/practice/zebra-puzzle/.meta/tests.toml b/exercises/practice/zebra-puzzle/.meta/tests.toml new file mode 100644 index 00000000..56c21c7a --- /dev/null +++ b/exercises/practice/zebra-puzzle/.meta/tests.toml @@ -0,0 +1,16 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[16efb4e4-8ad7-4d5e-ba96-e5537b66fd42] +description = "resident who drinks water" + +[084d5b8b-24e2-40e6-b008-c800da8cd257] +description = "resident who owns zebra" diff --git a/exercises/practice/zebra-puzzle/zebra-puzzle-test.el b/exercises/practice/zebra-puzzle/zebra-puzzle-test.el new file mode 100644 index 00000000..249e9e92 --- /dev/null +++ b/exercises/practice/zebra-puzzle/zebra-puzzle-test.el @@ -0,0 +1,22 @@ +;;; zebra-puzzle-test.el --- Zebra Puzzle (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "zebra-puzzle.el") +(declare-function drinks-water "zebra-puzzle.el" ()) +(declare-function owns-zebra "zebra-puzzle.el" ()) + + +(ert-deftest resident-who-drinks-water () + (should (string= (drinks-water) "Norwegian"))) + + +(ert-deftest resident-who-owns-zebra () + (should (string= (owns-zebra) "Japanese"))) + + +(provide 'zebra-puzzle-test) +;;; zebra-puzzle-test.el ends here diff --git a/exercises/practice/zebra-puzzle/zebra-puzzle.el b/exercises/practice/zebra-puzzle/zebra-puzzle.el new file mode 100644 index 00000000..4bd0ce93 --- /dev/null +++ b/exercises/practice/zebra-puzzle/zebra-puzzle.el @@ -0,0 +1,18 @@ +;;; zebra-puzzle.el --- Zebra Puzzle (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun drinks-water () + (error "Delete this S-Expression and write your own implementation")) + + +(defun owns-zebra () + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'zebra-puzzle) +;;; zebra-puzzle.el ends here + From 682ca3ec9020e6b262a6799c8138c1343f649035 Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Tue, 25 Jun 2024 15:03:51 -0500 Subject: [PATCH 121/162] add strain exercise (#423) --- config.json | 8 ++ .../practice/strain/.docs/instructions.md | 29 +++++++ exercises/practice/strain/.meta/config.json | 19 ++++ exercises/practice/strain/.meta/example.el | 24 ++++++ exercises/practice/strain/.meta/tests.toml | 52 +++++++++++ exercises/practice/strain/strain-test.el | 86 +++++++++++++++++++ exercises/practice/strain/strain.el | 17 ++++ 7 files changed, 235 insertions(+) create mode 100644 exercises/practice/strain/.docs/instructions.md create mode 100644 exercises/practice/strain/.meta/config.json create mode 100644 exercises/practice/strain/.meta/example.el create mode 100644 exercises/practice/strain/.meta/tests.toml create mode 100644 exercises/practice/strain/strain-test.el create mode 100644 exercises/practice/strain/strain.el diff --git a/config.json b/config.json index 65770b9b..7b6c2294 100644 --- a/config.json +++ b/config.json @@ -886,6 +886,14 @@ "practices": [], "prerequisites": [], "difficulty": 5 + }, + { + "slug": "strain", + "name": "Strain", + "uuid": "daff70f7-504a-4ba5-89a5-1a2860dcd98e", + "practices": [], + "prerequisites": [], + "difficulty": 2 } ] }, diff --git a/exercises/practice/strain/.docs/instructions.md b/exercises/practice/strain/.docs/instructions.md new file mode 100644 index 00000000..3469ae65 --- /dev/null +++ b/exercises/practice/strain/.docs/instructions.md @@ -0,0 +1,29 @@ +# Instructions + +Implement the `keep` and `discard` operation on collections. +Given a collection and a predicate on the collection's elements, `keep` returns a new collection containing those elements where the predicate is true, while `discard` returns a new collection containing those elements where the predicate is false. + +For example, given the collection of numbers: + +- 1, 2, 3, 4, 5 + +And the predicate: + +- is the number even? + +Then your keep operation should produce: + +- 2, 4 + +While your discard operation should produce: + +- 1, 3, 5 + +Note that the union of keep and discard is all the elements. + +The functions may be called `keep` and `discard`, or they may need different names in order to not clash with existing functions or concepts in your language. + +## Restrictions + +Keep your hands off that filter/reject/whatchamacallit functionality provided by your standard library! +Solve this one yourself using other basic tools instead. diff --git a/exercises/practice/strain/.meta/config.json b/exercises/practice/strain/.meta/config.json new file mode 100644 index 00000000..2165d6b3 --- /dev/null +++ b/exercises/practice/strain/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "strain.el" + ], + "test": [ + "strain-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Implement the `keep` and `discard` operation on collections.", + "source": "Conversation with James Edward Gray II", + "source_url": "http://graysoftinc.com/" +} diff --git a/exercises/practice/strain/.meta/example.el b/exercises/practice/strain/.meta/example.el new file mode 100644 index 00000000..7f7f0a41 --- /dev/null +++ b/exercises/practice/strain/.meta/example.el @@ -0,0 +1,24 @@ +;;; strain.el --- Strain (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun keep (predicate list) + "Return a list of elements in COLLECTION for which PREDICATE returns true." + (let (result) + (dolist (element list (nreverse result)) + (when (funcall predicate element) + (push element result))))) + +(defun discard (predicate list) + "Return a list of elements in COLLECTION for which PREDICATE returns false." + (let (result) + (dolist (element list (nreverse result)) + (unless (funcall predicate element) + (push element result))))) + + +(provide 'strain) +;;; strain.el ends here diff --git a/exercises/practice/strain/.meta/tests.toml b/exercises/practice/strain/.meta/tests.toml new file mode 100644 index 00000000..3a617b4a --- /dev/null +++ b/exercises/practice/strain/.meta/tests.toml @@ -0,0 +1,52 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[26af8c32-ba6a-4eb3-aa0a-ebd8f136e003] +description = "keep on empty list returns empty list" + +[f535cb4d-e99b-472a-bd52-9fa0ffccf454] +description = "keeps everything" + +[950b8e8e-f628-42a8-85e2-9b30f09cde38] +description = "keeps nothing" + +[92694259-6e76-470c-af87-156bdf75018a] +description = "keeps first and last" + +[938f7867-bfc7-449e-a21b-7b00cbb56994] +description = "keeps neither first nor last" + +[8908e351-4437-4d2b-a0f7-770811e48816] +description = "keeps strings" + +[2728036b-102a-4f1e-a3ef-eac6160d876a] +description = "keeps lists" + +[ef16beb9-8d84-451a-996a-14e80607fce6] +description = "discard on empty list returns empty list" + +[2f42f9bc-8e06-4afe-a222-051b5d8cd12a] +description = "discards everything" + +[ca990fdd-08c2-4f95-aa50-e0f5e1d6802b] +description = "discards nothing" + +[71595dae-d283-48ca-a52b-45fa96819d2f] +description = "discards first and last" + +[ae141f79-f86d-4567-b407-919eaca0f3dd] +description = "discards neither first nor last" + +[daf25b36-a59f-4f29-bcfe-302eb4e43609] +description = "discards strings" + +[a38d03f9-95ad-4459-80d1-48e937e4acaf] +description = "discards lists" diff --git a/exercises/practice/strain/strain-test.el b/exercises/practice/strain/strain-test.el new file mode 100644 index 00000000..b73d08e5 --- /dev/null +++ b/exercises/practice/strain/strain-test.el @@ -0,0 +1,86 @@ +;;; strain-test.el --- Strain (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "strain.el") +(declare-function keep "strain.el" (predicate list)) +(declare-function discard "strain.el" (predicate list)) + + +(defun starts-with (string prefix) + (string-prefix-p prefix string)) + + +(defun contains (list element) + (member element list)) + + +(ert-deftest keep-on-empty-list-returns-empty-list () + (should (equal (keep (lambda (x) t) '()) '()))) + + +(ert-deftest keeps-everything () + (should (equal (keep (lambda (x) t) '(1 3 5)) '(1 3 5)))) + + +(ert-deftest keeps-nothing () + (should (equal (keep (lambda (x) nil) '(1 3 5)) '()))) + + +(ert-deftest keeps-first-and-last () + (should (equal (keep (lambda (x) (= 1 (% x 2))) '(1 2 3)) '(1 3)))) + + +(ert-deftest keeps-neither-first-nor-last () + (should (equal (keep (lambda (x) (= 0 (% x 2))) '(1 2 3)) '(2)))) + + +(ert-deftest keeps-strings () + (should (equal (keep (lambda (x) (starts-with x "z")) + '("apple" "zebra" "banana" "zombies" "cherimoya" "zealot")) + '("zebra" "zombies" "zealot")))) + + +(ert-deftest keeps-lists () + (should (equal (keep (lambda (x) (contains x 5)) + '((1 2 3) (5 5 5) (5 1 2) (2 1 2) (1 5 2) (2 2 1) (1 2 5))) + '((5 5 5) (5 1 2) (1 5 2) (1 2 5))))) + + +(ert-deftest discard-on-empty-list-returns-empty-list () + (should (equal (discard (lambda (x) t) '()) '()))) + + +(ert-deftest discards-everything () + (should (equal (discard (lambda (x) t) '(1 3 5)) '()))) + + +(ert-deftest discards-nothing () + (should (equal (discard (lambda (x) nil) '(1 3 5)) '(1 3 5)))) + + +(ert-deftest discards-first-and-last () + (should (equal (discard (lambda (x) (= (mod x 2) 1)) '(1 2 3)) '(2)))) + + +(ert-deftest discards-neither-first-nor-last () + (should (equal (discard (lambda (x) (= (mod x 2) 0)) '(1 2 3)) '(1 3)))) + + +(ert-deftest discards-strings () + (should (equal (discard (lambda (x) (starts-with x "z")) + '("apple" "zebra" "banana" "zombies" "cherimoya" "zealot")) + '("apple" "banana" "cherimoya")))) + + +(ert-deftest discards-lists () + (should (equal (discard (lambda (x) (contains x 5)) + '((1 2 3) (5 5 5) (5 1 2) (2 1 2) (1 5 2) (2 2 1) (1 2 5))) + '((1 2 3) (2 1 2) (2 2 1))))) + + +(provide 'strain-test) +;;; strain-test.el ends here diff --git a/exercises/practice/strain/strain.el b/exercises/practice/strain/strain.el new file mode 100644 index 00000000..457ccbb3 --- /dev/null +++ b/exercises/practice/strain/strain.el @@ -0,0 +1,17 @@ +;;; strain.el --- Strain (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun keep (predicate list) + (error "Delete this S-Expression and write your own implementation")) + +(defun discard (predicate list) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'strain) +;;; strain.el ends here + From 6495c13d84e2099c7e60c3e90ba03506caad1854 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Wed, 26 Jun 2024 15:48:08 +0200 Subject: [PATCH 122/162] Upgrade CI test run to Emacs 29.4 (#424) * Upgrade CI run to Emacs 29.4 * Don't need to update purcell/setup-emacs --- .github/workflows/ci.yml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 965e6e63..b426e1de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: purcell/setup-emacs@c851e5408f2d2f657fa80375bbe3fb35029aa488 with: - version: 29.3 + version: 29.4 - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.0.0 diff --git a/README.md b/README.md index 64f4b532..ff79e989 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This repo holds all the instructions, tests, code, & support files for Emacs Lisp _exercises_ currently under development or implemented & available for students. If you haven't already, you can check out and study the live language track [here][exercism-emacs-lisp-track]. -🌟   The test runner is currently running Emacs 29.3 +🌟   The test runner is currently running Emacs 29.4 Currently the Emacs Lisp track doesn't feature a syllabus, so it only contains practice exercises. Practice exercises are open-ended problems that allow you to build and test your knowledge of a programming language. You can find the practice exercises referenced in the [config.json][config-json] and the files in the [`exercises/practice`][emacs-lisp-exercises-practice-dir] directory. The practice exercises are shared between tracks. You can find the canonical problem description in the [problem specifications repository][problem-specifications-repository]. From 03bbe90e2921479021b68d516149fd78ce1e9b02 Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Fri, 28 Jun 2024 18:44:31 -0500 Subject: [PATCH 123/162] add proverb exercise (#426) --- config.json | 8 ++++ .../practice/proverb/.docs/instructions.md | 19 ++++++++ exercises/practice/proverb/.meta/config.json | 19 ++++++++ exercises/practice/proverb/.meta/example.el | 19 ++++++++ exercises/practice/proverb/.meta/tests.toml | 28 +++++++++++ exercises/practice/proverb/proverb-test.el | 48 +++++++++++++++++++ exercises/practice/proverb/proverb.el | 14 ++++++ 7 files changed, 155 insertions(+) create mode 100644 exercises/practice/proverb/.docs/instructions.md create mode 100644 exercises/practice/proverb/.meta/config.json create mode 100644 exercises/practice/proverb/.meta/example.el create mode 100644 exercises/practice/proverb/.meta/tests.toml create mode 100644 exercises/practice/proverb/proverb-test.el create mode 100644 exercises/practice/proverb/proverb.el diff --git a/config.json b/config.json index 7b6c2294..bc26cbe9 100644 --- a/config.json +++ b/config.json @@ -894,6 +894,14 @@ "practices": [], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "proverb", + "name": "Proverb", + "uuid": "e946ec2a-749a-4018-877b-25c42d4ee5b0", + "practices": [], + "prerequisites": [], + "difficulty": 2 } ] }, diff --git a/exercises/practice/proverb/.docs/instructions.md b/exercises/practice/proverb/.docs/instructions.md new file mode 100644 index 00000000..f6fb8593 --- /dev/null +++ b/exercises/practice/proverb/.docs/instructions.md @@ -0,0 +1,19 @@ +# Instructions + +For want of a horseshoe nail, a kingdom was lost, or so the saying goes. + +Given a list of inputs, generate the relevant proverb. +For example, given the list `["nail", "shoe", "horse", "rider", "message", "battle", "kingdom"]`, you will output the full text of this proverbial rhyme: + +```text +For want of a nail the shoe was lost. +For want of a shoe the horse was lost. +For want of a horse the rider was lost. +For want of a rider the message was lost. +For want of a message the battle was lost. +For want of a battle the kingdom was lost. +And all for the want of a nail. +``` + +Note that the list of inputs may vary; your solution should be able to handle lists of arbitrary length and content. +No line of the output text should be a static, unchanging string; all should vary according to the input given. diff --git a/exercises/practice/proverb/.meta/config.json b/exercises/practice/proverb/.meta/config.json new file mode 100644 index 00000000..ff212aa9 --- /dev/null +++ b/exercises/practice/proverb/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "proverb.el" + ], + "test": [ + "proverb-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "For want of a horseshoe nail, a kingdom was lost, or so the saying goes. Output the full text of this proverbial rhyme.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/For_Want_of_a_Nail" +} diff --git a/exercises/practice/proverb/.meta/example.el b/exercises/practice/proverb/.meta/example.el new file mode 100644 index 00000000..083270bd --- /dev/null +++ b/exercises/practice/proverb/.meta/example.el @@ -0,0 +1,19 @@ +;;; proverb.el --- Proverb (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun recite (strings) + (let ((n (length strings))) + (cond ((= n 0) '()) + ((= n 1) (list (format "And all for the want of a %s." (car strings)))) + (t (append (cl-loop for i from 0 to (- n 2) + collect (format "For want of a %s the %s was lost." (nth i strings) (nth (1+ i) strings))) + (list (format "And all for the want of a %s." (car strings)))))))) + + +(provide 'proverb) +;;; proverb.el ends here + diff --git a/exercises/practice/proverb/.meta/tests.toml b/exercises/practice/proverb/.meta/tests.toml new file mode 100644 index 00000000..dc92a0c9 --- /dev/null +++ b/exercises/practice/proverb/.meta/tests.toml @@ -0,0 +1,28 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[e974b73e-7851-484f-8d6d-92e07fe742fc] +description = "zero pieces" + +[2fcd5f5e-8b82-4e74-b51d-df28a5e0faa4] +description = "one piece" + +[d9d0a8a1-d933-46e2-aa94-eecf679f4b0e] +description = "two pieces" + +[c95ef757-5e94-4f0d-a6cb-d2083f5e5a83] +description = "three pieces" + +[433fb91c-35a2-4d41-aeab-4de1e82b2126] +description = "full proverb" + +[c1eefa5a-e8d9-41c7-91d4-99fab6d6b9f7] +description = "four pieces modernized" diff --git a/exercises/practice/proverb/proverb-test.el b/exercises/practice/proverb/proverb-test.el new file mode 100644 index 00000000..8f5f1412 --- /dev/null +++ b/exercises/practice/proverb/proverb-test.el @@ -0,0 +1,48 @@ +;;; proverb-test.el --- Proverb (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "proverb.el") +(declare-function recite "proverb.el" (strings)) + + +(ert-deftest zero-pieces () + (should (equal (recite '()) '()))) + + +(ert-deftest one-piece () + (should (equal (recite '("nail")) '("And all for the want of a nail.")))) + + +(ert-deftest two-pieces () + (should (equal (recite '("nail" "shoe")) '("For want of a nail the shoe was lost." "And all for the want of a nail.")))) + + +(ert-deftest three-pieces () + (should (equal (recite '("nail" "shoe" "horse")) '("For want of a nail the shoe was lost." "For want of a shoe the horse was lost." "And all for the want of a nail.")))) + + +(ert-deftest full-proverb () + (should (equal (recite '("nail" "shoe" "horse" "rider" "message" "battle" "kingdom")) + '("For want of a nail the shoe was lost." + "For want of a shoe the horse was lost." + "For want of a horse the rider was lost." + "For want of a rider the message was lost." + "For want of a message the battle was lost." + "For want of a battle the kingdom was lost." + "And all for the want of a nail.")))) + + +(ert-deftest four-pieces-modernized () + (should (equal (recite '("pin" "gun" "soldier" "battle")) + '("For want of a pin the gun was lost." + "For want of a gun the soldier was lost." + "For want of a soldier the battle was lost." + "And all for the want of a pin.")))) + + +(provide 'proverb-test) +;;; proverb-test.el ends here diff --git a/exercises/practice/proverb/proverb.el b/exercises/practice/proverb/proverb.el new file mode 100644 index 00000000..dd9ae8b8 --- /dev/null +++ b/exercises/practice/proverb/proverb.el @@ -0,0 +1,14 @@ +;;; proverb.el --- Proverb (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun recite (strings) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'proverb) +;;; proverb.el ends here + From 0bd76f984dd5bb4cdbf2611f01260e9908114aaf Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Fri, 28 Jun 2024 18:52:18 -0500 Subject: [PATCH 124/162] add say exercise (#425) --- config.json | 10 ++- exercises/practice/say/.docs/instructions.md | 48 +++++++++++ exercises/practice/say/.meta/config.json | 19 +++++ exercises/practice/say/.meta/example.el | 54 ++++++++++++ exercises/practice/say/.meta/tests.toml | 67 +++++++++++++++ exercises/practice/say/say-test.el | 89 ++++++++++++++++++++ exercises/practice/say/say.el | 18 ++++ 7 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 exercises/practice/say/.docs/instructions.md create mode 100644 exercises/practice/say/.meta/config.json create mode 100644 exercises/practice/say/.meta/example.el create mode 100644 exercises/practice/say/.meta/tests.toml create mode 100644 exercises/practice/say/say-test.el create mode 100644 exercises/practice/say/say.el diff --git a/config.json b/config.json index bc26cbe9..1a6f6612 100644 --- a/config.json +++ b/config.json @@ -902,6 +902,14 @@ "practices": [], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "say", + "name": "Say", + "uuid": "7a6c586a-c8fa-4313-8036-5ff21097702c", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, @@ -948,4 +956,4 @@ "typing/strong", "used_for/scripts" ] -} +} \ No newline at end of file diff --git a/exercises/practice/say/.docs/instructions.md b/exercises/practice/say/.docs/instructions.md new file mode 100644 index 00000000..ad3d3477 --- /dev/null +++ b/exercises/practice/say/.docs/instructions.md @@ -0,0 +1,48 @@ +# Instructions + +Given a number from 0 to 999,999,999,999, spell out that number in English. + +## Step 1 + +Handle the basic case of 0 through 99. + +If the input to the program is `22`, then the output should be `'twenty-two'`. + +Your program should complain loudly if given a number outside the blessed range. + +Some good test cases for this program are: + +- 0 +- 14 +- 50 +- 98 +- -1 +- 100 + +### Extension + +If you're on a Mac, shell out to Mac OS X's `say` program to talk out loud. +If you're on Linux or Windows, eSpeakNG may be available with the command `espeak`. + +## Step 2 + +Implement breaking a number up into chunks of thousands. + +So `1234567890` should yield a list like 1, 234, 567, and 890, while the far simpler `1000` should yield just 1 and 0. + +## Step 3 + +Now handle inserting the appropriate scale word between those chunks. + +So `1234567890` should yield `'1 billion 234 million 567 thousand 890'` + +The program must also report any values that are out of range. +It's fine to stop at "trillion". + +## Step 4 + +Put it all together to get nothing but plain English. + +`12345` should give `twelve thousand three hundred forty-five`. + +The program must also report any values that are out of range. diff --git a/exercises/practice/say/.meta/config.json b/exercises/practice/say/.meta/config.json new file mode 100644 index 00000000..2a649de5 --- /dev/null +++ b/exercises/practice/say/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "say.el" + ], + "test": [ + "say-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Given a number from 0 to 999,999,999,999, spell out that number in English.", + "source": "A variation on the JavaRanch CattleDrive, Assignment 4", + "source_url": "https://coderanch.com/wiki/718804" +} diff --git a/exercises/practice/say/.meta/example.el b/exercises/practice/say/.meta/example.el new file mode 100644 index 00000000..8b560a97 --- /dev/null +++ b/exercises/practice/say/.meta/example.el @@ -0,0 +1,54 @@ +;;; say.el --- Say (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(define-error 'out-of-range "input out of range") + +(defun say (number) + (when (or (< number 0) (>= number (expt 10 12))) + (signal 'out-of-range 'nil)) + (let ((ones '("zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine")) + (teens '("ten" "eleven" "twelve" "thirteen" "fourteen" "fifteen" "sixteen" "seventeen" "eighteen" "nineteen")) + (tens '("" "" "twenty" "thirty" "forty" "fifty" "sixty" "seventy" "eighty" "ninety")) + (powers '("" "thousand" "million" "billion"))) + + (defun number-to-words (n) + (let ((parts '())) + (while (> n 0) + (let* ((power (if (> n 999999999) 3 (if (> n 999999) 2 (if (> n 999) 1 0)))) + (unit (expt 1000 power)) + (quotient (/ n unit)) + (remainder (% n unit))) + (if (> quotient 0) + (push (concat (number-to-words-1000 quotient) (if (> power 0) (concat " " (nth power powers)) "")) parts)) + (setq n remainder))) + (string-join (reverse parts) " "))) + + (defun number-to-words-1000 (n) + (cond + ((< n 10) (nth n ones)) + ((< n 20) (nth (- n 10) teens)) + ((< n 100) + (let ((ten (nth (/ n 10) tens)) + (one (nth (% n 10) ones))) + (if (= (% n 10) 0) + ten + (concat ten "-" one)))) + ((< n 1000) + (let ((hundred (nth (/ n 100) ones)) + (remainder (% n 100))) + (if (= remainder 0) + (concat hundred " hundred") + (concat hundred " hundred " (number-to-words-1000 remainder))))))) + + (when (and (>= number 0) (< number (expt 10 12))) + (if (= number 0) + "zero" + (string-trim (number-to-words number)))))) + + +(provide 'say) +;;; say.el ends here + diff --git a/exercises/practice/say/.meta/tests.toml b/exercises/practice/say/.meta/tests.toml new file mode 100644 index 00000000..a5532e9e --- /dev/null +++ b/exercises/practice/say/.meta/tests.toml @@ -0,0 +1,67 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[5d22a120-ba0c-428c-bd25-8682235d83e8] +description = "zero" + +[9b5eed77-dbf6-439d-b920-3f7eb58928f6] +description = "one" + +[7c499be1-612e-4096-a5e1-43b2f719406d] +description = "fourteen" + +[f541dd8e-f070-4329-92b4-b7ce2fcf06b4] +description = "twenty" + +[d78601eb-4a84-4bfa-bf0e-665aeb8abe94] +description = "twenty-two" + +[f010d4ca-12c9-44e9-803a-27789841adb1] +description = "thirty" + +[738ce12d-ee5c-4dfb-ad26-534753a98327] +description = "ninety-nine" + +[e417d452-129e-4056-bd5b-6eb1df334dce] +description = "one hundred" + +[d6924f30-80ba-4597-acf6-ea3f16269da8] +description = "one hundred twenty-three" + +[2f061132-54bc-4fd4-b5df-0a3b778959b9] +description = "two hundred" + +[feed6627-5387-4d38-9692-87c0dbc55c33] +description = "nine hundred ninety-nine" + +[3d83da89-a372-46d3-b10d-de0c792432b3] +description = "one thousand" + +[865af898-1d5b-495f-8ff0-2f06d3c73709] +description = "one thousand two hundred thirty-four" + +[b6a3f442-266e-47a3-835d-7f8a35f6cf7f] +description = "one million" + +[2cea9303-e77e-4212-b8ff-c39f1978fc70] +description = "one million two thousand three hundred forty-five" + +[3e240eeb-f564-4b80-9421-db123f66a38f] +description = "one billion" + +[9a43fed1-c875-4710-8286-5065d73b8a9e] +description = "a big number" + +[49a6a17b-084e-423e-994d-a87c0ecc05ef] +description = "numbers below zero are out of range" + +[4d6492eb-5853-4d16-9d34-b0f61b261fd9] +description = "numbers above 999,999,999,999 are out of range" diff --git a/exercises/practice/say/say-test.el b/exercises/practice/say/say-test.el new file mode 100644 index 00000000..36770824 --- /dev/null +++ b/exercises/practice/say/say-test.el @@ -0,0 +1,89 @@ +;;; say-test.el --- Say (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "say.el") +(declare-function say "say.el" (number)) + + +(ert-deftest zero () + (should (string= (say 0) "zero"))) + + +(ert-deftest one () + (should (string= (say 1) "one"))) + + +(ert-deftest fourteen () + (should (string= (say 14) "fourteen"))) + + +(ert-deftest twenty () + (should (string= (say 20) "twenty"))) + + +(ert-deftest twenty-two () + (should (string= (say 22) "twenty-two"))) + + +(ert-deftest thirty () + (should (string= (say 30) "thirty"))) + + +(ert-deftest ninety-nine () + (should (string= (say 99) "ninety-nine"))) + + +(ert-deftest one-hundred () + (should (string= (say 100) "one hundred"))) + + +(ert-deftest one-hundred-twenty-three () + (should (string= (say 123) "one hundred twenty-three"))) + + +(ert-deftest two-hundred () + (should (string= (say 200) "two hundred"))) + + +(ert-deftest nine-hundred-ninety-nine () + (should (string= (say 999) "nine hundred ninety-nine"))) + + +(ert-deftest one-thousand () + (should (string= (say 1000) "one thousand"))) + + +(ert-deftest one-thousand-two-hundred-thirty-four () + (should (string= (say 1234) "one thousand two hundred thirty-four"))) + + +(ert-deftest one-million () + (should (string= (say 1000000) "one million"))) + + +(ert-deftest one-million-two-thousand-three-hundred-forty-five () + (should (string= (say 1002345) "one million two thousand three hundred forty-five"))) + + +(ert-deftest one-billion () + (should (string= (say 1000000000) "one billion"))) + + +(ert-deftest a-big-number () + (should (string= (say 987654321123) "nine hundred eighty-seven billion six hundred fifty-four million three hundred twenty-one thousand one hundred twenty-three"))) + + +(ert-deftest numbers-below-zero-are-out-of-range () + (should-error (say -1) :type 'out-of-range)) + + +(ert-deftest numbers-above-999999999999-are-out-of-range () + (should-error (say 1000000000000) :type 'out-of-range)) + + +(provide 'say-test) +;;; say-test.el ends here diff --git a/exercises/practice/say/say.el b/exercises/practice/say/say.el new file mode 100644 index 00000000..8c8e3167 --- /dev/null +++ b/exercises/practice/say/say.el @@ -0,0 +1,18 @@ +;;; say.el --- Say (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(define-error 'out-of-range + (error "Delete this S-Expression and write your own implementation")) + + +(defun say (number) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'say) +;;; say.el ends here + From a71b94a1009f977b1dc15c396e515a00cc8f9955 Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Mon, 1 Jul 2024 23:24:58 +1000 Subject: [PATCH 125/162] Sync protein-translation tests (#430) --- exercises/practice/protein-translation/.meta/tests.toml | 3 +++ .../practice/protein-translation/protein-translation-test.el | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/exercises/practice/protein-translation/.meta/tests.toml b/exercises/practice/protein-translation/.meta/tests.toml index 804b446e..de680e39 100644 --- a/exercises/practice/protein-translation/.meta/tests.toml +++ b/exercises/practice/protein-translation/.meta/tests.toml @@ -87,6 +87,9 @@ description = "Translation stops if STOP codon in middle of three-codon sequence [2c2a2a60-401f-4a80-b977-e0715b23b93d] description = "Translation stops if STOP codon in middle of six-codon sequence" +[f6f92714-769f-4187-9524-e353e8a41a80] +description = "Sequence of two non-STOP codons does not translate to a STOP codon" + [1e75ea2a-f907-4994-ae5c-118632a1cb0f] description = "Non-existing codon can't translate" include = false diff --git a/exercises/practice/protein-translation/protein-translation-test.el b/exercises/practice/protein-translation/protein-translation-test.el index 60575dbb..3e435098 100644 --- a/exercises/practice/protein-translation/protein-translation-test.el +++ b/exercises/practice/protein-translation/protein-translation-test.el @@ -139,6 +139,11 @@ (proteins "UGGUGUUAUUAAUGGUUU")))) +(ert-deftest sequence-of-two-non-stop-codons-does-not-translate-to-a-stop-codon () + (should (equal '("Methionine" "Methionine") + (proteins "AUGAUG")))) + + (ert-deftest unknown-amino-acids-not-part-of-a-codon-cant-translate () (should-error (proteins "XYZ"))) From 8c5e45e32d112ef29110961f531ee9eb1619c7c7 Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Mon, 1 Jul 2024 23:26:24 +1000 Subject: [PATCH 126/162] Sync exercise docs (#429) zebra-puzzle example solution updated with hobbies [no important files changed] --- .../affine-cipher/.docs/instructions.md | 4 +-- .../pascals-triangle/.docs/instructions.md | 27 ++++++++++++++++--- .../pascals-triangle/.docs/introduction.md | 22 +++++++++++++++ .../zebra-puzzle/.docs/instructions.md | 18 ++++++------- .../zebra-puzzle/.docs/introduction.md | 2 +- .../practice/zebra-puzzle/.meta/example.el | 20 +++++++------- 6 files changed, 68 insertions(+), 25 deletions(-) create mode 100644 exercises/practice/pascals-triangle/.docs/introduction.md diff --git a/exercises/practice/affine-cipher/.docs/instructions.md b/exercises/practice/affine-cipher/.docs/instructions.md index 26ce1534..4eff918d 100644 --- a/exercises/practice/affine-cipher/.docs/instructions.md +++ b/exercises/practice/affine-cipher/.docs/instructions.md @@ -18,10 +18,10 @@ E(x) = (ai + b) mod m Where: -- `i` is the letter's index from `0` to the length of the alphabet - 1 +- `i` is the letter's index from `0` to the length of the alphabet - 1. - `m` is the length of the alphabet. For the Roman alphabet `m` is `26`. -- `a` and `b` are integers which make the encryption key +- `a` and `b` are integers which make up the encryption key. Values `a` and `m` must be _coprime_ (or, _relatively prime_) for automatic decryption to succeed, i.e., they have number `1` as their only common factor (more information can be found in the [Wikipedia article about coprime integers][coprime-integers]). In case `a` is not coprime to `m`, your program should indicate that this is an error. diff --git a/exercises/practice/pascals-triangle/.docs/instructions.md b/exercises/practice/pascals-triangle/.docs/instructions.md index f5567859..0f58f006 100644 --- a/exercises/practice/pascals-triangle/.docs/instructions.md +++ b/exercises/practice/pascals-triangle/.docs/instructions.md @@ -1,8 +1,20 @@ # Instructions -Compute Pascal's triangle up to a given number of rows. +Your task is to output the first N rows of Pascal's triangle. -In Pascal's Triangle each number is computed by adding the numbers to the right and left of the current position in the previous row. +[Pascal's triangle][wikipedia] is a triangular array of positive integers. + +In Pascal's triangle, the number of values in a row is equal to its row number (which starts at one). +Therefore, the first row has one value, the second row has two values, and so on. + +The first (topmost) row has a single value: `1`. +Subsequent rows' values are computed by adding the numbers directly to the right and left of the current position in the previous row. + +If the previous row does _not_ have a value to the left or right of the current position (which only happens for the leftmost and rightmost positions), treat that position's value as zero (effectively "ignoring" it in the summation). + +## Example + +Let's look at the first 5 rows of Pascal's Triangle: ```text 1 @@ -10,5 +22,14 @@ In Pascal's Triangle each number is computed by adding the numbers to the right 1 2 1 1 3 3 1 1 4 6 4 1 -# ... etc ``` + +The topmost row has one value, which is `1`. + +The leftmost and rightmost values have only one preceding position to consider, which is the position to its right respectively to its left. +With the topmost value being `1`, it follows from this that all the leftmost and rightmost values are also `1`. + +The other values all have two positions to consider. +For example, the fifth row's (`1 4 6 4 1`) middle value is `6`, as the values to its left and right in the preceding row are `3` and `3`: + +[wikipedia]: https://en.wikipedia.org/wiki/Pascal%27s_triangle diff --git a/exercises/practice/pascals-triangle/.docs/introduction.md b/exercises/practice/pascals-triangle/.docs/introduction.md new file mode 100644 index 00000000..60b8ec30 --- /dev/null +++ b/exercises/practice/pascals-triangle/.docs/introduction.md @@ -0,0 +1,22 @@ +# Introduction + +With the weather being great, you're not looking forward to spending an hour in a classroom. +Annoyed, you enter the class room, where you notice a strangely satisfying triangle shape on the blackboard. +Whilst waiting for your math teacher to arrive, you can't help but notice some patterns in the triangle: the outer values are all ones, each subsequent row has one more value than its previous row and the triangle is symmetrical. +Weird! + +Not long after you sit down, your teacher enters the room and explains that this triangle is the famous [Pascal's triangle][wikipedia]. + +Over the next hour, your teacher reveals some amazing things hidden in this triangle: + +- It can be used to compute how many ways you can pick K elements from N values. +- It contains the Fibonacci sequence. +- If you color odd and even numbers differently, you get a beautiful pattern called the [Sierpiński triangle][wikipedia-sierpinski-triangle]. + +The teacher implores you and your classmates to lookup other uses, and assures you that there are lots more! +At that moment, the school bell rings. +You realize that for the past hour, you were completely absorbed in learning about Pascal's triangle. +You quickly grab your laptop from your bag and go outside, ready to enjoy both the sunshine _and_ the wonders of Pascal's triangle. + +[wikipedia]: https://en.wikipedia.org/wiki/Pascal%27s_triangle +[wikipedia-sierpinski-triangle]: https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle diff --git a/exercises/practice/zebra-puzzle/.docs/instructions.md b/exercises/practice/zebra-puzzle/.docs/instructions.md index c666e33c..aedce9b2 100644 --- a/exercises/practice/zebra-puzzle/.docs/instructions.md +++ b/exercises/practice/zebra-puzzle/.docs/instructions.md @@ -12,20 +12,20 @@ The following 15 statements are all known to be true: 1. There are five houses. 2. The Englishman lives in the red house. 3. The Spaniard owns the dog. -4. Coffee is drunk in the green house. +4. The person in the green house drinks coffee. 5. The Ukrainian drinks tea. 6. The green house is immediately to the right of the ivory house. -7. The Old Gold smoker owns snails. -8. Kools are smoked in the yellow house. -9. Milk is drunk in the middle house. +7. The snail owner likes to go dancing. +8. The person in the yellow house is a painter. +9. The person in the middle house drinks milk. 10. The Norwegian lives in the first house. -11. The man who smokes Chesterfields lives in the house next to the man with the fox. -12. Kools are smoked in the house next to the house where the horse is kept. -13. The Lucky Strike smoker drinks orange juice. -14. The Japanese smokes Parliaments. +11. The person who enjoys reading lives in the house next to the person with the fox. +12. The painter's house is next to the house with the horse. +13. The person who plays football drinks orange juice. +14. The Japanese person plays chess. 15. The Norwegian lives next to the blue house. -Additionally, each of the five houses is painted a different color, and their inhabitants are of different national extractions, own different pets, drink different beverages and smoke different brands of cigarettes. +Additionally, each of the five houses is painted a different color, and their inhabitants are of different national extractions, own different pets, drink different beverages and engage in different hobbies. ~~~~exercism/note There are 24 billion (5!⁵ = 24,883,200,000) possible solutions, so try ruling out as many solutions as possible. diff --git a/exercises/practice/zebra-puzzle/.docs/introduction.md b/exercises/practice/zebra-puzzle/.docs/introduction.md index 33d688fd..bbcaa6fd 100644 --- a/exercises/practice/zebra-puzzle/.docs/introduction.md +++ b/exercises/practice/zebra-puzzle/.docs/introduction.md @@ -1,7 +1,7 @@ # Introduction The Zebra Puzzle is a famous logic puzzle in which there are five houses, each painted a different color. -The houses have different inhabitants, who have different nationalities, own different pets, drink different beverages and smoke different brands of cigarettes. +The houses have different inhabitants, who have different nationalities, own different pets, drink different beverages and enjoy different hobbies. To help you solve the puzzle, you're given 15 statements describing the solution. However, only by combining the information in _all_ statements will you be able to find the solution to the puzzle. diff --git a/exercises/practice/zebra-puzzle/.meta/example.el b/exercises/practice/zebra-puzzle/.meta/example.el index c7694221..7cd80917 100644 --- a/exercises/practice/zebra-puzzle/.meta/example.el +++ b/exercises/practice/zebra-puzzle/.meta/example.el @@ -23,7 +23,7 @@ (defvar houses-by-number nil) (cl-defstruct house - number color owner pet drink smokes) + number color owner pet drink hobby) (setq all-houses (cl-loop for n in '(1 2 3 4 5) @@ -31,8 +31,8 @@ append (cl-loop for o in '(Englishman Spaniard Ukrainian Norwegian Japanese) append (cl-loop for p in '(dog snails fox horse zebra) append (cl-loop for d in '(coffee tea milk orange-juice water) - append (cl-loop for s in '(Old-Gold Kools Chesterfields Lucky-Strike Parliaments) - collect (make-house :number n :color c :owner o :pet p :drink d :smokes s)))))))) + append (cl-loop for e in '(dancing painting reading football chess) + collect (make-house :number n :color c :owner o :pet p :drink d :hobby e)))))))) (setq house-constraints (list @@ -44,18 +44,18 @@ (equal (house-color h) 'green))) (lambda (h) (equal (equal (house-owner h) 'Ukrainian) (equal (house-drink h) 'tea))) - (lambda (h) (equal (equal (house-smokes h) 'Old-Gold) + (lambda (h) (equal (equal (house-hobby h) 'dancing) (equal (house-pet h) 'snails))) - (lambda (h) (equal (equal (house-smokes h) 'Kools) + (lambda (h) (equal (equal (house-hobby h) 'painting) (equal (house-color h) 'yellow))) (lambda (h) (equal (equal (house-drink h) 'milk) (= (house-number h) 3))) (lambda (h) (equal (equal (house-owner h) 'Norwegian) (= (house-number h) 1))) - (lambda (h) (equal (equal (house-smokes h) 'Lucky-Strike) + (lambda (h) (equal (equal (house-hobby h) 'football) (equal (house-drink h) 'orange-juice))) (lambda (h) (equal (equal (house-owner h) 'Japanese) - (equal (house-smokes h) 'Parliaments))) + (equal (house-hobby h) 'chess))) (lambda (h) (equal (= (house-number h) 2) (equal (house-color h) 'blue))) (lambda (h) (if (equal (house-color h) 'green) @@ -86,12 +86,12 @@ (= (house-number h1) (1+ (house-number h2))) t)) (lambda (h1 h2) - (if (and (equal (house-smokes h1) 'Chesterfields) + (if (and (equal (house-hobby h1) 'reading) (equal (house-pet h2) 'fox)) (next-door? h1 h2) t)) (lambda (h1 h2) - (if (and (equal (house-smokes h1) 'Kools) + (if (and (equal (house-hobby h1) 'painting) (equal (house-pet h2) 'horse)) (next-door? h1 h2) t)))) @@ -117,7 +117,7 @@ (equal (house-owner h1) (house-owner h2)) (equal (house-pet h1) (house-pet h2)) (equal (house-drink h1) (house-drink h2)) - (equal (house-smokes h1) (house-smokes h2))))) + (equal (house-hobby h1) (house-hobby h2))))) (defun extends? (street h) "Check if a house, H, can be added to a STREET." From e2646c7647939914d8c7ea4e947ff3d7afe55f85 Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Wed, 3 Jul 2024 18:47:34 -0500 Subject: [PATCH 127/162] Parallel letter frequency (#422) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add parallel-letter-frequency, part of 48 in 24 * practice-exercise-generator: Don't include commas in test names (#420) fixes #419 * fix merge conflict * fix json formating issue * fix merge issue * refactor to use parallism * check if ci failure was a fluke * fix ci failure * add empty string check * return hash-table, update difficulty * cleanup, fix error * add instructions.append * Use extra file for subprocess code * bin/test-examples: Handle testing of exercises with additional files * Don't use additional solution file * add BNAndras and fapdash as contributors * Use printed representation for hash table (de)serialization * Revert changes to `bin/test-examples` See https://github.com/exercism/emacs-lisp/pull/422#discussion_r1663317223 * refactor tests * Typo fix --------- Co-authored-by: FAP <459631+fapdash@users.noreply.github.com> Co-authored-by: András B Nagy <20251272+BNAndras@users.noreply.github.com> --- config.json | 8 + .../.docs/instructions.append.md | 9 + .../.docs/instructions.md | 7 + .../.meta/config.json | 21 ++ .../.meta/example.el | 77 +++++ .../.meta/tests.toml | 49 +++ .../parallel-letter-frequency-test.el | 289 ++++++++++++++++++ .../parallel-letter-frequency.el | 14 + 8 files changed, 474 insertions(+) create mode 100644 exercises/practice/parallel-letter-frequency/.docs/instructions.append.md create mode 100644 exercises/practice/parallel-letter-frequency/.docs/instructions.md create mode 100644 exercises/practice/parallel-letter-frequency/.meta/config.json create mode 100644 exercises/practice/parallel-letter-frequency/.meta/example.el create mode 100644 exercises/practice/parallel-letter-frequency/.meta/tests.toml create mode 100644 exercises/practice/parallel-letter-frequency/parallel-letter-frequency-test.el create mode 100644 exercises/practice/parallel-letter-frequency/parallel-letter-frequency.el diff --git a/config.json b/config.json index 1a6f6612..8204ffc7 100644 --- a/config.json +++ b/config.json @@ -910,6 +910,14 @@ "practices": [], "prerequisites": [], "difficulty": 5 + }, + { + "slug": "parallel-letter-frequency", + "name": "Parallel Letter Frequency", + "uuid": "3daf3903-1eb0-49b9-827a-76e6b7ca25fb", + "practices": [], + "prerequisites": [], + "difficulty": 10 } ] }, diff --git a/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md b/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md new file mode 100644 index 00000000..b58c60a0 --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md @@ -0,0 +1,9 @@ +# Instructions append + +## Using Parallelism + +The goal of this exercise is to practice parallelism with Emacs Lisp. + +In Emacs Lisp this can be achieved by using [`asynchronous processes`](https://www.gnu.org/software/emacs/manual/html_node/elisp/Asynchronous-Processes.html#:~:text=An%20asynchronous%20process%20is%20controlled,%2Dtype%20(see%20below)). + +You may also want to look at the documentation for [`batch mode`](https://www.gnu.org/software/emacs/manual/html_node/elisp/Batch-Mode.html), [`sentinels`](https://www.gnu.org/software/emacs/manual/html_node/elisp/Sentinels.html) and [`receiving output from processes`](https://www.gnu.org/software/emacs/manual/html_node/elisp/Output-from-Processes.html). diff --git a/exercises/practice/parallel-letter-frequency/.docs/instructions.md b/exercises/practice/parallel-letter-frequency/.docs/instructions.md new file mode 100644 index 00000000..6147b90a --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/.docs/instructions.md @@ -0,0 +1,7 @@ +# Instructions + +Count the frequency of letters in texts using parallel computation. + +Parallelism is about doing things in parallel that can also be done sequentially. +A common example is counting the frequency of letters. +Employ parallelism to calculate the total frequency of each letter in a list of texts. diff --git a/exercises/practice/parallel-letter-frequency/.meta/config.json b/exercises/practice/parallel-letter-frequency/.meta/config.json new file mode 100644 index 00000000..4372e34f --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/.meta/config.json @@ -0,0 +1,21 @@ +{ + "authors": [ + "kmarker1101" + ], + "contributors": [ + "fapdash", + "BNAndras" + ], + "files": { + "solution": [ + "parallel-letter-frequency.el" + ], + "test": [ + "parallel-letter-frequency-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Count the frequency of letters in texts using parallel computation." +} diff --git a/exercises/practice/parallel-letter-frequency/.meta/example.el b/exercises/practice/parallel-letter-frequency/.meta/example.el new file mode 100644 index 00000000..11123bff --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/.meta/example.el @@ -0,0 +1,77 @@ +;;; parallel-letter-frequency.el --- Parallel Letter Frequency (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) + + +(defun clean-text (text) + (downcase (replace-regexp-in-string "[^[:alpha:]]" "" text))) + + +(defun combine-frequencies (freqs-list) + (let ((combined-freqs (make-hash-table :test 'equal))) + (dolist (freqs freqs-list) + (maphash (lambda (key value) + (puthash key (+ value (gethash key combined-freqs 0)) combined-freqs)) + freqs)) + combined-freqs)) + + +(defun calculate-frequencies (texts) + (let ((cleaned-texts (mapcar #'clean-text texts))) + (if (cl-every #'string-empty-p cleaned-texts) + (make-hash-table :test 'equal) + (let* ((num-processes (min (length cleaned-texts) (max 1 (string-to-number (shell-command-to-string "nproc"))))) + (texts-per-process (ceiling (/ (float (length cleaned-texts)) num-processes))) + (results (make-hash-table :test 'equal)) + (pending num-processes) + (final-result (make-hash-table :test 'equal)) + (processes nil)) + (dotimes (i num-processes) + (let* ((start-index (* i texts-per-process)) + (end-index (min (* (1+ i) texts-per-process) (length cleaned-texts))) + (process-texts (if (< start-index (length cleaned-texts)) + (cl-subseq cleaned-texts start-index end-index) + '()))) + (when (not (null process-texts)) + (let* ((command (prin1-to-string `(calculate-frequencies-in-subprocess ',process-texts))) + (process (make-process + :name (format "letter-freq-process-%d" i) + :buffer (generate-new-buffer (format " *letter-freq-process-%d*" i)) + :command (list "emacs" "--batch" "-l" "parallel-letter-frequency.el" "--eval" command) + :sentinel (lambda (proc _event) + (when (eq (process-status proc) 'exit) + (with-current-buffer (process-buffer proc) + (let ((result (read (buffer-string)))) + (maphash (lambda (key value) + (puthash key (+ value (gethash key results 0)) results)) + result)) + (setq pending (1- pending)) + (when (= pending 0) + (setq final-result (combine-frequencies (list results)))))))))) + (push process processes))))) + (while (> pending 0) + (sleep-for 0.1)) + final-result)))) + + +(defun calculate-frequencies-in-subprocess (texts) + (let ((freqs (make-hash-table :test 'equal))) + (dolist (text texts) + (let ((text-freqs (make-hash-table :test 'equal))) + (dolist (char (string-to-list text)) + (when (string-match-p "[[:alpha:]]" (char-to-string char)) + (puthash + char (1+ (gethash char text-freqs 0)) text-freqs))) + (maphash + (lambda (key value) + (puthash key (+ value (gethash key freqs 0)) freqs)) + text-freqs))) + (prin1 freqs))) + + +(provide 'parallel-letter-frequency) +;;; parallel-letter-frequency.el ends here diff --git a/exercises/practice/parallel-letter-frequency/.meta/tests.toml b/exercises/practice/parallel-letter-frequency/.meta/tests.toml new file mode 100644 index 00000000..0c974f7f --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/.meta/tests.toml @@ -0,0 +1,49 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[c054d642-c1fa-4234-8007-9339f2337886] +description = "no texts" + +[818031be-49dc-4675-b2f9-c4047f638a2a] +description = "one text with one letter" + +[c0b81d1b-940d-4cea-9f49-8445c69c17ae] +description = "one text with multiple letters" + +[708ff1e0-f14a-43fd-adb5-e76750dcf108] +description = "two texts with one letter" + +[1b5c28bb-4619-4c9d-8db9-a4bb9c3bdca0] +description = "two texts with multiple letters" + +[6366e2b8-b84c-4334-a047-03a00a656d63] +description = "ignore letter casing" + +[92ebcbb0-9181-4421-a784-f6f5aa79f75b] +description = "ignore whitespace" + +[bc5f4203-00ce-4acc-a5fa-f7b865376fd9] +description = "ignore punctuation" + +[68032b8b-346b-4389-a380-e397618f6831] +description = "ignore numbers" + +[aa9f97ac-3961-4af1-88e7-6efed1bfddfd] +description = "Unicode letters" + +[7b1da046-701b-41fc-813e-dcfb5ee51813] +description = "combination of lower- and uppercase letters, punctuation and white space" + +[4727f020-df62-4dcf-99b2-a6e58319cb4f] +description = "large texts" + +[adf8e57b-8e54-4483-b6b8-8b32c115884c] +description = "many small texts" diff --git a/exercises/practice/parallel-letter-frequency/parallel-letter-frequency-test.el b/exercises/practice/parallel-letter-frequency/parallel-letter-frequency-test.el new file mode 100644 index 00000000..520254f7 --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/parallel-letter-frequency-test.el @@ -0,0 +1,289 @@ +;;; parallel-letter-frequency-test.el --- Parallel Letter Frequency (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "parallel-letter-frequency.el") +(declare-function calculate-frequencies "parallel-letter-frequency.el" (texts)) + + +(defun hash-table-contains (expected actual) + (let ((result t)) + (maphash (lambda (key value) + (unless (equal (gethash key actual) value) + (setq result nil))) + expected) + result)) + + +(ert-deftest no-texts () + (let ((expected (make-hash-table :test 'equal))) + (should (hash-table-contains expected (calculate-frequencies '()))))) + + +(ert-deftest one-text-with-one-letter () + (let ((expected (make-hash-table :test 'equal))) + (puthash ?a 1 expected) + (should (hash-table-contains expected (calculate-frequencies '("a")))))) + + +(ert-deftest one-text-with-multiple-letters () + (let ((expected (make-hash-table :test 'equal))) + (puthash ?b 2 expected) + (puthash ?c 3 expected) + (puthash ?d 1 expected) + (should (hash-table-contains expected (calculate-frequencies '("bbcccd")))))) + + +(ert-deftest two-texts-with-one-letter () + (let ((expected (make-hash-table :test 'equal))) + (puthash ?e 1 expected) + (puthash ?f 1 expected) + (should (hash-table-contains expected (calculate-frequencies '("e" "f")))))) + + +(ert-deftest two-texts-with-multiple-letters () + (let ((expected (make-hash-table :test 'equal))) + (puthash ?g 2 expected) + (puthash ?h 3 expected) + (puthash ?i 1 expected) + (should (hash-table-contains expected (calculate-frequencies '("ggh" "hhi")))))) + + +(ert-deftest ignore-letter-casing () + (let ((expected (make-hash-table :test 'equal))) + (puthash ?m 2 expected) + (should (hash-table-contains expected (calculate-frequencies '("m" "M")))))) + + +(ert-deftest ignore-whitespace () + (let ((expected (make-hash-table :test 'equal))) + (should (hash-table-contains expected (calculate-frequencies '(" " "\t" "\r\n")))))) + + +(ert-deftest ignore-punctuation () + (let ((expected (make-hash-table :test 'equal))) + (should (hash-table-contains expected (calculate-frequencies '("!" "?" ";" "," ".")))))) + + +(ert-deftest ignore-numbers () + (let ((expected (make-hash-table :test 'equal))) + (should (hash-table-contains expected (calculate-frequencies '("1" "2" "3" "4" "5" "6" "7" "8" "9")))))) + + +(ert-deftest unicode-letters () + (let ((expected (make-hash-table :test 'equal))) + (puthash ?ø 1 expected) + (puthash ?φ 1 expected) + (puthash ?ほ 1 expected) + (puthash ?本 1 expected) + (should (hash-table-contains expected (calculate-frequencies '("ø" "φ" "ほ" "本")))))) + + +(ert-deftest combination-of-lower-and-uppercase-letters-punctuation-and-white-space () + (let ((expected (make-hash-table :test 'equal))) + (puthash ?a 32 expected) + (puthash ?b 4 expected) + (puthash ?c 6 expected) + (puthash ?d 14 expected) + (puthash ?e 37 expected) + (puthash ?f 7 expected) + (puthash ?g 8 expected) + (puthash ?h 29 expected) + (puthash ?i 19 expected) + (puthash ?k 6 expected) + (puthash ?l 12 expected) + (puthash ?m 7 expected) + (puthash ?n 19 expected) + (puthash ?o 22 expected) + (puthash ?p 7 expected) + (puthash ?r 17 expected) + (puthash ?s 16 expected) + (puthash ?t 30 expected) + (puthash ?u 9 expected) + (puthash ?v 2 expected) + (puthash ?w 9 expected) + (puthash ?y 4 expected) + (should (hash-table-contains expected (calculate-frequencies '("There, peeping among the cloud-wrack above a dark tower high up in the mountains, Sam saw a white star twinkle for a while. The beauty of it smote his heart, as he looked up out of the forsaken land, and hope returned to him. For like a shaft, clear and cold, the thought pierced him that in the end, the shadow was only a small and passing thing: there was light and high beauty forever beyond its reach.")))))) + + +(defvar large-text + '("I am a sick man.... I am a spiteful man. I am an unattractive man." + "I believe my liver is diseased. However, I know nothing at all about my disease, and do not" + "know for certain what ails me. I don't consult a doctor for it," + "and never have, though I have a respect for medicine and doctors." + "Besides, I am extremely superstitious, sufficiently so to respect medicine," + "anyway (I am well-educated enough not to be superstitious, but I am superstitious)." + "No, I refuse to consult a doctor from spite." + "That you probably will not understand. Well, I understand it, though." + "Of course, I can't explain who it is precisely that I am mortifying in this case by my spite:" + "I am perfectly well aware that I cannot \"pay out\" the doctors by not consulting them;" + "I know better than anyone that by all this I am only injuring myself and no one else." + "But still, if I don't consult a doctor it is from spite." + "My liver is bad, well - let it get worse!" + "I have been going on like that for a long time - twenty years. Now I am forty." + "I used to be in the government service, but am no longer." + "I was a spiteful official. I was rude and took pleasure in being so." + "I did not take bribes, you see, so I was bound to find a recompense in that, at least." + "(A poor jest, but I will not scratch it out. I wrote it thinking it would sound very witty;" + "but now that I have seen myself that I only wanted to show off in a despicable way -" + "I will not scratch it out on purpose!) When petitioners used to come for" + "information to the table at which I sat, I used to grind my teeth at them," + "and felt intense enjoyment when I succeeded in making anybody unhappy." + "I almost did succeed. For the most part they were all timid people - of course," + "they were petitioners. But of the uppish ones there was one officer in particular" + "I could not endure. He simply would not be humble, and clanked his sword in a disgusting way." + "I carried on a feud with him for eighteen months over that sword. At last I got the better of him." + "He left off clanking it. That happened in my youth, though. But do you know," + "gentlemen, what was the chief point about my spite? Why, the whole point," + "the real sting of it lay in the fact that continually, even in the moment of the acutest spleen," + "I was inwardly conscious with shame that I was not only not a spiteful but not even an embittered man," + "that I was simply scaring sparrows at random and amusing myself by it." + "I might foam at the mouth, but bring me a doll to play with, give me a cup of tea with sugar in it," + "and maybe I should be appeased. I might even be genuinely touched," + "though probably I should grind my teeth at myself afterwards and lie awake at night with shame for" + "months after. That was my way. I was lying when I said just now that I was a spiteful official." + "I was lying from spite. I was simply amusing myself with the petitioners and with the officer," + "and in reality I never could become spiteful. I was conscious every moment in myself of many," + "very many elements absolutely opposite to that. I felt them positively swarming in me," + "these opposite elements. I knew that they had been swarming in me all my life and craving some outlet from me," + "but I would not let them, would not let them, purposely would not let them come out." + "They tormented me till I was ashamed: they drove me to convulsions and - sickened me, at last," + "how they sickened me!" + "Gentlemen, I am joking, and I know myself that my jokes are not brilliant" + "but you know one can take everything as a joke. I am, perhaps, jesting against the grain." + "Gentlemen, I am tormented by questions; answer them for me. You, for instance, want to cure men of their" + "old habits and reform their will in accordance with science and good sense." + "But how do you know, not only that it is possible, but also that it is" + "desirable to reform man in that way? And what leads you to the conclusion that man's" + "inclinations need reforming? In short, how do you know that such a reformation will be a benefit to man?" + "And to go to the root of the matter, why are you so positively convinced that not to act against" + "his real normal interests guaranteed by the conclusions of reason and arithmetic is certainly always" + "advantageous for man and must always be a law for mankind? So far, you know," + "this is only your supposition. It may be the law of logic, but not the law of humanity." + "You think, gentlemen, perhaps that I am mad? Allow me to defend myself. I agree that man" + "is pre-eminently a creative animal, predestined to strive consciously for an object and to engage in engineering -" + "that is, incessantly and eternally to make new roads, wherever" + "they may lead. But the reason why he wants sometimes to go off at a tangent may just be that he is" + "predestined to make the road, and perhaps, too, that however stupid the \"direct\"" + "practical man may be, the thought sometimes will occur to him that the road almost always does lead" + "somewhere, and that the destination it leads to is less important than the process" + "of making it, and that the chief thing is to save the well-conducted child from despising engineering," + "and so giving way to the fatal idleness, which, as we all know," + "is the mother of all the vices. Man likes to make roads and to create, that is a fact beyond dispute." + "But why has he such a passionate love for destruction and chaos also?" + "Tell me that! But on that point I want to say a couple of words myself. May it not be that he loves" + "chaos and destruction (there can be no disputing that he does sometimes love it)" + "because he is instinctively afraid of attaining his object and completing the edifice he is constructing?" + "Who knows, perhaps he only loves that edifice from a distance, and is by no means" + "in love with it at close quarters; perhaps he only loves building it and does not want to live in it," + "but will leave it, when completed, for the use of les animaux domestiques -" + "such as the ants, the sheep, and so on. Now the ants have quite a different taste." + "They have a marvellous edifice of that pattern which endures for ever - the ant-heap." + "With the ant-heap the respectable race of ants began and with the ant-heap they will probably end," + "which does the greatest credit to their perseverance and good sense. But man is a frivolous and" + "incongruous creature, and perhaps, like a chess player, loves the process of the game, not the end of it." + "And who knows (there is no saying with certainty), perhaps the only goal on earth" + "to which mankind is striving lies in this incessant process of attaining, in other words," + "in life itself, and not in the thing to be attained, which must always be expressed as a formula," + "as positive as twice two makes four, and such positiveness is not life, gentlemen," + "but is the beginning of death." + "But these are all golden dreams. Oh, tell me, who was it first announced," + "who was it first proclaimed, that man only does nasty things because he does not know his own interests;" + "and that if he were enlightened, if his eyes were opened to his real normal interests," + "man would at once cease to do nasty things, would at once become good and noble because," + "being enlightened and understanding his real advantage, he would see his own advantage in the" + "good and nothing else, and we all know that not one man can, consciously, act against his own interests," + "consequently, so to say, through necessity, he would begin doing good? Oh, the babe! Oh, the pure," + "innocent child! Why, in the first place, when in all these thousands of years has there been a time" + "when man has acted only from his own interest? What is to be done with the millions of facts that bear" + "witness that men, consciously, that is fully understanding their real interests, have left them in the" + "background and have rushed headlong on another path, to meet peril and danger," + "compelled to this course by nobody and by nothing, but, as it were, simply disliking the beaten track," + "and have obstinately, wilfully, struck out another difficult, absurd way, seeking it almost in the darkness." + "So, I suppose, this obstinacy and perversity were pleasanter to them than any advantage...." + "Advantage! What is advantage? And will you take it upon yourself to define with perfect accuracy in what the" + "advantage of man consists? And what if it so happens that a man's advantage, sometimes, not only may," + "but even must, consist in his desiring in certain cases what is harmful to himself and not advantageous." + "And if so, if there can be such a case, the whole principle falls into dust. What do you think -" + "are there such cases? You laugh; laugh away, gentlemen, but only answer me: have man's advantages been" + "reckoned up with perfect certainty? Are there not some which not only have not been included but cannot" + "possibly be included under any classification? You see, you gentlemen have, to the best of my knowledge," + "taken your whole register of human advantages from the averages of statistical figures and" + "politico-economical formulas. Your advantages are prosperity, wealth, freedom, peace - and so on, and so on." + "So that the man who should, for instance, go openly and knowingly in opposition to all that list would to your thinking," + "and indeed mine, too, of course, be an obscurantist or an absolute madman: would not he? But, you know, this is" + "what is surprising: why does it so happen that all these statisticians, sages and lovers of humanity," + "when they reckon up human advantages invariably leave out one? They don't even take it into their reckoning" + "in the form in which it should be taken, and the whole reckoning depends upon that. It would be no greater matter," + "they would simply have to take it, this advantage, and add it to the list. But the trouble is, that this strange" + "advantage does not fall under any classification and is not in place in any list. I have a friend for instance ..." + "Ech! gentlemen, but of course he is your friend, too; and indeed there is no one, no one to whom he is not a friend!" + "Yes, but here I come to a stop! Gentlemen, you must excuse me for being over-philosophical;" + "it's the result of forty years underground! Allow me to indulge my fancy. You see, gentlemen, reason is an excellent thing," + "there's no disputing that, but reason is nothing but reason and satisfies only the rational side of man's nature," + "while will is a manifestation of the whole life, that is, of the whole human life including reason and all the impulses." + "And although our life, in this manifestation of it, is often worthless, yet it is life and not simply extracting square roots." + "Here I, for instance, quite naturally want to live, in order to satisfy all my capacities for life, and not simply my capacity" + "for reasoning, that is, not simply one twentieth of my capacity for life. What does reason know? Reason only knows what it has" + "succeeded in learning (some things, perhaps, it will never learn; this is a poor comfort, but why not say so frankly?)" + "and human nature acts as a whole, with everything that is in it, consciously or unconsciously, and, even it if goes wrong, it lives." + "I suspect, gentlemen, that you are looking at me with compassion; you tell me again that an enlightened and developed man," + "such, in short, as the future man will be, cannot consciously desire anything disadvantageous to himself, that that can be proved mathematically." + "I thoroughly agree, it can - by mathematics. But I repeat for the hundredth time, there is one case, one only, when man may consciously, purposely," + "desire what is injurious to himself, what is stupid, very stupid - simply in order to have the right to desire for himself even what is very stupid" + "and not to be bound by an obligation to desire only what is sensible. Of course, this very stupid thing, this caprice of ours, may be in reality," + "gentlemen, more advantageous for us than anything else on earth, especially in certain cases. And in particular it may be more advantageous than" + "any advantage even when it does us obvious harm, and contradicts the soundest conclusions of our reason concerning our advantage -" + "for in any circumstances it preserves for us what is most precious and most important - that is, our personality, our individuality." + "Some, you see, maintain that this really is the most precious thing for mankind; choice can, of course, if it chooses, be in agreement" + "with reason; and especially if this be not abused but kept within bounds. It is profitable and some- times even praiseworthy." + "But very often, and even most often, choice is utterly and stubbornly opposed to reason ... and ... and ... do you know that that," + "too, is profitable, sometimes even praiseworthy? Gentlemen, let us suppose that man is not stupid. (Indeed one cannot refuse to suppose that," + "if only from the one consideration, that, if man is stupid, then who is wise?) But if he is not stupid, he is monstrously ungrateful!" + "Phenomenally ungrateful. In fact, I believe that the best definition of man is the ungrateful biped. But that is not all, that is not his worst defect;" + "his worst defect is his perpetual moral obliquity, perpetual - from the days of the Flood to the Schleswig-Holstein period.")) + + +(ert-deftest large-texts () + (let ((expected (make-hash-table :test 'equal))) + (puthash ?a 845 expected) + (puthash ?b 155 expected) + (puthash ?c 278 expected) + (puthash ?d 359 expected) + (puthash ?e 1143 expected) + (puthash ?f 222 expected) + (puthash ?g 187 expected) + (puthash ?h 507 expected) + (puthash ?i 791 expected) + (puthash ?j 12 expected) + (puthash ?k 67 expected) + (puthash ?l 423 expected) + (puthash ?m 288 expected) + (puthash ?n 833 expected) + (puthash ?o 791 expected) + (puthash ?p 197 expected) + (puthash ?r 432 expected) + (puthash ?q 8 expected) + (puthash ?s 700 expected) + (puthash ?t 1043 expected) + (puthash ?u 325 expected) + (puthash ?v 111 expected) + (puthash ?w 223 expected) + (puthash ?x 7 expected) + (puthash ?y 251 expected) + (should (hash-table-contains expected (calculate-frequencies (split-string (mapconcat 'identity large-text "\n") "\n")))))) + + +(ert-deftest many-small-texts () + (let ((expected (make-hash-table :test 'equal))) + (puthash ?a 50 expected) + (puthash ?b 100 expected) + (puthash ?c 150 expected) + (should (hash-table-contains expected (calculate-frequencies '("abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc" "abbccc")))))) + + +(provide 'parallel-letter-frequency-test) +;;; parallel-letter-frequency-test.el ends here diff --git a/exercises/practice/parallel-letter-frequency/parallel-letter-frequency.el b/exercises/practice/parallel-letter-frequency/parallel-letter-frequency.el new file mode 100644 index 00000000..2bda046c --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/parallel-letter-frequency.el @@ -0,0 +1,14 @@ +;;; parallel-letter-frequency.el --- Parallel Letter Frequency (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun calculate-frequencies (texts) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'parallel-letter-frequency) +;;; parallel-letter-frequency.el ends here + From fda7741ad59e2d515dd0b35362ac303f1ba9e7de Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Thu, 4 Jul 2024 11:04:22 -0500 Subject: [PATCH 128/162] add variable-length-quantity exercise (#427) * add variable-lenght-quantity exercise * have tests use hex, update error message --- config.json | 10 +- .../.docs/instructions.md | 34 +++++ .../.meta/config.json | 19 +++ .../variable-length-quantity/.meta/example.el | 40 ++++++ .../variable-length-quantity/.meta/tests.toml | 88 +++++++++++++ .../variable-length-quantity-test.el | 118 ++++++++++++++++++ .../variable-length-quantity.el | 18 +++ 7 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 exercises/practice/variable-length-quantity/.docs/instructions.md create mode 100644 exercises/practice/variable-length-quantity/.meta/config.json create mode 100644 exercises/practice/variable-length-quantity/.meta/example.el create mode 100644 exercises/practice/variable-length-quantity/.meta/tests.toml create mode 100644 exercises/practice/variable-length-quantity/variable-length-quantity-test.el create mode 100644 exercises/practice/variable-length-quantity/variable-length-quantity.el diff --git a/config.json b/config.json index 8204ffc7..b3fcea7a 100644 --- a/config.json +++ b/config.json @@ -918,6 +918,14 @@ "practices": [], "prerequisites": [], "difficulty": 10 + }, + { + "slug": "variable-length-quantity", + "name": "Variable Length Quantity", + "uuid": "5073fd82-3025-4370-ae93-37b661c17483", + "practices": [], + "prerequisites": [], + "difficulty": 6 } ] }, @@ -964,4 +972,4 @@ "typing/strong", "used_for/scripts" ] -} \ No newline at end of file +} diff --git a/exercises/practice/variable-length-quantity/.docs/instructions.md b/exercises/practice/variable-length-quantity/.docs/instructions.md new file mode 100644 index 00000000..50125482 --- /dev/null +++ b/exercises/practice/variable-length-quantity/.docs/instructions.md @@ -0,0 +1,34 @@ +# Instructions + +Implement variable length quantity encoding and decoding. + +The goal of this exercise is to implement [VLQ][vlq] encoding/decoding. + +In short, the goal of this encoding is to encode integer values in a way that would save bytes. +Only the first 7 bits of each byte are significant (right-justified; sort of like an ASCII byte). +So, if you have a 32-bit value, you have to unpack it into a series of 7-bit bytes. +Of course, you will have a variable number of bytes depending upon your integer. +To indicate which is the last byte of the series, you leave bit #7 clear. +In all of the preceding bytes, you set bit #7. + +So, if an integer is between `0-127`, it can be represented as one byte. +Although VLQ can deal with numbers of arbitrary sizes, for this exercise we will restrict ourselves to only numbers that fit in a 32-bit unsigned integer. +Here are examples of integers as 32-bit values, and the variable length quantities that they translate to: + +```text + NUMBER VARIABLE QUANTITY +00000000 00 +00000040 40 +0000007F 7F +00000080 81 00 +00002000 C0 00 +00003FFF FF 7F +00004000 81 80 00 +00100000 C0 80 00 +001FFFFF FF FF 7F +00200000 81 80 80 00 +08000000 C0 80 80 00 +0FFFFFFF FF FF FF 7F +``` + +[vlq]: https://en.wikipedia.org/wiki/Variable-length_quantity diff --git a/exercises/practice/variable-length-quantity/.meta/config.json b/exercises/practice/variable-length-quantity/.meta/config.json new file mode 100644 index 00000000..3fe14e33 --- /dev/null +++ b/exercises/practice/variable-length-quantity/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "variable-length-quantity.el" + ], + "test": [ + "variable-length-quantity-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Implement variable length quantity encoding and decoding.", + "source": "A poor Splice developer having to implement MIDI encoding/decoding.", + "source_url": "https://splice.com/" +} diff --git a/exercises/practice/variable-length-quantity/.meta/example.el b/exercises/practice/variable-length-quantity/.meta/example.el new file mode 100644 index 00000000..d4f181a5 --- /dev/null +++ b/exercises/practice/variable-length-quantity/.meta/example.el @@ -0,0 +1,40 @@ +;;; variable-length-quantity.el --- Variable Length Quantity (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun encode (hex-numbers) + "Encode a list of hexadecimal numbers into VLQ format, returning a list of hexadecimal values." + (let ((encode-single (lambda (number) + (let ((byte-string (list (logand number #x7F)))) ; Initialize with the least significant byte + (setq number (lsh number -7)) ; Shift right before the loop + (while (> number 0) + (push (logior (logand number #x7F) #x80) byte-string) + (setq number (lsh number -7))) + byte-string)))) + (apply #'append (mapcar encode-single hex-numbers)))) + + +(defun decode (hex-values) + "Decode a list of hexadecimal values from VLQ format into hexadecimal numbers." + (let ((values '()) + (number 0) + (incomplete t)) + (dolist (byte hex-values) + (setq number (lsh number 7)) + (setq number (logior number (logand byte #x7F))) + (if (= (logand byte #x80) 0) + (progn + (setq values (cons number values)) + (setq number 0) + (setq incomplete nil)) + (setq incomplete t))) + (if incomplete + (error "imcomplete sequence") + (reverse values)))) + + +(provide 'variable-length-quantity) +;;; variable-length-quantity.el ends here diff --git a/exercises/practice/variable-length-quantity/.meta/tests.toml b/exercises/practice/variable-length-quantity/.meta/tests.toml new file mode 100644 index 00000000..c9af549f --- /dev/null +++ b/exercises/practice/variable-length-quantity/.meta/tests.toml @@ -0,0 +1,88 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[35c9db2e-f781-4c52-b73b-8e76427defd0] +description = "Encode a series of integers, producing a series of bytes. -> zero" + +[be44d299-a151-4604-a10e-d4b867f41540] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary single byte" + +[ea399615-d274-4af6-bbef-a1c23c9e1346] +description = "Encode a series of integers, producing a series of bytes. -> largest single byte" + +[77b07086-bd3f-4882-8476-8dcafee79b1c] +description = "Encode a series of integers, producing a series of bytes. -> smallest double byte" + +[63955a49-2690-4e22-a556-0040648d6b2d] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary double byte" + +[29da7031-0067-43d3-83a7-4f14b29ed97a] +description = "Encode a series of integers, producing a series of bytes. -> largest double byte" + +[3345d2e3-79a9-4999-869e-d4856e3a8e01] +description = "Encode a series of integers, producing a series of bytes. -> smallest triple byte" + +[5df0bc2d-2a57-4300-a653-a75ee4bd0bee] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary triple byte" + +[f51d8539-312d-4db1-945c-250222c6aa22] +description = "Encode a series of integers, producing a series of bytes. -> largest triple byte" + +[da78228b-544f-47b7-8bfe-d16b35bbe570] +description = "Encode a series of integers, producing a series of bytes. -> smallest quadruple byte" + +[11ed3469-a933-46f1-996f-2231e05d7bb6] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary quadruple byte" + +[d5f3f3c3-e0f1-4e7f-aad0-18a44f223d1c] +description = "Encode a series of integers, producing a series of bytes. -> largest quadruple byte" + +[91a18b33-24e7-4bfb-bbca-eca78ff4fc47] +description = "Encode a series of integers, producing a series of bytes. -> smallest quintuple byte" + +[5f34ff12-2952-4669-95fe-2d11b693d331] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary quintuple byte" + +[7489694b-88c3-4078-9864-6fe802411009] +description = "Encode a series of integers, producing a series of bytes. -> maximum 32-bit integer input" + +[f9b91821-cada-4a73-9421-3c81d6ff3661] +description = "Encode a series of integers, producing a series of bytes. -> two single-byte values" + +[68694449-25d2-4974-ba75-fa7bb36db212] +description = "Encode a series of integers, producing a series of bytes. -> two multi-byte values" + +[51a06b5c-de1b-4487-9a50-9db1b8930d85] +description = "Encode a series of integers, producing a series of bytes. -> many multi-byte values" + +[baa73993-4514-4915-bac0-f7f585e0e59a] +description = "Decode a series of bytes, producing a series of integers. -> one byte" + +[72e94369-29f9-46f2-8c95-6c5b7a595aee] +description = "Decode a series of bytes, producing a series of integers. -> two bytes" + +[df5a44c4-56f7-464e-a997-1db5f63ce691] +description = "Decode a series of bytes, producing a series of integers. -> three bytes" + +[1bb58684-f2dc-450a-8406-1f3452aa1947] +description = "Decode a series of bytes, producing a series of integers. -> four bytes" + +[cecd5233-49f1-4dd1-a41a-9840a40f09cd] +description = "Decode a series of bytes, producing a series of integers. -> maximum 32-bit integer" + +[e7d74ba3-8b8e-4bcb-858d-d08302e15695] +description = "Decode a series of bytes, producing a series of integers. -> incomplete sequence causes error" + +[aa378291-9043-4724-bc53-aca1b4a3fcb6] +description = "Decode a series of bytes, producing a series of integers. -> incomplete sequence causes error, even if value is zero" + +[a91e6f5a-c64a-48e3-8a75-ce1a81e0ebee] +description = "Decode a series of bytes, producing a series of integers. -> multiple values" diff --git a/exercises/practice/variable-length-quantity/variable-length-quantity-test.el b/exercises/practice/variable-length-quantity/variable-length-quantity-test.el new file mode 100644 index 00000000..de661317 --- /dev/null +++ b/exercises/practice/variable-length-quantity/variable-length-quantity-test.el @@ -0,0 +1,118 @@ +;;; variable-length-quantity-test.el --- Variable Length Quantity (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "variable-length-quantity.el") +(declare-function encode "variable-length-quantity.el" (integers)) +(declare-function decode "variable-length-quantity.el" (integers)) + + +(ert-deftest zero () + (should (equal (encode '(#x0)) '(#x0)))) + + +(ert-deftest arbitrary-single-byte () + (should (equal (encode '(#x40)) '(#x40)))) + + +(ert-deftest largest-single-byte () + (should (equal (encode '(#x7F)) '(#x7F)))) + + +(ert-deftest smallest-double-byte () + (should (equal (encode '(#x80)) '(#x81 #x0)))) + + +(ert-deftest arbitrary-double-byte () + (should (equal (encode '(#x2000)) '(#xC0 #x0)))) + + +(ert-deftest largest-double-byte () + (should (equal (encode '(#x3FFF)) '(#xFF #x7F)))) + + +(ert-deftest smallest-triple-byte () + (should (equal (encode '(#x4000)) '(#x81 #x80 #x0)))) + + +(ert-deftest arbitrary-triple-byte () + (should (equal (encode '(#x100000)) '(#xC0 #x80 #x0)))) + + +(ert-deftest largest-triple-byte () + (should (equal (encode '(#x1FFFFF)) '(#xFF #xFF #x7F)))) + + +(ert-deftest smallest-quadruple-byte () + (should (equal (encode '(#x200000)) '(#x81 #x80 #x80 #x0)))) + + +(ert-deftest arbitrary-quadruple-byte () + (should (equal (encode '(#x8000000)) '(#xC0 #x80 #x80 #x0)))) + + +(ert-deftest largest-quadruple-byte () + (should (equal (encode '(#xFFFFFFF)) '(#xFF #xFF #xFF #x7F)))) + + +(ert-deftest smallest-quintuple-byte () + (should (equal (encode '(#x10000000)) '(#x81 #x80 #x80 #x80 #x0)))) + + +(ert-deftest arbitrary-quintuple-byte () + (should (equal (encode '(#xFF000000)) '(#x8F #xF8 #x80 #x80 #x0)))) + + +(ert-deftest maximum-32-bit-integer-input () + (should (equal (encode '(#xFFFFFFFF)) '(#x8F #xFF #xFF #xFF #x7F)))) + + +(ert-deftest two-single-byte-values () + (should (equal (encode '(#x40 #x7F)) '(#x40 #x7F)))) + + +(ert-deftest two-multi-byte-values () + (should (equal (encode '(#x4000 #x123456)) '(#x81 #x80 #x0 #xC8 #xE8 #x56)))) + + +(ert-deftest many-multi-byte-values () + (should (equal (encode '(#x2000 #x123456 #xFFFFFFF #x0 #x3FFF #x4000)) '(#xC0 #x0 #xC8 #xE8 #x56 #xFF #xFF #xFF #x7F #x0 #xFF #x7F #x81 #x80 #x0)))) + + +(ert-deftest one-byte () + (should (equal (decode '(#x7F)) '(#x7F)))) + + +(ert-deftest two-bytes () + (should (equal (decode '(#xC0 #x0)) '(#x2000)))) + + +(ert-deftest three-bytes () + (should (equal (decode '(#xFF #xFF #x7F)) '(#x1FFFFF)))) + + +(ert-deftest four-bytes () + (should (equal (decode '(#x81 #x80 #x80 #x0)) '(#x200000)))) + + +(ert-deftest maximum-32-bit-integer () + (should (equal (decode '(#x8F #xFF #xFF #xFF #x7F)) '(#xFFFFFFFF)))) + + +(ert-deftest incomplete-sequence-causes-error () + (should-error (decode '(#xFF)))) + + +(ert-deftest incomplete-sequence-causes-error-even-if-value-is-zero () + (should-error (decode '(#x80)))) + + +(ert-deftest multiple-values () + (should (equal (decode '(#xC0 #x0 #xC8 #xE8 #x56 #xFF #xFF #xFF #x7F #x0 #xFF #x7F #x81 #x80 #x0)) '(#x2000 #x123456 #xFFFFFFF #x0 #x3FFF #x4000)))) + + +(provide 'variable-length-quantity-test) +;;; variable-length-quantity-test.el ends here diff --git a/exercises/practice/variable-length-quantity/variable-length-quantity.el b/exercises/practice/variable-length-quantity/variable-length-quantity.el new file mode 100644 index 00000000..8ff73b5d --- /dev/null +++ b/exercises/practice/variable-length-quantity/variable-length-quantity.el @@ -0,0 +1,18 @@ +;;; variable-length-quantity.el --- Variable Length Quantity (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun encode (integers) + (error "Delete this S-Expression and write your own implementation")) + + +(defun decode (integers) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'variable-length-quantity) +;;; variable-length-quantity.el ends here + From d6d72dd85b3e415476cddea40968a81484c8ffc8 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Sat, 6 Jul 2024 18:06:39 +0200 Subject: [PATCH 129/162] practice-exercise-generator: Remove alphanumeric chars except '-' (#433) fixes #431 --- tools/practice-exercise-generator.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/practice-exercise-generator.el b/tools/practice-exercise-generator.el index 5b4d7862..34b3f93d 100644 --- a/tools/practice-exercise-generator.el +++ b/tools/practice-exercise-generator.el @@ -171,7 +171,7 @@ Each hash-table has the keys: ("test-name" (string-inflection-kebab-case-function (replace-regexp-in-string - "," "" + "[^[:alpha:]-]" "" (replace-regexp-in-string "[ |_]" "-" (gethash "description" elem))))) ("uuid" (gethash "uuid" elem)) From 18bd2db1490620c601c66ff78cf67af307784609 Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Sat, 6 Jul 2024 19:52:18 -0500 Subject: [PATCH 130/162] add linked list exercise (#432) * add linked list exercise --- config.json | 8 + .../linked-list/.docs/instructions.md | 26 +++ .../linked-list/.docs/introduction.md | 6 + .../practice/linked-list/.meta/config.json | 18 ++ .../practice/linked-list/.meta/example.el | 88 ++++++++ .../practice/linked-list/.meta/tests.toml | 67 ++++++ .../practice/linked-list/linked-list-test.el | 193 ++++++++++++++++++ exercises/practice/linked-list/linked-list.el | 37 ++++ 8 files changed, 443 insertions(+) create mode 100644 exercises/practice/linked-list/.docs/instructions.md create mode 100644 exercises/practice/linked-list/.docs/introduction.md create mode 100644 exercises/practice/linked-list/.meta/config.json create mode 100644 exercises/practice/linked-list/.meta/example.el create mode 100644 exercises/practice/linked-list/.meta/tests.toml create mode 100644 exercises/practice/linked-list/linked-list-test.el create mode 100644 exercises/practice/linked-list/linked-list.el diff --git a/config.json b/config.json index b3fcea7a..63938e2d 100644 --- a/config.json +++ b/config.json @@ -926,6 +926,14 @@ "practices": [], "prerequisites": [], "difficulty": 6 + }, + { + "slug": "linked-list", + "name": "Linked List", + "uuid": "ede3b6fb-b399-44a8-8aee-7bdcabec408e", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, diff --git a/exercises/practice/linked-list/.docs/instructions.md b/exercises/practice/linked-list/.docs/instructions.md new file mode 100644 index 00000000..edf4055b --- /dev/null +++ b/exercises/practice/linked-list/.docs/instructions.md @@ -0,0 +1,26 @@ +# Instructions + +Your team has decided to use a doubly linked list to represent each train route in the schedule. +Each station along the train's route will be represented by a node in the linked list. + +You don't need to worry about arrival and departure times at the stations. +Each station will simply be represented by a number. + +Routes can be extended, adding stations to the beginning or end of a route. +They can also be shortened by removing stations from the beginning or the end of a route. + +Sometimes a station gets closed down, and in that case the station needs to be removed from the route, even if it is not at the beginning or end of the route. + +The size of a route is measured not by how far the train travels, but by how many stations it stops at. + +~~~~exercism/note +The linked list is a fundamental data structure in computer science, often used in the implementation of other data structures. +As the name suggests, it is a list of nodes that are linked together. +It is a list of "nodes", where each node links to its neighbor or neighbors. +In a **singly linked list** each node links only to the node that follows it. +In a **doubly linked list** each node links to both the node that comes before, as well as the node that comes after. + +If you want to dig deeper into linked lists, check out [this article][intro-linked-list] that explains it using nice drawings. + +[intro-linked-list]: https://medium.com/basecs/whats-a-linked-list-anyway-part-1-d8b7e6508b9d +~~~~ diff --git a/exercises/practice/linked-list/.docs/introduction.md b/exercises/practice/linked-list/.docs/introduction.md new file mode 100644 index 00000000..6e83ae7b --- /dev/null +++ b/exercises/practice/linked-list/.docs/introduction.md @@ -0,0 +1,6 @@ +# Introduction + +You are working on a project to develop a train scheduling system for a busy railway network. + +You've been asked to develop a prototype for the train routes in the scheduling system. +Each route consists of a sequence of train stations that a given train stops at. diff --git a/exercises/practice/linked-list/.meta/config.json b/exercises/practice/linked-list/.meta/config.json new file mode 100644 index 00000000..f914bcf2 --- /dev/null +++ b/exercises/practice/linked-list/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "linked-list.el" + ], + "test": [ + "linked-list-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Implement a doubly linked list.", + "source": "Classic computer science topic" +} diff --git a/exercises/practice/linked-list/.meta/example.el b/exercises/practice/linked-list/.meta/example.el new file mode 100644 index 00000000..566e0ebb --- /dev/null +++ b/exercises/practice/linked-list/.meta/example.el @@ -0,0 +1,88 @@ +;;; linked-list.el --- Linked List (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(require 'cl-lib) + + +(cl-defstruct node + value prev next) + + +(cl-defstruct dll + head tail) + + +(defun dll-create () + (make-dll :head nil :tail nil)) + + +(defun dll-push (list value) + (let ((new-node (make-node :value value :prev (dll-tail list) :next nil))) + (if (dll-tail list) + (setf (node-next (dll-tail list)) new-node) + (setf (dll-head list) new-node)) + (setf (dll-tail list) new-node))) + + +(defun dll-pop (list) + (when (dll-tail list) + (let ((value (node-value (dll-tail list))) + (new-tail (node-prev (dll-tail list)))) + (if new-tail + (setf (node-next new-tail) nil) + (setf (dll-head list) nil)) + (setf (dll-tail list) new-tail) + value))) + + +(defun dll-unshift (list value) + (let ((new-node (make-node :value value :prev nil :next (dll-head list)))) + (if (dll-head list) + (setf (node-prev (dll-head list)) new-node) + (setf (dll-tail list) new-node)) + (setf (dll-head list) new-node))) + + +(defun dll-shift (list) + (when (dll-head list) + (let ((value (node-value (dll-head list))) + (new-head (node-next (dll-head list)))) + (if new-head + (setf (node-prev new-head) nil) + (setf (dll-tail list) nil)) + (setf (dll-head list) new-head) + value))) + + +(defun dll-count (list) + (let ((count 0) + (current (dll-head list))) + (while current + (setq count (1+ count)) + (setq current (node-next current))) + count)) + + +(defun dll-delete (list value) + (let ((current (dll-head list))) + (while current + (if (equal (node-value current) value) + (progn + (let ((prev-node (node-prev current)) + (next-node (node-next current))) + (if prev-node + (setf (node-next prev-node) next-node) + (setf (dll-head list) next-node)) + (if next-node + (setf (node-prev next-node) prev-node) + (setf (dll-tail list) prev-node))) + (setq current nil)) + (setq current (node-next current)))))) + + +(provide 'linked-list) +;;; linked-list.el ends here diff --git a/exercises/practice/linked-list/.meta/tests.toml b/exercises/practice/linked-list/.meta/tests.toml new file mode 100644 index 00000000..96906d2c --- /dev/null +++ b/exercises/practice/linked-list/.meta/tests.toml @@ -0,0 +1,67 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[7f7e3987-b954-41b8-8084-99beca08752c] +description = "pop gets element from the list" + +[c3f67e5d-cfa2-4c3e-a18f-7ce999c3c885] +description = "push/pop respectively add/remove at the end of the list" + +[00ea24ce-4f5c-4432-abb4-cc6e85462657] +description = "shift gets an element from the list" + +[37962ee0-3324-4a29-b588-5a4c861e6564] +description = "shift gets first element from the list" + +[30a3586b-e9dc-43fb-9a73-2770cec2c718] +description = "unshift adds element at start of the list" + +[042f71e4-a8a7-4cf0-8953-7e4f3a21c42d] +description = "pop, push, shift, and unshift can be used in any order" + +[88f65c0c-4532-4093-8295-2384fb2f37df] +description = "count an empty list" + +[fc055689-5cbe-4cd9-b994-02e2abbb40a5] +description = "count a list with items" + +[8272cef5-130d-40ea-b7f6-5ffd0790d650] +description = "count is correct after mutation" + +[229b8f7a-bd8a-4798-b64f-0dc0bb356d95] +description = "popping to empty doesn't break the list" + +[4e1948b4-514e-424b-a3cf-a1ebbfa2d1ad] +description = "shifting to empty doesn't break the list" + +[e8f7c600-d597-4f79-949d-8ad8bae895a6] +description = "deletes the only element" + +[fd65e422-51f3-45c0-9fd0-c33da638f89b] +description = "deletes the element with the specified value from the list" + +[59db191a-b17f-4ab7-9c5c-60711ec1d013] +description = "deletes the element with the specified value from the list, re-assigns tail" + +[58242222-5d39-415b-951d-8128247f8993] +description = "deletes the element with the specified value from the list, re-assigns head" + +[ee3729ee-3405-4bd2-9bad-de0d4aa5d647] +description = "deletes the first of two elements" + +[47e3b3b4-b82c-4c23-8c1a-ceb9b17cb9fb] +description = "deletes the second of two elements" + +[7b420958-f285-4922-b8f9-10d9dcab5179] +description = "delete does not modify the list if the element is not found" + +[7e04828f-6082-44e3-a059-201c63252a76] +description = "deletes only the first occurrence" diff --git a/exercises/practice/linked-list/linked-list-test.el b/exercises/practice/linked-list/linked-list-test.el new file mode 100644 index 00000000..d58fd786 --- /dev/null +++ b/exercises/practice/linked-list/linked-list-test.el @@ -0,0 +1,193 @@ +;;; linked-list-test.el --- Linked List (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "linked-list.el") +(declare-function dll-create "linked-list.el" ()) +(declare-function dll-push "linked-list.el" (list value)) +(declare-function dll-pop "linked-list.el" (list)) +(declare-function dll-unshift "linked-list.el" (list value)) +(declare-function dll-shift "linked-list.el" (list)) +(declare-function dll-count "linked-list.el" (list)) +(declare-function dll-delete "linked-list.el" (list value)) + + +(ert-deftest pop-gets-element-from-the-list () + (let ((test-list (dll-create))) + (dll-push test-list 7) + (should (= (dll-pop test-list) 7)))) + + +(ert-deftest push/pop-respectively-add/remove-at-the-end-of-the-list () + (let ((test-list (dll-create))) + (dll-push test-list 11) + (dll-push test-list 13) + (should (= (dll-pop test-list) 13)) + (should (= (dll-pop test-list) 11)))) + + +(ert-deftest shift-gets-an-element-from-the-list () + (let ((test-list (dll-create))) + (dll-push test-list 17) + (should (= (dll-shift test-list) 17)))) + + +(ert-deftest shift-gets-first-element-from-the-list () + (let ((test-list (dll-create))) + (dll-push test-list 23) + (dll-push test-list 5) + (should (= (dll-shift test-list) 23)) + (should (= (dll-shift test-list) 5)))) + + +(ert-deftest unshift-adds-element-at-start-of-the-list () + (let ((test-list (dll-create))) + (dll-unshift test-list 23) + (dll-unshift test-list 5) + (should (= (dll-shift test-list) 5)) + (should (= (dll-shift test-list) 23)))) + + +(ert-deftest pop-push-shift-and-unshift-can-be-used-in-any-order () + (let ((test-list (dll-create))) + (dll-push test-list 1) + (dll-push test-list 2) + (should (= (dll-pop test-list) 2)) + (dll-push test-list 3) + (should (= (dll-shift test-list) 1)) + (dll-unshift test-list 4) + (dll-push test-list 5) + (should (= (dll-shift test-list) 4)) + (should (= (dll-pop test-list) 5)) + (should (= (dll-shift test-list) 3)))) + + +(ert-deftest count-an-empty-list () + (let ((test-list (dll-create))) + (should (= (dll-count test-list) 0)))) + + +(ert-deftest count-a-list-with-items () + (let ((test-list (dll-create))) + (dll-push test-list 37) + (dll-push test-list 1) + (should (= (dll-count test-list) 2)))) + + +(ert-deftest count-is-correct-after-mutation () + (let ((test-list (dll-create))) + (dll-push test-list 31) + (should (= (dll-count test-list) 1)) + (dll-unshift test-list 43) + (should (= (dll-count test-list) 2)) + (dll-shift test-list) + (should (= (dll-count test-list) 1)) + (dll-pop test-list) + (should (= (dll-count test-list) 0)))) + + +(ert-deftest popping-to-empty-does-not-break-the-list () + (let ((test-list (dll-create))) + (dll-push test-list 41) + (dll-push test-list 59) + (dll-pop test-list) + (dll-pop test-list) + (dll-push test-list 47) + (should (= (dll-count test-list) 1)) + (should (= (dll-pop test-list) 47)))) + + +(ert-deftest shifting-to-empty-does-not-break-the-list () + (let ((test-list (dll-create))) + (dll-push test-list 41) + (dll-push test-list 59) + (dll-shift test-list) + (dll-shift test-list) + (dll-push test-list 47) + (should (= (dll-count test-list) 1)) + (should (= (dll-shift test-list) 47)))) + + +(ert-deftest deletes-the-only-element () + (let ((test-list (dll-create))) + (dll-push test-list 61) + (dll-delete test-list 61) + (should (= (dll-count test-list) 0)))) + + +(ert-deftest deletes-the-element-with-the-specified-value-from-the-list () + (let ((test-list (dll-create))) + (dll-push test-list 71) + (dll-push test-list 83) + (dll-push test-list 79) + (dll-delete test-list 83) + (should (= (dll-count test-list) 2)) + (should (= (dll-pop test-list) 79)) + (should (= (dll-shift test-list) 71)))) + + +(ert-deftest deletes-the-element-with-the-specified-value-from-the-list-re-assigns-tail () + (let ((test-list (dll-create))) + (dll-push test-list 71) + (dll-push test-list 83) + (dll-push test-list 79) + (dll-delete test-list 83) + (should (= (dll-count test-list) 2)) + (should (= (dll-pop test-list) 79)) + (should (= (dll-pop test-list) 71)))) + + +(ert-deftest deletes-the-element-with-the-specified-value-from-the-list-re-assigns-head () + (let ((test-list (dll-create))) + (dll-push test-list 71) + (dll-push test-list 83) + (dll-push test-list 79) + (dll-delete test-list 83) + (should (= (dll-count test-list) 2)) + (should (= (dll-shift test-list) 71)) + (should (= (dll-shift test-list) 79)))) + + +(ert-deftest deletes-the-first-of-two-elements () + (let ((test-list (dll-create))) + (dll-push test-list 97) + (dll-push test-list 101) + (dll-delete test-list 97) + (should (= (dll-count test-list) 1)) + (should (= (dll-pop test-list) 101)))) + + +(ert-deftest deletes-the-second-of-two-elements () + (let ((test-list (dll-create))) + (dll-push test-list 97) + (dll-push test-list 101) + (dll-delete test-list 101) + (should (= (dll-count test-list) 1)) + (should (= (dll-pop test-list) 97)))) + + +(ert-deftest delete-does-not-modify-the-list-if-the-element-is-not-found () + (let ((test-list (dll-create))) + (dll-push test-list 89) + (dll-delete test-list 103) + (should (= (dll-count test-list) 1)))) + + +(ert-deftest deletes-only-the-first-occurrence () + (let ((test-list (dll-create))) + (dll-push test-list 73) + (dll-push test-list 9) + (dll-push test-list 9) + (dll-push test-list 107) + (dll-delete test-list 9) + (should (= (dll-count test-list) 3)) + (should (= (dll-pop test-list) 107)) + (should (= (dll-pop test-list) 9)) + (should (= (dll-pop test-list) 73)))) + + +(provide 'linked-list-test) +;;; linked-list-test.el ends here diff --git a/exercises/practice/linked-list/linked-list.el b/exercises/practice/linked-list/linked-list.el new file mode 100644 index 00000000..4ad78995 --- /dev/null +++ b/exercises/practice/linked-list/linked-list.el @@ -0,0 +1,37 @@ +;;; linked-list.el --- Linked List (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun dll-create () + (error "Delete this S-Expression and write your own implementation")) + + +(defun dll-push (list value) + (error "Delete this S-Expression and write your own implementation")) + + +(defun dll-pop (list) + (error "Delete this S-Expression and write your own implementation")) + + +(defun dll-unshift (list value) + (error "Delete this S-Expression and write your own implementation")) + + +(defun dll-shift (list) + (error "Delete this S-Expression and write your own implementation")) + + +(defun dll-count (list) + (error "Delete this S-Expression and write your own implementation")) + + +(defun dll-delete (list value) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'linked-list) +;;; linked-list.el ends here From 5ab3dfc206e761967488d717a90bc20127070ff0 Mon Sep 17 00:00:00 2001 From: Kevin Marker Date: Mon, 8 Jul 2024 19:37:45 -0500 Subject: [PATCH 131/162] add resistor-color-trio exercise (#434) --- config.json | 8 +++ .../resistor-color-trio/.docs/instructions.md | 56 +++++++++++++++++++ .../resistor-color-trio/.meta/config.json | 19 +++++++ .../resistor-color-trio/.meta/example.el | 40 +++++++++++++ .../resistor-color-trio/.meta/tests.toml | 40 +++++++++++++ .../resistor-color-trio-test.el | 53 ++++++++++++++++++ .../resistor-color-trio.el | 14 +++++ 7 files changed, 230 insertions(+) create mode 100644 exercises/practice/resistor-color-trio/.docs/instructions.md create mode 100644 exercises/practice/resistor-color-trio/.meta/config.json create mode 100644 exercises/practice/resistor-color-trio/.meta/example.el create mode 100644 exercises/practice/resistor-color-trio/.meta/tests.toml create mode 100644 exercises/practice/resistor-color-trio/resistor-color-trio-test.el create mode 100644 exercises/practice/resistor-color-trio/resistor-color-trio.el diff --git a/config.json b/config.json index 63938e2d..ee914de1 100644 --- a/config.json +++ b/config.json @@ -934,6 +934,14 @@ "practices": [], "prerequisites": [], "difficulty": 5 + }, + { + "slug": "resistor-color-trio", + "name": "Resistor Color Trio", + "uuid": "e63a974b-1d30-4323-8059-98d131d52f6e", + "practices": [], + "prerequisites": [], + "difficulty": 2 } ] }, diff --git a/exercises/practice/resistor-color-trio/.docs/instructions.md b/exercises/practice/resistor-color-trio/.docs/instructions.md new file mode 100644 index 00000000..59d22783 --- /dev/null +++ b/exercises/practice/resistor-color-trio/.docs/instructions.md @@ -0,0 +1,56 @@ +# Instructions + +If you want to build something using a Raspberry Pi, you'll probably use _resistors_. +For this exercise, you need to know only three things about them: + +- Each resistor has a resistance value. +- Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. + To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. +- Each band acts as a digit of a number. + For example, if they printed a brown band (value 1) followed by a green band (value 5), it would translate to the number 15. + In this exercise, you are going to create a helpful program so that you don't have to remember the values of the bands. + The program will take 3 colors as input, and outputs the correct value, in ohms. + The color bands are encoded as follows: + +- Black: 0 +- Brown: 1 +- Red: 2 +- Orange: 3 +- Yellow: 4 +- Green: 5 +- Blue: 6 +- Violet: 7 +- Grey: 8 +- White: 9 + +In Resistor Color Duo you decoded the first two colors. +For instance: orange-orange got the main value `33`. +The third color stands for how many zeros need to be added to the main value. +The main value plus the zeros gives us a value in ohms. +For the exercise it doesn't matter what ohms really are. +For example: + +- orange-orange-black would be 33 and no zeros, which becomes 33 ohms. +- orange-orange-red would be 33 and 2 zeros, which becomes 3300 ohms. +- orange-orange-orange would be 33 and 3 zeros, which becomes 33000 ohms. + +(If Math is your thing, you may want to think of the zeros as exponents of 10. +If Math is not your thing, go with the zeros. +It really is the same thing, just in plain English instead of Math lingo.) + +This exercise is about translating the colors into a label: + +> "... ohms" + +So an input of `"orange", "orange", "black"` should return: + +> "33 ohms" + +When we get to larger resistors, a [metric prefix][metric-prefix] is used to indicate a larger magnitude of ohms, such as "kiloohms". +That is similar to saying "2 kilometers" instead of "2000 meters", or "2 kilograms" for "2000 grams". + +For example, an input of `"orange", "orange", "orange"` should return: + +> "33 kiloohms" + +[metric-prefix]: https://en.wikipedia.org/wiki/Metric_prefix diff --git a/exercises/practice/resistor-color-trio/.meta/config.json b/exercises/practice/resistor-color-trio/.meta/config.json new file mode 100644 index 00000000..035b71db --- /dev/null +++ b/exercises/practice/resistor-color-trio/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "kmarker1101" + ], + "files": { + "solution": [ + "resistor-color-trio.el" + ], + "test": [ + "resistor-color-trio-test.el" + ], + "example": [ + ".meta/example.el" + ] + }, + "blurb": "Convert color codes, as used on resistors, to a human-readable label.", + "source": "Maud de Vries, Erik Schierboom", + "source_url": "https://github.com/exercism/problem-specifications/issues/1549" +} diff --git a/exercises/practice/resistor-color-trio/.meta/example.el b/exercises/practice/resistor-color-trio/.meta/example.el new file mode 100644 index 00000000..c2011b1a --- /dev/null +++ b/exercises/practice/resistor-color-trio/.meta/example.el @@ -0,0 +1,40 @@ +;;; resistor-color-trio.el --- Resistor Color Trio (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(setq band-values + '(("black" . 0) + ("brown" . 1) + ("red" . 2) + ("orange" . 3) + ("yellow" . 4) + ("green" . 5) + ("blue" . 6) + ("violet" . 7) + ("grey" . 8) + ("white" . 9))) + + +(defun label (colors) + (let* ((color-1 (nth 0 colors)) + (color-2 (nth 1 colors)) + (color-3 (nth 2 colors)) + (value (+ (* (cdr (assoc color-1 band-values)) 10) + (cdr (assoc color-2 band-values)))) + (resistance (* value (expt 10 (cdr (assoc color-3 band-values)))))) + (cond + ((< resistance 1000) + (format "%d ohms" resistance)) + ((< resistance 1000000) + (format "%d kiloohms" (/ resistance 1000))) + ((< resistance 1000000000) + (format "%d megaohms" (/ resistance 1000000))) + (t + (format "%d gigaohms" (/ resistance 1000000000)))))) + + +(provide 'resistor-color-trio) +;;; resistor-color-trio.el ends here diff --git a/exercises/practice/resistor-color-trio/.meta/tests.toml b/exercises/practice/resistor-color-trio/.meta/tests.toml new file mode 100644 index 00000000..b7d45fa5 --- /dev/null +++ b/exercises/practice/resistor-color-trio/.meta/tests.toml @@ -0,0 +1,40 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[d6863355-15b7-40bb-abe0-bfb1a25512ed] +description = "Orange and orange and black" + +[1224a3a9-8c8e-4032-843a-5224e04647d6] +description = "Blue and grey and brown" + +[b8bda7dc-6b95-4539-abb2-2ad51d66a207] +description = "Red and black and red" + +[5b1e74bc-d838-4eda-bbb3-eaba988e733b] +description = "Green and brown and orange" + +[f5d37ef9-1919-4719-a90d-a33c5a6934c9] +description = "Yellow and violet and yellow" + +[5f6404a7-5bb3-4283-877d-3d39bcc33854] +description = "Blue and violet and blue" + +[7d3a6ab8-e40e-46c3-98b1-91639fff2344] +description = "Minimum possible value" + +[ca0aa0ac-3825-42de-9f07-dac68cc580fd] +description = "Maximum possible value" + +[0061a76c-903a-4714-8ce2-f26ce23b0e09] +description = "First two colors make an invalid octal number" + +[30872c92-f567-4b69-a105-8455611c10c4] +description = "Ignore extra colors" diff --git a/exercises/practice/resistor-color-trio/resistor-color-trio-test.el b/exercises/practice/resistor-color-trio/resistor-color-trio-test.el new file mode 100644 index 00000000..3b0838dc --- /dev/null +++ b/exercises/practice/resistor-color-trio/resistor-color-trio-test.el @@ -0,0 +1,53 @@ +;;; resistor-color-trio-test.el --- Resistor Color Trio (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(load-file "resistor-color-trio.el") +(declare-function label "resistor-color-trio.el" (colors)) + + +(ert-deftest orange-and-orange-and-black () + (should (string= (label '("orange" "orange" "black")) + "33 ohms"))) + +(ert-deftest blue-and-grey-and-brown () + (should (string= (label '("blue" "grey" "brown")) + "680 ohms"))) + +(ert-deftest red-and-black-and-red () + (should (string= (label '("red" "black" "red")) + "2 kiloohms"))) + +(ert-deftest green-and-brown-and-orange () + (should (string= (label '("green" "brown" "orange")) + "51 kiloohms"))) + +(ert-deftest yellow-and-violet-and-yellow () + (should (string= (label '("yellow" "violet" "yellow")) + "470 kiloohms"))) + +(ert-deftest blue-and-violet-and-blue () + (should (string= (label '("blue" "violet" "blue")) + "67 megaohms"))) + +(ert-deftest minimum-possible-value () + (should (string= (label '("black" "black" "black")) + "0 ohms"))) + +(ert-deftest maximum-possible-value () + (should (string= (label '("white" "white" "white")) + "99 gigaohms"))) + +(ert-deftest first-two-colors-make-an-invalid-octal-number () + (should (string= (label '("black" "grey" "black")) + "8 ohms"))) + +(ert-deftest ignore-extra-colors () + (should (string= (label '("blue" "green" "yellow" "orange")) + "650 kiloohms"))) + +(provide 'resistor-color-trio-test) +;;; resistor-color-trio-test.el ends here diff --git a/exercises/practice/resistor-color-trio/resistor-color-trio.el b/exercises/practice/resistor-color-trio/resistor-color-trio.el new file mode 100644 index 00000000..44aafd33 --- /dev/null +++ b/exercises/practice/resistor-color-trio/resistor-color-trio.el @@ -0,0 +1,14 @@ +;;; resistor-color-trio.el --- Resistor Color Trio (exercism) -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + + +(defun label (colors) + (error "Delete this S-Expression and write your own implementation")) + + +(provide 'resistor-color-trio) +;;; resistor-color-trio.el ends here + From 018c30c890de8deab993a14940dba53c2cb58dcc Mon Sep 17 00:00:00 2001 From: Exercism Bot Date: Wed, 10 Jul 2024 14:04:30 +0100 Subject: [PATCH 132/162] =?UTF-8?q?=F0=9F=A4=96=20Sync=20org-wide=20files?= =?UTF-8?q?=20to=20upstream=20repo=20(#435)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More info: https://github.com/exercism/org-wide-files/commit/0328994b105cecbf8d5bcab2a7fc5b9791685f87 --- bin/fetch-configlet | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/bin/fetch-configlet b/bin/fetch-configlet index 4800e150..6bef43ab 100755 --- a/bin/fetch-configlet +++ b/bin/fetch-configlet @@ -24,10 +24,11 @@ get_download_url() { local latest='https://api.github.com/repos/exercism/configlet/releases/latest' local arch case "$(uname -m)" in - x86_64) arch='x86-64' ;; - *686*) arch='i386' ;; - *386*) arch='i386' ;; - *) arch='x86-64' ;; + aarch64|arm64) arch='arm64' ;; + x86_64) arch='x86-64' ;; + *686*) arch='i386' ;; + *386*) arch='i386' ;; + *) arch='x86-64' ;; esac local suffix="${os}_${arch}.${ext}" curl "${curlopts[@]}" --header 'Accept: application/vnd.github.v3+json' "${latest}" | @@ -47,7 +48,7 @@ main() { fi local os - case "$(uname)" in + case "$(uname -s)" in Darwin*) os='macos' ;; Linux*) os='linux' ;; Windows*) os='windows' ;; @@ -58,8 +59,8 @@ main() { local ext case "${os}" in - windows*) ext='zip' ;; - *) ext='tar.gz' ;; + windows) ext='zip' ;; + *) ext='tar.gz' ;; esac echo "Fetching configlet..." >&2 @@ -69,16 +70,16 @@ main() { curl "${curlopts[@]}" --output "${output_path}" "${download_url}" case "${ext}" in - *zip) unzip "${output_path}" -d "${output_dir}" ;; - *) tar xzf "${output_path}" -C "${output_dir}" ;; + zip) unzip "${output_path}" -d "${output_dir}" ;; + *) tar xzf "${output_path}" -C "${output_dir}" ;; esac rm -f "${output_path}" local executable_ext case "${os}" in - windows*) executable_ext='.exe' ;; - *) executable_ext='' ;; + windows) executable_ext='.exe' ;; + *) executable_ext='' ;; esac local configlet_path="${output_dir}/configlet${executable_ext}" From fa516580ad8c9edf475ab347d931d5ee8aef33d4 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 11 Jul 2024 16:58:56 +0200 Subject: [PATCH 133/162] Sync the `resistor-color-trio` exercise's docs with the latest data. (#438) --- .../resistor-color-trio/.docs/instructions.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/exercises/practice/resistor-color-trio/.docs/instructions.md b/exercises/practice/resistor-color-trio/.docs/instructions.md index 59d22783..1ac5cf5e 100644 --- a/exercises/practice/resistor-color-trio/.docs/instructions.md +++ b/exercises/practice/resistor-color-trio/.docs/instructions.md @@ -12,16 +12,16 @@ For this exercise, you need to know only three things about them: The program will take 3 colors as input, and outputs the correct value, in ohms. The color bands are encoded as follows: -- Black: 0 -- Brown: 1 -- Red: 2 -- Orange: 3 -- Yellow: 4 -- Green: 5 -- Blue: 6 -- Violet: 7 -- Grey: 8 -- White: 9 +- black: 0 +- brown: 1 +- red: 2 +- orange: 3 +- yellow: 4 +- green: 5 +- blue: 6 +- violet: 7 +- grey: 8 +- white: 9 In Resistor Color Duo you decoded the first two colors. For instance: orange-orange got the main value `33`. From df34cf0dc986c2a19a57498e7659618f8681421a Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 11 Jul 2024 17:03:26 +0200 Subject: [PATCH 134/162] Sync the `resistor-color` exercise's docs with the latest data. (#436) --- .../resistor-color/.docs/instructions.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/exercises/practice/resistor-color/.docs/instructions.md b/exercises/practice/resistor-color/.docs/instructions.md index 646c1439..0125e718 100644 --- a/exercises/practice/resistor-color/.docs/instructions.md +++ b/exercises/practice/resistor-color/.docs/instructions.md @@ -15,16 +15,16 @@ In this exercise you are going to create a helpful program so that you don't hav These colors are encoded as follows: -- Black: 0 -- Brown: 1 -- Red: 2 -- Orange: 3 -- Yellow: 4 -- Green: 5 -- Blue: 6 -- Violet: 7 -- Grey: 8 -- White: 9 +- black: 0 +- brown: 1 +- red: 2 +- orange: 3 +- yellow: 4 +- green: 5 +- blue: 6 +- violet: 7 +- grey: 8 +- white: 9 The goal of this exercise is to create a way: From 6554bfd6a89d7649a49c2541d4a842a2da3b3520 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 11 Jul 2024 17:26:34 +0200 Subject: [PATCH 135/162] Sync the `resistor-color-duo` exercise's docs with the latest data. (#437) --- .../resistor-color-duo/.docs/instructions.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/exercises/practice/resistor-color-duo/.docs/instructions.md b/exercises/practice/resistor-color-duo/.docs/instructions.md index 18ee4078..4ae694da 100644 --- a/exercises/practice/resistor-color-duo/.docs/instructions.md +++ b/exercises/practice/resistor-color-duo/.docs/instructions.md @@ -17,16 +17,16 @@ The program will take color names as input and output a two digit number, even i The band colors are encoded as follows: -- Black: 0 -- Brown: 1 -- Red: 2 -- Orange: 3 -- Yellow: 4 -- Green: 5 -- Blue: 6 -- Violet: 7 -- Grey: 8 -- White: 9 +- black: 0 +- brown: 1 +- red: 2 +- orange: 3 +- yellow: 4 +- green: 5 +- blue: 6 +- violet: 7 +- grey: 8 +- white: 9 From the example above: brown-green should return 15, and From 4f921ca276f3f140468e0bdf1997a39f22cd48ae Mon Sep 17 00:00:00 2001 From: Exercism Bot Date: Wed, 4 Sep 2024 14:25:08 +0100 Subject: [PATCH 136/162] =?UTF-8?q?=F0=9F=A4=96=20Sync=20org-wide=20files?= =?UTF-8?q?=20to=20upstream=20repo=20(#442)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ping-cross-track-maintainers-team.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/workflows/ping-cross-track-maintainers-team.yml diff --git a/.github/workflows/ping-cross-track-maintainers-team.yml b/.github/workflows/ping-cross-track-maintainers-team.yml new file mode 100644 index 00000000..b6ec9c56 --- /dev/null +++ b/.github/workflows/ping-cross-track-maintainers-team.yml @@ -0,0 +1,16 @@ +name: Ping cross-track maintainers team + +on: + pull_request_target: + types: + - opened + +permissions: + pull-requests: write + +jobs: + ping: + if: github.repository_owner == 'exercism' # Stops this job from running on forks + uses: exercism/github-actions/.github/workflows/ping-cross-track-maintainers-team.yml@main + secrets: + github_membership_token: ${{ secrets.COMMUNITY_CONTRIBUTIONS_WORKFLOW_TOKEN }} From c51d6ae6914074c7741c5fa70c91bc6a569db851 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 4 Sep 2024 15:42:15 +0200 Subject: [PATCH 137/162] Change the interval for dependabot updates to monthly (#441) --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ed8f4a43..234b07e7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,4 +6,4 @@ updates: - package-ecosystem: 'github-actions' directory: '/' schedule: - interval: 'daily' + interval: 'monthly' From 176b8529c625842d94e2553dbebb3278e3e4259f Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:14:46 +0200 Subject: [PATCH 138/162] Fix flaky configlet-sync job (#443) The job sometimes fails because we're hitting a rate limit. Removing `update_existing: true` seems to the main culprit for hitting the rate limit. See https://github.com/JasonEtco/create-an-issue/issues/142#issuecomment-2066826259 works on #359 --- .github/workflows/configlet-sync.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index 5fe9728b..b97c8979 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -39,4 +39,3 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: filename: .github/configlet-sync-issue.md - update_existing: true From cb6697204414199ef40c46d91993c25a8690990e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Wed, 4 Sep 2024 09:46:06 -0700 Subject: [PATCH 139/162] Sync docs (#440) --- exercises/practice/hamming/.docs/instructions.md | 10 +++++----- exercises/practice/luhn/.docs/instructions.md | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/exercises/practice/hamming/.docs/instructions.md b/exercises/practice/hamming/.docs/instructions.md index 020fdd02..b9ae6efc 100644 --- a/exercises/practice/hamming/.docs/instructions.md +++ b/exercises/practice/hamming/.docs/instructions.md @@ -1,6 +1,6 @@ # Instructions -Calculate the Hamming Distance between two DNA strands. +Calculate the Hamming distance between two DNA strands. Your body is made up of cells that contain DNA. Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. @@ -9,18 +9,18 @@ In fact, the average human body experiences about 10 quadrillion cell divisions When cells divide, their DNA replicates too. Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. If we compare two strands of DNA and count the differences between them we can see how many mistakes occurred. -This is known as the "Hamming Distance". +This is known as the "Hamming distance". -We read DNA using the letters C,A,G and T. +We read DNA using the letters C, A, G and T. Two strands might look like this: GAGCCTACTAACGGGAT CATCGTAATGACGGCCT ^ ^ ^ ^ ^ ^^ -They have 7 differences, and therefore the Hamming Distance is 7. +They have 7 differences, and therefore the Hamming distance is 7. -The Hamming Distance is useful for lots of things in science, not just biology, so it's a nice phrase to be familiar with :) +The Hamming distance is useful for lots of things in science, not just biology, so it's a nice phrase to be familiar with :) ## Implementation notes diff --git a/exercises/practice/luhn/.docs/instructions.md b/exercises/practice/luhn/.docs/instructions.md index 8cbe791f..49934c10 100644 --- a/exercises/practice/luhn/.docs/instructions.md +++ b/exercises/practice/luhn/.docs/instructions.md @@ -22,7 +22,8 @@ The first step of the Luhn algorithm is to double every second digit, starting f We will be doubling ```text -4_3_ 3_9_ 0_4_ 6_6_ +4539 3195 0343 6467 +↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ (double these) ``` If doubling the number results in a number greater than 9 then subtract 9 from the product. From b6351ddd7a2e0ce7fe100908740d0e5cbed60c22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:11:55 -0700 Subject: [PATCH 140/162] Bump purcell/setup-emacs from 6.0 to 7.0 (#446) Bumps [purcell/setup-emacs](https://github.com/purcell/setup-emacs) from 6.0 to 7.0. - [Release notes](https://github.com/purcell/setup-emacs/releases) - [Commits](https://github.com/purcell/setup-emacs/compare/c851e5408f2d2f657fa80375bbe3fb35029aa488...7a92187aa5b5a3b854cbdfa47499fbd3d1207163) --- updated-dependencies: - dependency-name: purcell/setup-emacs dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b426e1de..4493eebf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: purcell/setup-emacs@c851e5408f2d2f657fa80375bbe3fb35029aa488 + - uses: purcell/setup-emacs@7a92187aa5b5a3b854cbdfa47499fbd3d1207163 with: version: 29.4 From a657a4dc620bf3bc34c7707e9f972f5bfd72abf3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:12:14 -0700 Subject: [PATCH 141/162] Bump actions/checkout from 4.1.7 to 4.2.0 (#445) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.7 to 4.2.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/692973e3d937129bcbf40652eb9f2f61becf3332...d632683dd7b4114ad314bca15554477dd762a938) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/configlet-sync.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4493eebf..edfef5e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: with: version: 29.4 - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.0.0 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.0.0 - name: Run exercism/emacs-lisp ci (runs tests) for all exercises run: | diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index b97c8979..3c005549 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.0.0 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.0.0 - name: Fetch configlet uses: exercism/github-actions/configlet-ci@main From ae2c8d383f954bf17f65e976b009ebcf35d2b282 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 21:19:31 -0700 Subject: [PATCH 142/162] Bump actions/checkout from 4.2.0 to 4.2.2 (#448) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.0 to 4.2.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/d632683dd7b4114ad314bca15554477dd762a938...11bd71901bbe5b1630ceea73d27597364c9af683) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/configlet-sync.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edfef5e2..98b3579e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: with: version: 29.4 - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.0.0 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.0.0 - name: Run exercism/emacs-lisp ci (runs tests) for all exercises run: | diff --git a/.github/workflows/configlet-sync.yml b/.github/workflows/configlet-sync.yml index 3c005549..4787cbeb 100644 --- a/.github/workflows/configlet-sync.yml +++ b/.github/workflows/configlet-sync.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.0.0 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.0.0 - name: Fetch configlet uses: exercism/github-actions/configlet-ci@main From a055f3d0d21d971e54edadeae2c18e805d38e398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Fri, 1 Nov 2024 07:37:35 -0700 Subject: [PATCH 143/162] Sync docs and metadata (#449) --- exercises/practice/hamming/.meta/config.json | 2 +- exercises/practice/rna-transcription/.docs/instructions.md | 6 +++--- exercises/practice/sublist/.docs/instructions.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/exercises/practice/hamming/.meta/config.json b/exercises/practice/hamming/.meta/config.json index 59d29d00..44152c8d 100644 --- a/exercises/practice/hamming/.meta/config.json +++ b/exercises/practice/hamming/.meta/config.json @@ -18,7 +18,7 @@ ".meta/example.el" ] }, - "blurb": "Calculate the Hamming difference between two DNA strands.", + "blurb": "Calculate the Hamming distance between two DNA strands.", "source": "The Calculating Point Mutations problem at Rosalind", "source_url": "https://rosalind.info/problems/hamm/" } diff --git a/exercises/practice/rna-transcription/.docs/instructions.md b/exercises/practice/rna-transcription/.docs/instructions.md index 36da381f..4dbfd3a2 100644 --- a/exercises/practice/rna-transcription/.docs/instructions.md +++ b/exercises/practice/rna-transcription/.docs/instructions.md @@ -1,12 +1,12 @@ # Instructions -Your task is determine the RNA complement of a given DNA sequence. +Your task is to determine the RNA complement of a given DNA sequence. Both DNA and RNA strands are a sequence of nucleotides. -The four nucleotides found in DNA are adenine (**A**), cytosine (**C**), guanine (**G**) and thymine (**T**). +The four nucleotides found in DNA are adenine (**A**), cytosine (**C**), guanine (**G**), and thymine (**T**). -The four nucleotides found in RNA are adenine (**A**), cytosine (**C**), guanine (**G**) and uracil (**U**). +The four nucleotides found in RNA are adenine (**A**), cytosine (**C**), guanine (**G**), and uracil (**U**). Given a DNA strand, its transcribed RNA strand is formed by replacing each nucleotide with its complement: diff --git a/exercises/practice/sublist/.docs/instructions.md b/exercises/practice/sublist/.docs/instructions.md index 7535931a..8228edc6 100644 --- a/exercises/practice/sublist/.docs/instructions.md +++ b/exercises/practice/sublist/.docs/instructions.md @@ -8,8 +8,8 @@ Given any two lists `A` and `B`, determine if: - None of the above is true, thus lists `A` and `B` are unequal Specifically, list `A` is equal to list `B` if both lists have the same values in the same order. -List `A` is a superlist of `B` if `A` contains a sub-sequence of values equal to `B`. -List `A` is a sublist of `B` if `B` contains a sub-sequence of values equal to `A`. +List `A` is a superlist of `B` if `A` contains a contiguous sub-sequence of values equal to `B`. +List `A` is a sublist of `B` if `B` contains a contiguous sub-sequence of values equal to `A`. Examples: From aaae064cec34bad6abafa05fce69a237cc62797b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Sat, 30 Nov 2024 18:31:54 -0800 Subject: [PATCH 144/162] Sync files, metadata, and tests (#451) * Sync files, metadata, and tests * Update expected value --- exercises/practice/bob/.meta/tests.toml | 5 +++++ exercises/practice/bob/bob-test.el | 2 +- .../practice/hamming/.docs/instructions.md | 11 ----------- .../practice/hamming/.docs/introduction.md | 12 ++++++++++++ .../protein-translation/.docs/instructions.md | 8 ++++---- .../pythagorean-triplet/.docs/instructions.md | 2 +- .../pythagorean-triplet/.docs/introduction.md | 19 +++++++++++++++++++ .../pythagorean-triplet/.meta/config.json | 4 ++-- .../square-root/.docs/instructions.md | 17 +++++++++++------ .../square-root/.docs/introduction.md | 10 ++++++++++ 10 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 exercises/practice/hamming/.docs/introduction.md create mode 100644 exercises/practice/pythagorean-triplet/.docs/introduction.md create mode 100644 exercises/practice/square-root/.docs/introduction.md diff --git a/exercises/practice/bob/.meta/tests.toml b/exercises/practice/bob/.meta/tests.toml index ea47d6bb..5299e289 100644 --- a/exercises/practice/bob/.meta/tests.toml +++ b/exercises/practice/bob/.meta/tests.toml @@ -71,6 +71,7 @@ description = "alternate silence" [66953780-165b-4e7e-8ce3-4bcb80b6385a] description = "multiple line question" +include = false [5371ef75-d9ea-4103-bcfa-2da973ddec1b] description = "starting with whitespace" @@ -83,3 +84,7 @@ description = "other whitespace" [12983553-8601-46a8-92fa-fcaa3bc4a2a0] description = "non-question ending with whitespace" + +[2c7278ac-f955-4eb4-bf8f-e33eb4116a15] +description = "multiple line question" +reimplements = "66953780-165b-4e7e-8ce3-4bcb80b6385a" diff --git a/exercises/practice/bob/bob-test.el b/exercises/practice/bob/bob-test.el index ea481e6f..29bf758d 100644 --- a/exercises/practice/bob/bob-test.el +++ b/exercises/practice/bob/bob-test.el @@ -89,7 +89,7 @@ (ert-deftest responds-to-multiple-line-question () (should - (string= "Whatever." (response-for "\nDoes this cryogenic chamber make me look fat?\nno")))) + (string= "Sure." (response-for "\nDoes this cryogenic chamber make\n me look fat?")))) (ert-deftest responds-to-starting-with-whitespace () (should diff --git a/exercises/practice/hamming/.docs/instructions.md b/exercises/practice/hamming/.docs/instructions.md index b9ae6efc..8f47a179 100644 --- a/exercises/practice/hamming/.docs/instructions.md +++ b/exercises/practice/hamming/.docs/instructions.md @@ -2,15 +2,6 @@ Calculate the Hamming distance between two DNA strands. -Your body is made up of cells that contain DNA. -Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. -In fact, the average human body experiences about 10 quadrillion cell divisions in a lifetime! - -When cells divide, their DNA replicates too. -Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. -If we compare two strands of DNA and count the differences between them we can see how many mistakes occurred. -This is known as the "Hamming distance". - We read DNA using the letters C, A, G and T. Two strands might look like this: @@ -20,8 +11,6 @@ Two strands might look like this: They have 7 differences, and therefore the Hamming distance is 7. -The Hamming distance is useful for lots of things in science, not just biology, so it's a nice phrase to be familiar with :) - ## Implementation notes The Hamming distance is only defined for sequences of equal length, so an attempt to calculate it between sequences of different lengths should not work. diff --git a/exercises/practice/hamming/.docs/introduction.md b/exercises/practice/hamming/.docs/introduction.md new file mode 100644 index 00000000..8419bf47 --- /dev/null +++ b/exercises/practice/hamming/.docs/introduction.md @@ -0,0 +1,12 @@ +# Introduction + +Your body is made up of cells that contain DNA. +Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. +In fact, the average human body experiences about 10 quadrillion cell divisions in a lifetime! + +When cells divide, their DNA replicates too. +Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. +If we compare two strands of DNA and count the differences between them, we can see how many mistakes occurred. +This is known as the "Hamming distance". + +The Hamming distance is useful in many areas of science, not just biology, so it's a nice phrase to be familiar with :) diff --git a/exercises/practice/protein-translation/.docs/instructions.md b/exercises/practice/protein-translation/.docs/instructions.md index 7dc34d2e..44880802 100644 --- a/exercises/practice/protein-translation/.docs/instructions.md +++ b/exercises/practice/protein-translation/.docs/instructions.md @@ -2,12 +2,12 @@ Translate RNA sequences into proteins. -RNA can be broken into three nucleotide sequences called codons, and then translated to a polypeptide like so: +RNA can be broken into three-nucleotide sequences called codons, and then translated to a protein like so: RNA: `"AUGUUUUCU"` => translates to Codons: `"AUG", "UUU", "UCU"` -=> which become a polypeptide with the following sequence => +=> which become a protein with the following sequence => Protein: `"Methionine", "Phenylalanine", "Serine"` @@ -27,9 +27,9 @@ Protein: `"Methionine", "Phenylalanine", "Serine"` Note the stop codon `"UAA"` terminates the translation and the final methionine is not translated into the protein sequence. -Below are the codons and resulting Amino Acids needed for the exercise. +Below are the codons and resulting amino acids needed for the exercise. -| Codon | Protein | +| Codon | Amino Acid | | :----------------- | :------------ | | AUG | Methionine | | UUU, UUC | Phenylalanine | diff --git a/exercises/practice/pythagorean-triplet/.docs/instructions.md b/exercises/practice/pythagorean-triplet/.docs/instructions.md index 1c1a8aea..ced833d7 100644 --- a/exercises/practice/pythagorean-triplet/.docs/instructions.md +++ b/exercises/practice/pythagorean-triplet/.docs/instructions.md @@ -1,4 +1,4 @@ -# Instructions +# Description A Pythagorean triplet is a set of three natural numbers, {a, b, c}, for which, diff --git a/exercises/practice/pythagorean-triplet/.docs/introduction.md b/exercises/practice/pythagorean-triplet/.docs/introduction.md new file mode 100644 index 00000000..3453c6ed --- /dev/null +++ b/exercises/practice/pythagorean-triplet/.docs/introduction.md @@ -0,0 +1,19 @@ +# Introduction + +You are an accomplished problem-solver, known for your ability to tackle the most challenging mathematical puzzles. +One evening, you receive an urgent letter from an inventor called the Triangle Tinkerer, who is working on a groundbreaking new project. +The letter reads: + +> Dear Mathematician, +> +> I need your help. +> I am designing a device that relies on the unique properties of Pythagorean triplets — sets of three integers that satisfy the equation a² + b² = c². +> This device will revolutionize navigation, but for it to work, I must program it with every possible triplet where the sum of a, b, and c equals a specific number, N. +> Calculating these triplets by hand would take me years, but I hear you are more than up to the task. +> +> Time is of the essence. +> The future of my invention — and perhaps even the future of mathematical innovation — rests on your ability to solve this problem. + +Motivated by the importance of the task, you set out to find all Pythagorean triplets that satisfy the condition. +Your work could have far-reaching implications, unlocking new possibilities in science and engineering. +Can you rise to the challenge and make history? diff --git a/exercises/practice/pythagorean-triplet/.meta/config.json b/exercises/practice/pythagorean-triplet/.meta/config.json index ce368d16..6ed6cc09 100644 --- a/exercises/practice/pythagorean-triplet/.meta/config.json +++ b/exercises/practice/pythagorean-triplet/.meta/config.json @@ -13,7 +13,7 @@ ".meta/example.el" ] }, - "blurb": "There exists exactly one Pythagorean triplet for which a + b + c = 1000. Find the triplet.", - "source": "Problem 9 at Project Euler", + "blurb": "Given an integer N, find all Pythagorean triplets for which a + b + c = N.", + "source": "A variation of Problem 9 from Project Euler", "source_url": "https://projecteuler.net/problem=9" } diff --git a/exercises/practice/square-root/.docs/instructions.md b/exercises/practice/square-root/.docs/instructions.md index e9905e9d..d258b868 100644 --- a/exercises/practice/square-root/.docs/instructions.md +++ b/exercises/practice/square-root/.docs/instructions.md @@ -1,13 +1,18 @@ # Instructions -Given a natural radicand, return its square root. +Your task is to calculate the square root of a given number. -Note that the term "radicand" refers to the number for which the root is to be determined. -That is, it is the number under the root symbol. +- Try to avoid using the pre-existing math libraries of your language. +- As input you'll be given a positive whole number, i.e. 1, 2, 3, 4… +- You are only required to handle cases where the result is a positive whole number. -Check out the Wikipedia pages on [square root][square-root] and [methods of computing square roots][computing-square-roots]. +Some potential approaches: -Recall also that natural numbers are positive real whole numbers (i.e. 1, 2, 3 and up). +- Linear or binary search for a number that gives the input number when squared. +- Successive approximation using Newton's or Heron's method. +- Calculating one digit at a time or one bit at a time. -[square-root]: https://en.wikipedia.org/wiki/Square_root +You can check out the Wikipedia pages on [integer square root][integer-square-root] and [methods of computing square roots][computing-square-roots] to help with choosing a method of calculation. + +[integer-square-root]: https://en.wikipedia.org/wiki/Integer_square_root [computing-square-roots]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots diff --git a/exercises/practice/square-root/.docs/introduction.md b/exercises/practice/square-root/.docs/introduction.md new file mode 100644 index 00000000..1d692934 --- /dev/null +++ b/exercises/practice/square-root/.docs/introduction.md @@ -0,0 +1,10 @@ +# Introduction + +We are launching a deep space exploration rocket and we need a way to make sure the navigation system stays on target. + +As the first step in our calculation, we take a target number and find its square root (that is, the number that when multiplied by itself equals the target number). + +The journey will be very long. +To make the batteries last as long as possible, we had to make our rocket's onboard computer very power efficient. +Unfortunately that means that we can't rely on fancy math libraries and functions, as they use more power. +Instead we want to implement our own square root calculation. From acc84448608bff6f2b64bbc408f2c2eab67eb60a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 31 Dec 2024 17:20:27 -0800 Subject: [PATCH 145/162] Sync files (#453) * Sync docs and metadata * Sync pig-latin tests --- .../affine-cipher/.docs/instructions.md | 2 +- .../atbash-cipher/.docs/instructions.md | 2 +- .../practice/atbash-cipher/.meta/config.json | 2 +- .../collatz-conjecture/.docs/instructions.md | 28 +---------- .../collatz-conjecture/.docs/introduction.md | 28 +++++++++++ .../collatz-conjecture/.meta/config.json | 4 +- .../eliuds-eggs/.docs/introduction.md | 48 +++++++++++++------ .../grade-school/.docs/instructions.md | 20 ++++---- .../practice/knapsack/.docs/instructions.md | 8 ++-- .../practice/knapsack/.docs/introduction.md | 12 +++-- .../phone-number/.docs/introduction.md | 12 +++++ exercises/practice/pig-latin/.meta/tests.toml | 3 ++ .../practice/pig-latin/pig-latin-test.el | 4 ++ 13 files changed, 107 insertions(+), 66 deletions(-) create mode 100644 exercises/practice/collatz-conjecture/.docs/introduction.md create mode 100644 exercises/practice/phone-number/.docs/introduction.md diff --git a/exercises/practice/affine-cipher/.docs/instructions.md b/exercises/practice/affine-cipher/.docs/instructions.md index 4eff918d..f6329db9 100644 --- a/exercises/practice/affine-cipher/.docs/instructions.md +++ b/exercises/practice/affine-cipher/.docs/instructions.md @@ -4,7 +4,7 @@ Create an implementation of the affine cipher, an ancient encryption system crea The affine cipher is a type of monoalphabetic substitution cipher. Each character is mapped to its numeric equivalent, encrypted with a mathematical function and then converted to the letter relating to its new numeric value. -Although all monoalphabetic ciphers are weak, the affine cipher is much stronger than the atbash cipher, because it has many more keys. +Although all monoalphabetic ciphers are weak, the affine cipher is much stronger than the Atbash cipher, because it has many more keys. [//]: # " monoalphabetic as spelled by Merriam-Webster, compare to polyalphabetic " diff --git a/exercises/practice/atbash-cipher/.docs/instructions.md b/exercises/practice/atbash-cipher/.docs/instructions.md index 21ca2ce0..1e7627b1 100644 --- a/exercises/practice/atbash-cipher/.docs/instructions.md +++ b/exercises/practice/atbash-cipher/.docs/instructions.md @@ -1,6 +1,6 @@ # Instructions -Create an implementation of the atbash cipher, an ancient encryption system created in the Middle East. +Create an implementation of the Atbash cipher, an ancient encryption system created in the Middle East. The Atbash cipher is a simple substitution cipher that relies on transposing all the letters in the alphabet such that the resulting alphabet is backwards. The first letter is replaced with the last letter, the second with the second-last, and so on. diff --git a/exercises/practice/atbash-cipher/.meta/config.json b/exercises/practice/atbash-cipher/.meta/config.json index 7bcaa351..1ea9a8f6 100644 --- a/exercises/practice/atbash-cipher/.meta/config.json +++ b/exercises/practice/atbash-cipher/.meta/config.json @@ -17,7 +17,7 @@ ".meta/example.el" ] }, - "blurb": "Create an implementation of the atbash cipher, an ancient encryption system created in the Middle East.", + "blurb": "Create an implementation of the Atbash cipher, an ancient encryption system created in the Middle East.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Atbash" } diff --git a/exercises/practice/collatz-conjecture/.docs/instructions.md b/exercises/practice/collatz-conjecture/.docs/instructions.md index ba060483..af332a81 100644 --- a/exercises/practice/collatz-conjecture/.docs/instructions.md +++ b/exercises/practice/collatz-conjecture/.docs/instructions.md @@ -1,29 +1,3 @@ # Instructions -The Collatz Conjecture or 3x+1 problem can be summarized as follows: - -Take any positive integer n. -If n is even, divide n by 2 to get n / 2. -If n is odd, multiply n by 3 and add 1 to get 3n + 1. -Repeat the process indefinitely. -The conjecture states that no matter which number you start with, you will always reach 1 eventually. - -Given a number n, return the number of steps required to reach 1. - -## Examples - -Starting with n = 12, the steps would be as follows: - -0. 12 -1. 6 -2. 3 -3. 10 -4. 5 -5. 16 -6. 8 -7. 4 -8. 2 -9. 1 - -Resulting in 9 steps. -So for input n = 12, the return value would be 9. +Given a positive integer, return the number of steps it takes to reach 1 according to the rules of the Collatz Conjecture. diff --git a/exercises/practice/collatz-conjecture/.docs/introduction.md b/exercises/practice/collatz-conjecture/.docs/introduction.md new file mode 100644 index 00000000..c35bdeb6 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.docs/introduction.md @@ -0,0 +1,28 @@ +# Introduction + +One evening, you stumbled upon an old notebook filled with cryptic scribbles, as though someone had been obsessively chasing an idea. +On one page, a single question stood out: **Can every number find its way to 1?** +It was tied to something called the **Collatz Conjecture**, a puzzle that has baffled thinkers for decades. + +The rules were deceptively simple. +Pick any positive integer. + +- If it's even, divide it by 2. +- If it's odd, multiply it by 3 and add 1. + +Then, repeat these steps with the result, continuing indefinitely. + +Curious, you picked number 12 to test and began the journey: + +12 ➜ 6 ➜ 3 ➜ 10 ➜ 5 ➜ 16 ➜ 8 ➜ 4 ➜ 2 ➜ 1 + +Counting from the second number (6), it took 9 steps to reach 1, and each time the rules repeated, the number kept changing. +At first, the sequence seemed unpredictable — jumping up, down, and all over. +Yet, the conjecture claims that no matter the starting number, we'll always end at 1. + +It was fascinating, but also puzzling. +Why does this always seem to work? +Could there be a number where the process breaks down, looping forever or escaping into infinity? +The notebook suggested solving this could reveal something profound — and with it, fame, [fortune][collatz-prize], and a place in history awaits whoever could unlock its secrets. + +[collatz-prize]: https://mathprize.net/posts/collatz-conjecture/ diff --git a/exercises/practice/collatz-conjecture/.meta/config.json b/exercises/practice/collatz-conjecture/.meta/config.json index bcbe5f22..e117ae5b 100644 --- a/exercises/practice/collatz-conjecture/.meta/config.json +++ b/exercises/practice/collatz-conjecture/.meta/config.json @@ -14,6 +14,6 @@ ] }, "blurb": "Calculate the number of steps to reach 1 using the Collatz conjecture.", - "source": "An unsolved problem in mathematics named after mathematician Lothar Collatz", - "source_url": "https://en.wikipedia.org/wiki/3x_%2B_1_problem" + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Collatz_conjecture" } diff --git a/exercises/practice/eliuds-eggs/.docs/introduction.md b/exercises/practice/eliuds-eggs/.docs/introduction.md index 49eaffd8..81989748 100644 --- a/exercises/practice/eliuds-eggs/.docs/introduction.md +++ b/exercises/practice/eliuds-eggs/.docs/introduction.md @@ -12,36 +12,54 @@ The position information encoding is calculated as follows: 2. Convert the number from binary to decimal. 3. Show the result on the display. -Example 1: +## Example 1 + +![Seven individual nest boxes arranged in a row whose first, third, fourth and seventh nests each have a single egg.](https://assets.exercism.org/images/exercises/eliuds-eggs/example-1-coop.svg) ```text -Chicken Coop: _ _ _ _ _ _ _ |E| |E|E| | |E| +``` + +### Resulting Binary + +![1011001](https://assets.exercism.org/images/exercises/eliuds-eggs/example-1-binary.svg) + +```text + _ _ _ _ _ _ _ +|1|0|1|1|0|0|1| +``` -Resulting Binary: - 1 0 1 1 0 0 1 +### Decimal number on the display -Decimal number on the display: 89 -Actual eggs in the coop: +### Actual eggs in the coop + 4 + +## Example 2 + +![Seven individual nest boxes arranged in a row where only the fourth nest has an egg.](https://assets.exercism.org/images/exercises/eliuds-eggs/example-2-coop.svg) + +```text + _ _ _ _ _ _ _ +| | | |E| | | | ``` -Example 2: +### Resulting Binary + +![0001000](https://assets.exercism.org/images/exercises/eliuds-eggs/example-2-binary.svg) ```text -Chicken Coop: - _ _ _ _ _ _ _ _ -| | | |E| | | | | + _ _ _ _ _ _ _ +|0|0|0|1|0|0|0| +``` -Resulting Binary: - 0 0 0 1 0 0 0 0 +### Decimal number on the display -Decimal number on the display: 16 -Actual eggs in the coop: +### Actual eggs in the coop + 1 -``` diff --git a/exercises/practice/grade-school/.docs/instructions.md b/exercises/practice/grade-school/.docs/instructions.md index 9a63e398..3cb1b5d5 100644 --- a/exercises/practice/grade-school/.docs/instructions.md +++ b/exercises/practice/grade-school/.docs/instructions.md @@ -1,21 +1,21 @@ # Instructions -Given students' names along with the grade that they are in, create a roster for the school. +Given students' names along with the grade they are in, create a roster for the school. In the end, you should be able to: -- Add a student's name to the roster for a grade +- Add a student's name to the roster for a grade: - "Add Jim to grade 2." - "OK." -- Get a list of all students enrolled in a grade +- Get a list of all students enrolled in a grade: - "Which students are in grade 2?" - - "We've only got Jim just now." + - "We've only got Jim right now." - Get a sorted list of all students in all grades. - Grades should sort as 1, 2, 3, etc., and students within a grade should be sorted alphabetically by name. - - "Who all is enrolled in school right now?" + Grades should be sorted as 1, 2, 3, etc., and students within a grade should be sorted alphabetically by name. + - "Who is enrolled in school right now?" - "Let me think. - We have Anna, Barb, and Charlie in grade 1, Alex, Peter, and Zoe in grade 2 and Jim in grade 5. - So the answer is: Anna, Barb, Charlie, Alex, Peter, Zoe and Jim" + We have Anna, Barb, and Charlie in grade 1, Alex, Peter, and Zoe in grade 2, and Jim in grade 5. + So the answer is: Anna, Barb, Charlie, Alex, Peter, Zoe, and Jim." -Note that all our students only have one name (It's a small town, what do you want?) and each student cannot be added more than once to a grade or the roster. -In fact, when a test attempts to add the same student more than once, your implementation should indicate that this is incorrect. +Note that all our students only have one name (it's a small town, what do you want?), and each student cannot be added more than once to a grade or the roster. +If a test attempts to add the same student more than once, your implementation should indicate that this is incorrect. diff --git a/exercises/practice/knapsack/.docs/instructions.md b/exercises/practice/knapsack/.docs/instructions.md index 3411db98..0ebf7914 100644 --- a/exercises/practice/knapsack/.docs/instructions.md +++ b/exercises/practice/knapsack/.docs/instructions.md @@ -1,11 +1,11 @@ # Instructions -Your task is to determine which items to take so that the total value of his selection is maximized, taking into account the knapsack's carrying capacity. +Your task is to determine which items to take so that the total value of her selection is maximized, taking into account the knapsack's carrying capacity. Items will be represented as a list of items. Each item will have a weight and value. All values given will be strictly positive. -Bob can take only one of each item. +Lhakpa can take only one of each item. For example: @@ -21,5 +21,5 @@ Knapsack Maximum Weight: 10 ``` For the above, the first item has weight 5 and value 10, the second item has weight 4 and value 40, and so on. -In this example, Bob should take the second and fourth item to maximize his value, which, in this case, is 90. -He cannot get more than 90 as his knapsack has a weight limit of 10. +In this example, Lhakpa should take the second and fourth item to maximize her value, which, in this case, is 90. +She cannot get more than 90 as her knapsack has a weight limit of 10. diff --git a/exercises/practice/knapsack/.docs/introduction.md b/exercises/practice/knapsack/.docs/introduction.md index 9b2bed8b..9ac9df59 100644 --- a/exercises/practice/knapsack/.docs/introduction.md +++ b/exercises/practice/knapsack/.docs/introduction.md @@ -1,8 +1,10 @@ # Introduction -Bob is a thief. -After months of careful planning, he finally manages to crack the security systems of a fancy store. +Lhakpa is a [Sherpa][sherpa] mountain guide and porter. +After months of careful planning, the expedition Lhakpa works for is about to leave. +She will be paid the value she carried to the base camp. -In front of him are many items, each with a value and weight. -Bob would gladly take all of the items, but his knapsack can only hold so much weight. -Bob has to carefully consider which items to take so that the total value of his selection is maximized. +In front of her are many items, each with a value and weight. +Lhakpa would gladly take all of the items, but her knapsack can only hold so much weight. + +[sherpa]: https://en.wikipedia.org/wiki/Sherpa_people#Mountaineering diff --git a/exercises/practice/phone-number/.docs/introduction.md b/exercises/practice/phone-number/.docs/introduction.md new file mode 100644 index 00000000..c4142c5a --- /dev/null +++ b/exercises/practice/phone-number/.docs/introduction.md @@ -0,0 +1,12 @@ +# Introduction + +You've joined LinkLine, a leading communications company working to ensure reliable connections for everyone. +The team faces a big challenge: users submit phone numbers in all sorts of formats — dashes, spaces, dots, parentheses, and even prefixes. +Some numbers are valid, while others are impossible to use. + +Your mission is to turn this chaos into order. +You'll clean up valid numbers, formatting them appropriately for use in the system. +At the same time, you'll identify and filter out any invalid entries. + +The success of LinkLine's operations depends on your ability to separate the useful from the unusable. +Are you ready to take on the challenge and keep the connections running smoothly? diff --git a/exercises/practice/pig-latin/.meta/tests.toml b/exercises/practice/pig-latin/.meta/tests.toml index c29168c5..d524305b 100644 --- a/exercises/practice/pig-latin/.meta/tests.toml +++ b/exercises/practice/pig-latin/.meta/tests.toml @@ -39,6 +39,9 @@ description = "first letter and ay are moved to the end of words that start with [bce94a7a-a94e-4e2b-80f4-b2bb02e40f71] description = "first letter and ay are moved to the end of words that start with consonants -> word beginning with q without a following u" +[e59dbbe8-ccee-4619-a8e9-ce017489bfc0] +description = "first letter and ay are moved to the end of words that start with consonants -> word beginning with consonant and vowel containing qu" + [c01e049a-e3e2-451c-bf8e-e2abb7e438b8] description = "some letter clusters are treated like a single consonant -> word beginning with ch" diff --git a/exercises/practice/pig-latin/pig-latin-test.el b/exercises/practice/pig-latin/pig-latin-test.el index d3540983..93996c21 100644 --- a/exercises/practice/pig-latin/pig-latin-test.el +++ b/exercises/practice/pig-latin/pig-latin-test.el @@ -49,6 +49,10 @@ (should (string= (translate "qat") "atqay"))) +(ert-deftest word-beginning-with-consonant-and-vowel-containing-qu () + (should (string= (translate "liquid") "iquidlay"))) + + (ert-deftest word-beginning-with-ch () (should (string= (translate "chair") "airchay"))) From cb5d69044d9f12236bf12402b5a68cc7d58b311c Mon Sep 17 00:00:00 2001 From: Isaac Good Date: Fri, 17 Jan 2025 23:20:07 -0800 Subject: [PATCH 146/162] exercises/practice/anagram: add an append with instructions about the order of the return values (#454) --- exercises/practice/anagram/.docs/instructions.append.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 exercises/practice/anagram/.docs/instructions.append.md diff --git a/exercises/practice/anagram/.docs/instructions.append.md b/exercises/practice/anagram/.docs/instructions.append.md new file mode 100644 index 00000000..2b17bb7a --- /dev/null +++ b/exercises/practice/anagram/.docs/instructions.append.md @@ -0,0 +1,3 @@ +# Instructions Append + +You must return the anagrams in the same order as they are listed in the candidate words. From f31cba580b01704a7095c92c5f6db42fee87a3d3 Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Sat, 1 Feb 2025 12:12:48 +1100 Subject: [PATCH 147/162] Sync exercise instructions (#456) --- exercises/practice/anagram/.docs/instructions.md | 11 +++++------ exercises/practice/grains/.meta/config.json | 2 +- exercises/practice/leap/.meta/config.json | 2 +- exercises/practice/luhn/.docs/instructions.md | 8 +++----- exercises/practice/luhn/.docs/introduction.md | 11 +++++++++++ .../practice/pascals-triangle/.docs/introduction.md | 2 +- .../practice/rna-transcription/.meta/config.json | 2 +- exercises/practice/say/.meta/config.json | 2 +- 8 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 exercises/practice/luhn/.docs/introduction.md diff --git a/exercises/practice/anagram/.docs/instructions.md b/exercises/practice/anagram/.docs/instructions.md index a7298485..dca24f52 100644 --- a/exercises/practice/anagram/.docs/instructions.md +++ b/exercises/practice/anagram/.docs/instructions.md @@ -1,13 +1,12 @@ # Instructions -Your task is to, given a target word and a set of candidate words, to find the subset of the candidates that are anagrams of the target. +Given a target word and one or more candidate words, your task is to find the candidates that are anagrams of the target. An anagram is a rearrangement of letters to form a new word: for example `"owns"` is an anagram of `"snow"`. A word is _not_ its own anagram: for example, `"stop"` is not an anagram of `"stop"`. -The target and candidates are words of one or more ASCII alphabetic characters (`A`-`Z` and `a`-`z`). -Lowercase and uppercase characters are equivalent: for example, `"PoTS"` is an anagram of `"sTOp"`, but `StoP` is not an anagram of `sTOp`. -The anagram set is the subset of the candidate set that are anagrams of the target (in any order). -Words in the anagram set should have the same letter case as in the candidate set. +The target word and candidate words are made up of one or more ASCII alphabetic characters (`A`-`Z` and `a`-`z`). +Lowercase and uppercase characters are equivalent: for example, `"PoTS"` is an anagram of `"sTOp"`, but `"StoP"` is not an anagram of `"sTOp"`. +The words you need to find should be taken from the candidate words, using the same letter case. -Given the target `"stone"` and candidates `"stone"`, `"tones"`, `"banana"`, `"tons"`, `"notes"`, `"Seton"`, the anagram set is `"tones"`, `"notes"`, `"Seton"`. +Given the target `"stone"` and the candidate words `"stone"`, `"tones"`, `"banana"`, `"tons"`, `"notes"`, and `"Seton"`, the anagram words you need to find are `"tones"`, `"notes"`, and `"Seton"`. diff --git a/exercises/practice/grains/.meta/config.json b/exercises/practice/grains/.meta/config.json index 6bb32f2d..3586fed6 100644 --- a/exercises/practice/grains/.meta/config.json +++ b/exercises/practice/grains/.meta/config.json @@ -20,5 +20,5 @@ }, "blurb": "Calculate the number of grains of wheat on a chessboard given that the number on each square doubles.", "source": "The CodeRanch Cattle Drive, Assignment 6", - "source_url": "https://coderanch.com/wiki/718824/Grains" + "source_url": "https://web.archive.org/web/20240908084142/https://coderanch.com/wiki/718824/Grains" } diff --git a/exercises/practice/leap/.meta/config.json b/exercises/practice/leap/.meta/config.json index 4560b0c7..960964d1 100644 --- a/exercises/practice/leap/.meta/config.json +++ b/exercises/practice/leap/.meta/config.json @@ -18,5 +18,5 @@ }, "blurb": "Determine whether a given year is a leap year.", "source": "CodeRanch Cattle Drive, Assignment 3", - "source_url": "https://coderanch.com/t/718816/Leap" + "source_url": "https://web.archive.org/web/20240907033714/https://coderanch.com/t/718816/Leap" } diff --git a/exercises/practice/luhn/.docs/instructions.md b/exercises/practice/luhn/.docs/instructions.md index 49934c10..5bbf007b 100644 --- a/exercises/practice/luhn/.docs/instructions.md +++ b/exercises/practice/luhn/.docs/instructions.md @@ -1,12 +1,10 @@ # Instructions -Given a number determine whether or not it is valid per the Luhn formula. +Determine whether a credit card number is valid according to the [Luhn formula][luhn]. -The [Luhn algorithm][luhn] is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers and Canadian Social Insurance Numbers. +The number will be provided as a string. -The task is to check if a given string is valid. - -## Validating a Number +## Validating a number Strings of length 1 or less are not valid. Spaces are allowed in the input, but they should be stripped before checking. diff --git a/exercises/practice/luhn/.docs/introduction.md b/exercises/practice/luhn/.docs/introduction.md new file mode 100644 index 00000000..ec2bd709 --- /dev/null +++ b/exercises/practice/luhn/.docs/introduction.md @@ -0,0 +1,11 @@ +# Introduction + +At the Global Verification Authority, you've just been entrusted with a critical assignment. +Across the city, from online purchases to secure logins, countless operations rely on the accuracy of numerical identifiers like credit card numbers, bank account numbers, transaction codes, and tracking IDs. +The Luhn algorithm is a simple checksum formula used to ensure these numbers are valid and error-free. + +A batch of identifiers has just arrived on your desk. +All of them must pass the Luhn test to ensure they're legitimate. +If any fail, they'll be flagged as invalid, preventing errors or fraud, such as incorrect transactions or unauthorized access. + +Can you ensure this is done right? The integrity of many services depends on you. diff --git a/exercises/practice/pascals-triangle/.docs/introduction.md b/exercises/practice/pascals-triangle/.docs/introduction.md index 60b8ec30..eab454e5 100644 --- a/exercises/practice/pascals-triangle/.docs/introduction.md +++ b/exercises/practice/pascals-triangle/.docs/introduction.md @@ -13,7 +13,7 @@ Over the next hour, your teacher reveals some amazing things hidden in this tria - It contains the Fibonacci sequence. - If you color odd and even numbers differently, you get a beautiful pattern called the [Sierpiński triangle][wikipedia-sierpinski-triangle]. -The teacher implores you and your classmates to lookup other uses, and assures you that there are lots more! +The teacher implores you and your classmates to look up other uses, and assures you that there are lots more! At that moment, the school bell rings. You realize that for the past hour, you were completely absorbed in learning about Pascal's triangle. You quickly grab your laptop from your bag and go outside, ready to enjoy both the sunshine _and_ the wonders of Pascal's triangle. diff --git a/exercises/practice/rna-transcription/.meta/config.json b/exercises/practice/rna-transcription/.meta/config.json index b5e32eab..b45df897 100644 --- a/exercises/practice/rna-transcription/.meta/config.json +++ b/exercises/practice/rna-transcription/.meta/config.json @@ -16,7 +16,7 @@ ".meta/example.el" ] }, - "blurb": "Given a DNA strand, return its RNA Complement Transcription.", + "blurb": "Given a DNA strand, return its RNA complement.", "source": "Hyperphysics", "source_url": "https://web.archive.org/web/20220408112140/http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html" } diff --git a/exercises/practice/say/.meta/config.json b/exercises/practice/say/.meta/config.json index 2a649de5..278dbf8b 100644 --- a/exercises/practice/say/.meta/config.json +++ b/exercises/practice/say/.meta/config.json @@ -15,5 +15,5 @@ }, "blurb": "Given a number from 0 to 999,999,999,999, spell out that number in English.", "source": "A variation on the JavaRanch CattleDrive, Assignment 4", - "source_url": "https://coderanch.com/wiki/718804" + "source_url": "https://web.archive.org/web/20240907035912/https://coderanch.com/wiki/718804" } From 8677ef663b7febd9ef120f5c737ada5b1df17330 Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Sat, 1 Mar 2025 12:44:16 +1100 Subject: [PATCH 148/162] Sync instructions (#458) [no important files changed] --- .../affine-cipher/.docs/instructions.md | 2 +- .../practice/grains/.docs/instructions.md | 14 ++-- .../practice/grains/.docs/introduction.md | 6 ++ .../practice/sieve/.docs/instructions.md | 75 +++++++++++++++++-- .../simple-cipher/.docs/instructions.md | 10 +-- 5 files changed, 84 insertions(+), 23 deletions(-) create mode 100644 exercises/practice/grains/.docs/introduction.md diff --git a/exercises/practice/affine-cipher/.docs/instructions.md b/exercises/practice/affine-cipher/.docs/instructions.md index f6329db9..1603dbbc 100644 --- a/exercises/practice/affine-cipher/.docs/instructions.md +++ b/exercises/practice/affine-cipher/.docs/instructions.md @@ -20,7 +20,7 @@ Where: - `i` is the letter's index from `0` to the length of the alphabet - 1. - `m` is the length of the alphabet. - For the Roman alphabet `m` is `26`. + For the Latin alphabet `m` is `26`. - `a` and `b` are integers which make up the encryption key. Values `a` and `m` must be _coprime_ (or, _relatively prime_) for automatic decryption to succeed, i.e., they have number `1` as their only common factor (more information can be found in the [Wikipedia article about coprime integers][coprime-integers]). diff --git a/exercises/practice/grains/.docs/instructions.md b/exercises/practice/grains/.docs/instructions.md index df479fc0..f5b752a8 100644 --- a/exercises/practice/grains/.docs/instructions.md +++ b/exercises/practice/grains/.docs/instructions.md @@ -1,15 +1,11 @@ # Instructions -Calculate the number of grains of wheat on a chessboard given that the number on each square doubles. +Calculate the number of grains of wheat on a chessboard. -There once was a wise servant who saved the life of a prince. -The king promised to pay whatever the servant could dream up. -Knowing that the king loved chess, the servant told the king he would like to have grains of wheat. -One grain on the first square of a chess board, with the number of grains doubling on each successive square. +A chessboard has 64 squares. +Square 1 has one grain, square 2 has two grains, square 3 has four grains, and so on, doubling each time. -There are 64 squares on a chessboard (where square 1 has one grain, square 2 has two grains, and so on). +Write code that calculates: -Write code that shows: - -- how many grains were on a given square, and +- the number of grains on a given square - the total number of grains on the chessboard diff --git a/exercises/practice/grains/.docs/introduction.md b/exercises/practice/grains/.docs/introduction.md new file mode 100644 index 00000000..0df4f46f --- /dev/null +++ b/exercises/practice/grains/.docs/introduction.md @@ -0,0 +1,6 @@ +# Introduction + +There once was a wise servant who saved the life of a prince. +The king promised to pay whatever the servant could dream up. +Knowing that the king loved chess, the servant told the king he would like to have grains of wheat. +One grain on the first square of a chessboard, with the number of grains doubling on each successive square. diff --git a/exercises/practice/sieve/.docs/instructions.md b/exercises/practice/sieve/.docs/instructions.md index 085c0a57..71292e17 100644 --- a/exercises/practice/sieve/.docs/instructions.md +++ b/exercises/practice/sieve/.docs/instructions.md @@ -6,37 +6,96 @@ A prime number is a number larger than 1 that is only divisible by 1 and itself. For example, 2, 3, 5, 7, 11, and 13 are prime numbers. By contrast, 6 is _not_ a prime number as it not only divisible by 1 and itself, but also by 2 and 3. -To use the Sieve of Eratosthenes, you first create a list of all the numbers between 2 and your given number. -Then you repeat the following steps: +To use the Sieve of Eratosthenes, first, write out all the numbers from 2 up to and including your given number. +Then, follow these steps: -1. Find the next unmarked number in your list (skipping over marked numbers). +1. Find the next unmarked number (skipping over marked numbers). This is a prime number. 2. Mark all the multiples of that prime number as **not** prime. -You keep repeating these steps until you've gone through every number in your list. +Repeat the steps until you've gone through every number. At the end, all the unmarked numbers are prime. ~~~~exercism/note -The tests don't check that you've implemented the algorithm, only that you've come up with the correct list of primes. -To check you are implementing the Sieve correctly, a good first test is to check that you do not use division or remainder operations. +The Sieve of Eratosthenes marks off multiples of each prime using addition (repeatedly adding the prime) or multiplication (directly computing its multiples), rather than checking each number for divisibility. + +The tests don't check that you've implemented the algorithm, only that you've come up with the correct primes. ~~~~ ## Example Let's say you're finding the primes less than or equal to 10. -- List out 2, 3, 4, 5, 6, 7, 8, 9, 10, leaving them all unmarked. +- Write out 2, 3, 4, 5, 6, 7, 8, 9, 10, leaving them all unmarked. + + ```text + 2 3 4 5 6 7 8 9 10 + ``` + - 2 is unmarked and is therefore a prime. Mark 4, 6, 8 and 10 as "not prime". + + ```text + 2 3 [4] 5 [6] 7 [8] 9 [10] + ↑ + ``` + - 3 is unmarked and is therefore a prime. Mark 6 and 9 as not prime _(marking 6 is optional - as it's already been marked)_. + + ```text + 2 3 [4] 5 [6] 7 [8] [9] [10] + ↑ + ``` + - 4 is marked as "not prime", so we skip over it. + + ```text + 2 3 [4] 5 [6] 7 [8] [9] [10] + ↑ + ``` + - 5 is unmarked and is therefore a prime. Mark 10 as not prime _(optional - as it's already been marked)_. + + ```text + 2 3 [4] 5 [6] 7 [8] [9] [10] + ↑ + ``` + - 6 is marked as "not prime", so we skip over it. + + ```text + 2 3 [4] 5 [6] 7 [8] [9] [10] + ↑ + ``` + - 7 is unmarked and is therefore a prime. + + ```text + 2 3 [4] 5 [6] 7 [8] [9] [10] + ↑ + ``` + - 8 is marked as "not prime", so we skip over it. + + ```text + 2 3 [4] 5 [6] 7 [8] [9] [10] + ↑ + ``` + - 9 is marked as "not prime", so we skip over it. + + ```text + 2 3 [4] 5 [6] 7 [8] [9] [10] + ↑ + ``` + - 10 is marked as "not prime", so we stop as there are no more numbers to check. -You've examined all numbers and found 2, 3, 5, and 7 are still unmarked, which means they're the primes less than or equal to 10. + ```text + 2 3 [4] 5 [6] 7 [8] [9] [10] + ↑ + ``` + +You've examined all the numbers and found that 2, 3, 5, and 7 are still unmarked, meaning they're the primes less than or equal to 10. diff --git a/exercises/practice/simple-cipher/.docs/instructions.md b/exercises/practice/simple-cipher/.docs/instructions.md index 475af618..33785744 100644 --- a/exercises/practice/simple-cipher/.docs/instructions.md +++ b/exercises/practice/simple-cipher/.docs/instructions.md @@ -11,14 +11,14 @@ If anyone wishes to decipher these, and get at their meaning, he must substitute Ciphers are very straight-forward algorithms that allow us to render text less readable while still allowing easy deciphering. They are vulnerable to many forms of cryptanalysis, but Caesar was lucky that his enemies were not cryptanalysts. -The Caesar Cipher was used for some messages from Julius Caesar that were sent afield. +The Caesar cipher was used for some messages from Julius Caesar that were sent afield. Now Caesar knew that the cipher wasn't very good, but he had one ally in that respect: almost nobody could read well. So even being a couple letters off was sufficient so that people couldn't recognize the few words that they did know. -Your task is to create a simple shift cipher like the Caesar Cipher. -This image is a great example of the Caesar Cipher: +Your task is to create a simple shift cipher like the Caesar cipher. +This image is a great example of the Caesar cipher: -![Caesar Cipher][img-caesar-cipher] +![Caesar cipher][img-caesar-cipher] For example: @@ -44,7 +44,7 @@ would return the obscured "ldpdsdqgdehdu" In the example above, we've set a = 0 for the key value. So when the plaintext is added to the key, we end up with the same message coming out. So "aaaa" is not an ideal key. -But if we set the key to "dddd", we would get the same thing as the Caesar Cipher. +But if we set the key to "dddd", we would get the same thing as the Caesar cipher. ## Step 3 From 6e6ba4c37b5446be4c85fe09baab7689ea2fc9f6 Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Sat, 1 Mar 2025 13:44:05 +1100 Subject: [PATCH 149/162] Sync flatten-array (#459) [no important files changed] --- .../.docs/instructions.append.md | 3 ++ .../flatten-array/.docs/instructions.md | 15 ++++-- .../practice/flatten-array/.meta/tests.toml | 20 ++++++++ .../flatten-array/flatten-array-test.el | 50 +++++++++++++------ 4 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 exercises/practice/flatten-array/.docs/instructions.append.md diff --git a/exercises/practice/flatten-array/.docs/instructions.append.md b/exercises/practice/flatten-array/.docs/instructions.append.md new file mode 100644 index 00000000..7ea1fb6d --- /dev/null +++ b/exercises/practice/flatten-array/.docs/instructions.append.md @@ -0,0 +1,3 @@ +# Instructions Append + +The input and output are represented as lists. diff --git a/exercises/practice/flatten-array/.docs/instructions.md b/exercises/practice/flatten-array/.docs/instructions.md index 89dacfa3..b5b82713 100644 --- a/exercises/practice/flatten-array/.docs/instructions.md +++ b/exercises/practice/flatten-array/.docs/instructions.md @@ -1,11 +1,16 @@ # Instructions -Take a nested list and return a single flattened list with all values except nil/null. +Take a nested array of any depth and return a fully flattened array. -The challenge is to take an arbitrarily-deep nested list-like structure and produce a flattened structure without any nil/null values. +Note that some language tracks may include null-like values in the input array, and the way these values are represented varies by track. +Such values should be excluded from the flattened array. -For example: +Additionally, the input may be of a different data type and contain different types, depending on the track. -input: [1,[2,3,null,4],[null],5] +Check the test suite for details. -output: [1,2,3,4,5] +## Example + +input: `[1, [2, 6, null], [[null, [4]], 5]]` + +output: `[1, 2, 6, 4, 5]` diff --git a/exercises/practice/flatten-array/.meta/tests.toml b/exercises/practice/flatten-array/.meta/tests.toml index 6300219d..44acf175 100644 --- a/exercises/practice/flatten-array/.meta/tests.toml +++ b/exercises/practice/flatten-array/.meta/tests.toml @@ -32,12 +32,32 @@ description = "null values are omitted from the final result" [c6cf26de-8ccd-4410-84bd-b9efd88fd2bc] description = "consecutive null values at the front of the list are omitted from the final result" +include = false + +[bc72da10-5f55-4ada-baf3-50e4da02ec8e] +description = "consecutive null values at the front of the array are omitted from the final result" +reimplements = "c6cf26de-8ccd-4410-84bd-b9efd88fd2bc" [382c5242-587e-4577-b8ce-a5fb51e385a1] description = "consecutive null values in the middle of the list are omitted from the final result" +include = false + +[6991836d-0d9b-4703-80a0-3f1f23eb5981] +description = "consecutive null values in the middle of the array are omitted from the final result" +reimplements = "382c5242-587e-4577-b8ce-a5fb51e385a1" [ef1d4790-1b1e-4939-a179-51ace0829dbd] description = "6 level nest list with null values" +include = false + +[dc90a09c-5376-449c-a7b3-c2d20d540069] +description = "6 level nested array with null values" +reimplements = "ef1d4790-1b1e-4939-a179-51ace0829dbd" [85721643-705a-4150-93ab-7ae398e2942d] description = "all values in nested list are null" +include = false + +[51f5d9af-8f7f-4fb5-a156-69e8282cb275] +description = "all values in nested array are null" +reimplements = "85721643-705a-4150-93ab-7ae398e2942d" diff --git a/exercises/practice/flatten-array/flatten-array-test.el b/exercises/practice/flatten-array/flatten-array-test.el index d70a1318..391ec247 100644 --- a/exercises/practice/flatten-array/flatten-array-test.el +++ b/exercises/practice/flatten-array/flatten-array-test.el @@ -1,4 +1,4 @@ -;;; flatten-array-test.el --- Flatten Array (exercism) -*- lexical-binding: t; -*- +;;; flatten-array-test.el --- Tests for Flatten Array (exercism) -*- lexical-binding: t; -*- ;;; Commentary: @@ -10,20 +10,31 @@ (ert-deftest empty () - (should (equal (list-flatten '()) '()))) + (should + (equal + (list-flatten '()) + '()))) (ert-deftest no-nesting () - (should (equal (list-flatten '(0 1 2)) '(0 1 2)))) + (should + (equal + (list-flatten '(0 1 2)) + '(0 1 2)))) (ert-deftest flattens-a-nested-array () - (should (equal (list-flatten '((()))) '()))) + (should + (equal + (list-flatten '((()))) + '()))) (ert-deftest flattens-array-with-just-integers-present () (should - (equal (list-flatten '(1 (2 3 4 5 6 7) 8)) '(1 2 3 4 5 6 7 8)))) + (equal + (list-flatten '(1 (2 3 4 5 6 7) 8)) + '(1 2 3 4 5 6 7 8)))) (ert-deftest 5-level-nesting () @@ -41,33 +52,42 @@ (ert-deftest null-values-are-omitted-from-the-final-result () - (should (equal (list-flatten '(1 2 nil)) '(1 2)))) + (should + (equal + (list-flatten '(1 2 nil)) + '(1 2)))) (ert-deftest - consecutive-null-values-at-the-front-of-the-list-are-omitted-from-the-final-result + consecutive-null-values-at-the-front-of-the-array-are-omitted-from-the-final-result () - (should (equal (list-flatten '(nil nil 3)) '(3)))) + (should + (equal + (list-flatten '(nil nil 3)) + '(3)))) (ert-deftest - consecutive-null-values-in-the-middle-of-the-list-are-omitted-from-the-final-result + consecutive-null-values-in-the-middle-of-the-array-are-omitted-from-the-final-result () - (should (equal (list-flatten '(1 nil nil 4)) '(1 4)))) + (should + (equal + (list-flatten '(1 nil nil 4)) + '(1 4)))) -(ert-deftest 6-level-nest-list-with-null-values () +(ert-deftest 6-level-nested-array-with-null-values () (should (equal - (list-flatten - '(0 2 ((2 3) 8 ((100)) nil ((nil))) -2)) + (list-flatten '(0 2 ((2 3) 8 ((100)) nil ((nil))) -2)) '(0 2 2 3 8 100 -2)))) -(ert-deftest all-values-in-nested-list-are-null () +(ert-deftest all-values-in-nested-array-are-null () (should (equal - (list-flatten '(nil (((nil))) nil nil ((nil nil) nil) nil)) '()))) + (list-flatten '(nil (((nil))) nil nil ((nil nil) nil) nil)) + '()))) (provide 'flatten-array-test) From 1dba346f15e1df5d24b498ff2dbfd6726da75586 Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Sat, 8 Mar 2025 07:29:41 +1100 Subject: [PATCH 150/162] Rename two exercises (#460) Now all practice exercises have names consistent with problem-specifications metadata https://github.com/exercism/problem-specifications/blob/main/exercises/isbn-verifier/metadata.toml https://github.com/exercism/problem-specifications/blob/main/exercises/two-fer/metadata.toml [no important files changed] --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index ee914de1..a9e8694f 100644 --- a/config.json +++ b/config.json @@ -481,7 +481,7 @@ }, { "slug": "two-fer", - "name": "Two Fer", + "name": "Two-Fer", "uuid": "36e5dc3a-2122-484a-ae82-beb7b813e2cd", "practices": [], "prerequisites": [], @@ -782,7 +782,7 @@ }, { "slug": "isbn-verifier", - "name": "Isbn Verifier", + "name": "ISBN Verifier", "uuid": "b0cbc3b5-1d6c-40b8-bdd1-5ba9089024aa", "practices": [], "prerequisites": [], From 558f6f86c01132fbc4d73a93667ff54d41c4daf5 Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Wed, 12 Mar 2025 21:08:57 +0000 Subject: [PATCH 151/162] Upgrade CI workflow to Emacs 30.1 (#461) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 98b3579e..e5fe3d79 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: purcell/setup-emacs@7a92187aa5b5a3b854cbdfa47499fbd3d1207163 with: - version: 29.4 + version: 30.1 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.0.0 From e82773d58f5f78b244b828d7d7ba9550ce0a7ff4 Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Wed, 2 Apr 2025 00:42:29 +1100 Subject: [PATCH 152/162] Sync instructions (#463) [no important files changed] --- .../flatten-array/.docs/introduction.md | 7 +++ .../largest-series-product/.meta/example.el | 2 +- .../largest-series-product/.meta/tests.toml | 10 +++++ exercises/practice/luhn/.docs/instructions.md | 45 ++++++++++--------- exercises/practice/luhn/.docs/introduction.md | 4 +- 5 files changed, 45 insertions(+), 23 deletions(-) create mode 100644 exercises/practice/flatten-array/.docs/introduction.md diff --git a/exercises/practice/flatten-array/.docs/introduction.md b/exercises/practice/flatten-array/.docs/introduction.md new file mode 100644 index 00000000..a3148574 --- /dev/null +++ b/exercises/practice/flatten-array/.docs/introduction.md @@ -0,0 +1,7 @@ +# Introduction + +A shipment of emergency supplies has arrived, but there's a problem. +To protect from damage, the items — flashlights, first-aid kits, blankets — are packed inside boxes, and some of those boxes are nested several layers deep inside other boxes! + +To be prepared for an emergency, everything must be easily accessible in one box. +Can you unpack all the supplies and place them into a single box, so they're ready when needed most? diff --git a/exercises/practice/largest-series-product/.meta/example.el b/exercises/practice/largest-series-product/.meta/example.el index b7ec9bba..bebb4b07 100644 --- a/exercises/practice/largest-series-product/.meta/example.el +++ b/exercises/practice/largest-series-product/.meta/example.el @@ -10,7 +10,7 @@ (when (< span 0) (error "span must not be negative")) (when (> span (length digits)) - (error "span must be smaller than string length")) + (error "span must not exceed string length")) (unless (cl-every 'cl-digit-char-p (cl-coerce digits 'list)) (error "digits input must only contain digits")) (let ((largest 0)) diff --git a/exercises/practice/largest-series-product/.meta/tests.toml b/exercises/practice/largest-series-product/.meta/tests.toml index 6c111adf..5a62d619 100644 --- a/exercises/practice/largest-series-product/.meta/tests.toml +++ b/exercises/practice/largest-series-product/.meta/tests.toml @@ -38,6 +38,11 @@ description = "reports zero if all spans include zero" [5d81aaf7-4f67-4125-bf33-11493cc7eab7] description = "rejects span longer than string length" +include = false + +[0ae1ce53-d9ba-41bb-827f-2fceb64f058b] +description = "rejects span longer than string length" +reimplements = "5d81aaf7-4f67-4125-bf33-11493cc7eab7" [06bc8b90-0c51-4c54-ac22-3ec3893a079e] description = "reports 1 for empty string and empty product (0 span)" @@ -47,6 +52,11 @@ description = "reports 1 for nonempty string and empty product (0 span)" [6d96c691-4374-4404-80ee-2ea8f3613dd4] description = "rejects empty string and nonzero span" +include = false + +[6cf66098-a6af-4223-aab1-26aeeefc7402] +description = "rejects empty string and nonzero span" +reimplements = "6d96c691-4374-4404-80ee-2ea8f3613dd4" [7a38f2d6-3c35-45f6-8d6f-12e6e32d4d74] description = "rejects invalid character in digits" diff --git a/exercises/practice/luhn/.docs/instructions.md b/exercises/practice/luhn/.docs/instructions.md index 5bbf007b..df2e304a 100644 --- a/exercises/practice/luhn/.docs/instructions.md +++ b/exercises/practice/luhn/.docs/instructions.md @@ -1,6 +1,6 @@ # Instructions -Determine whether a credit card number is valid according to the [Luhn formula][luhn]. +Determine whether a number is valid according to the [Luhn formula][luhn]. The number will be provided as a string. @@ -10,54 +10,59 @@ Strings of length 1 or less are not valid. Spaces are allowed in the input, but they should be stripped before checking. All other non-digit characters are disallowed. -### Example 1: valid credit card number +## Examples -```text -4539 3195 0343 6467 -``` +### Valid credit card number -The first step of the Luhn algorithm is to double every second digit, starting from the right. -We will be doubling +The number to be checked is `4539 3195 0343 6467`. + +The first step of the Luhn algorithm is to start at the end of the number and double every second digit, beginning with the second digit from the right and moving left. ```text 4539 3195 0343 6467 ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ (double these) ``` -If doubling the number results in a number greater than 9 then subtract 9 from the product. -The results of our doubling: +If the result of doubling a digit is greater than 9, we subtract 9 from that result. +We end up with: ```text 8569 6195 0383 3437 ``` -Then sum all of the digits: +Finally, we sum all digits. +If the sum is evenly divisible by 10, the original number is valid. ```text -8+5+6+9+6+1+9+5+0+3+8+3+3+4+3+7 = 80 +8 + 5 + 6 + 9 + 6 + 1 + 9 + 5 + 0 + 3 + 8 + 3 + 3 + 4 + 3 + 7 = 80 ``` -If the sum is evenly divisible by 10, then the number is valid. -This number is valid! +80 is evenly divisible by 10, so number `4539 3195 0343 6467` is valid! + +### Invalid Canadian SIN + +The number to be checked is `066 123 468`. -### Example 2: invalid credit card number +We start at the end of the number and double every second digit, beginning with the second digit from the right and moving left. ```text -8273 1232 7352 0569 +066 123 478 + ↑ ↑ ↑ ↑ (double these) ``` -Double the second digits, starting from the right +If the result of doubling a digit is greater than 9, we subtract 9 from that result. +We end up with: ```text -7253 2262 5312 0539 +036 226 458 ``` -Sum the digits +We sum the digits: ```text -7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57 +0 + 3 + 6 + 2 + 2 + 6 + 4 + 5 + 8 = 36 ``` -57 is not evenly divisible by 10, so this number is not valid. +36 is not evenly divisible by 10, so number `066 123 478` is not valid! [luhn]: https://en.wikipedia.org/wiki/Luhn_algorithm diff --git a/exercises/practice/luhn/.docs/introduction.md b/exercises/practice/luhn/.docs/introduction.md index ec2bd709..dee48006 100644 --- a/exercises/practice/luhn/.docs/introduction.md +++ b/exercises/practice/luhn/.docs/introduction.md @@ -2,10 +2,10 @@ At the Global Verification Authority, you've just been entrusted with a critical assignment. Across the city, from online purchases to secure logins, countless operations rely on the accuracy of numerical identifiers like credit card numbers, bank account numbers, transaction codes, and tracking IDs. -The Luhn algorithm is a simple checksum formula used to ensure these numbers are valid and error-free. +The Luhn algorithm is a simple checksum formula used to help identify mistyped numbers. A batch of identifiers has just arrived on your desk. All of them must pass the Luhn test to ensure they're legitimate. -If any fail, they'll be flagged as invalid, preventing errors or fraud, such as incorrect transactions or unauthorized access. +If any fail, they'll be flagged as invalid, preventing mistakes such as incorrect transactions or failed account verifications. Can you ensure this is done right? The integrity of many services depends on you. From b61efbba40c05903ba79525345a2e4b894b7598e Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Fri, 11 Apr 2025 00:17:07 +1000 Subject: [PATCH 153/162] food-chain: fix argument order (#464) [no important files changed] --- exercises/practice/food-chain/food-chain.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/food-chain/food-chain.el b/exercises/practice/food-chain/food-chain.el index 2e6df614..db25de5b 100644 --- a/exercises/practice/food-chain/food-chain.el +++ b/exercises/practice/food-chain/food-chain.el @@ -5,7 +5,7 @@ ;;; Code: -(defun recite (end-verse start-verse) +(defun recite (start-verse end-verse) (error "Delete this S-Expression and write your own implementation")) From 13d3a9357b5589d908a718021b60d86f69628bec Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Mon, 14 Apr 2025 01:16:23 +0200 Subject: [PATCH 154/162] list-ops: Make headline for instructions append show up in UI (#468) - changes headline level for instructions append to make it show up in the web UI --- exercises/practice/list-ops/.docs/instructions.append.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/list-ops/.docs/instructions.append.md b/exercises/practice/list-ops/.docs/instructions.append.md index 92400777..771c11e5 100644 --- a/exercises/practice/list-ops/.docs/instructions.append.md +++ b/exercises/practice/list-ops/.docs/instructions.append.md @@ -1,4 +1,4 @@ -# Emacs Lisp Track specific functions +## Emacs Lisp track specific functions * `list-empty-p` (*given a list, return if the list is empty*) * `list-sum` (*given a list of numbers, return the sum of all elements*) From a054b41262758882e055460d1254063eac540504 Mon Sep 17 00:00:00 2001 From: borderite Date: Mon, 14 Apr 2025 16:35:06 -0700 Subject: [PATCH 155/162] Corrected a few tests of "Phone Number". (#466) - Revised the following tests using the canonical test data. - cleans-number-test - cleans-numbers-with-dots-test - valid-when-11-digits-and-first-is-1-test - Revised the following tests specific for "Phone Number" to conform the requirements for phone numbers. - area-code-test - pprint-test - pprint-full-us-phone-number-test --- exercises/practice/phone-number/phone-number-test.el | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/exercises/practice/phone-number/phone-number-test.el b/exercises/practice/phone-number/phone-number-test.el index b89eb82b..36a73088 100644 --- a/exercises/practice/phone-number/phone-number-test.el +++ b/exercises/practice/phone-number/phone-number-test.el @@ -10,15 +10,15 @@ (declare-function pprint "phone-number.el" (num)) (ert-deftest cleans-number-test () - (should (equal (numbers "(123) 456-7890") "1234567890"))) + (should (equal (numbers "(223) 456-7890") "2234567890"))) (ert-deftest cleans-numbers-with-dots-test () - (should (equal (numbers "123.456.7890") "1234567890"))) + (should (equal (numbers "223.456.7890") "2234567890"))) (ert-deftest valid-when-11-digits-and-first-is-1-test () - (should (equal (numbers "11234567890") "1234567890"))) + (should (equal (numbers "12234567890") "2234567890"))) (ert-deftest invalid-when-11-digits-test () @@ -40,15 +40,15 @@ (ert-deftest area-code-test () - (should (equal (area-code "1234567890") "123"))) + (should (equal (area-code "2234567890") "223"))) (ert-deftest pprint-test () - (should (equal (pprint "1234567890") "(123) 456-7890"))) + (should (equal (pprint "2234567890") "(223) 456-7890"))) (ert-deftest pprint-full-us-phone-number-test () - (should (equal (pprint "11234567890") "(123) 456-7890"))) + (should (equal (pprint "12234567890") "(223) 456-7890"))) (provide 'phone-number) From 1adc23e8b4b0fd91d4a233aad5e9dcbf7ecea377 Mon Sep 17 00:00:00 2001 From: borderite Date: Tue, 15 Apr 2025 22:24:07 -0700 Subject: [PATCH 156/162] Added a Emacs Lisp track-spepcific instruction to "Phone Number" (#465) (#467) * Added a Emacs Lisp track-spepcific instruction to "Phone Number". * Phone Number: Changed wording of the additional instruction (#467) The following changes have been made, per BNAndras' suggestions. - Each sentence is now on a separate line. - The phrase "user-entered phone number(s)" has been replaced with "phone numbers". - The word "input" has been repaced with "parameter". --- .../phone-number/.docs/instructions.append.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 exercises/practice/phone-number/.docs/instructions.append.md diff --git a/exercises/practice/phone-number/.docs/instructions.append.md b/exercises/practice/phone-number/.docs/instructions.append.md new file mode 100644 index 00000000..cb0a9b9a --- /dev/null +++ b/exercises/practice/phone-number/.docs/instructions.append.md @@ -0,0 +1,11 @@ +# Instructions Append + +In addition to the function, _numbers_, that cleans up phone numbers, you need to write two more functions, _area-code_ and _pprint_ in the Emacs Lisp track. + +Each of the extra functions takes the phone number as its only parameter. + +The first function _area-code_ extracts the area code from the input, while the second function _pprint_ transforms the input to a string in the format of +``` +(NXX) NXX-XXXX +``` +where `N` and `X` are as described above. From b049818b65b36e9f510679fa2768b877aa4873fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Tue, 15 Apr 2025 23:28:13 -0700 Subject: [PATCH 157/162] Sync `phone-number` instructions (#471) --- exercises/practice/phone-number/.docs/instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/phone-number/.docs/instructions.md b/exercises/practice/phone-number/.docs/instructions.md index 62ba48e9..5d4d3739 100644 --- a/exercises/practice/phone-number/.docs/instructions.md +++ b/exercises/practice/phone-number/.docs/instructions.md @@ -1,6 +1,6 @@ # Instructions -Clean up user-entered phone numbers so that they can be sent SMS messages. +Clean up phone numbers so that they can be sent SMS messages. The **North American Numbering Plan (NANP)** is a telephone numbering system used by many countries in North America like the United States, Canada or Bermuda. All NANP-countries share the same international country code: `1`. From 906e32572af4640ec78d056754a4a2da588f087f Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Tue, 22 Apr 2025 16:20:53 +1000 Subject: [PATCH 158/162] resistor-color-trio: decimal test cases (#474) We add test cases for - 3.3 kiloohms - 3.3 megaohms - 990 megaohms - 9.9 gigaohms --- .../.docs/instructions.append.md | 5 +++++ .../resistor-color-trio/.meta/example.el | 19 ++++++++++--------- .../resistor-color-trio-test.el | 16 ++++++++++++++++ 3 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 exercises/practice/resistor-color-trio/.docs/instructions.append.md diff --git a/exercises/practice/resistor-color-trio/.docs/instructions.append.md b/exercises/practice/resistor-color-trio/.docs/instructions.append.md new file mode 100644 index 00000000..de70a112 --- /dev/null +++ b/exercises/practice/resistor-color-trio/.docs/instructions.append.md @@ -0,0 +1,5 @@ +# Instructions append + +An input of `"orange", "orange", "green"` should return: + +> "3.3 megaohms" diff --git a/exercises/practice/resistor-color-trio/.meta/example.el b/exercises/practice/resistor-color-trio/.meta/example.el index c2011b1a..8c3eff3b 100644 --- a/exercises/practice/resistor-color-trio/.meta/example.el +++ b/exercises/practice/resistor-color-trio/.meta/example.el @@ -25,15 +25,16 @@ (value (+ (* (cdr (assoc color-1 band-values)) 10) (cdr (assoc color-2 band-values)))) (resistance (* value (expt 10 (cdr (assoc color-3 band-values)))))) - (cond - ((< resistance 1000) - (format "%d ohms" resistance)) - ((< resistance 1000000) - (format "%d kiloohms" (/ resistance 1000))) - ((< resistance 1000000000) - (format "%d megaohms" (/ resistance 1000000))) - (t - (format "%d gigaohms" (/ resistance 1000000000)))))) + (string-replace ".0" "" + (cond + ((< resistance 1000) + (format "%d ohms" resistance)) + ((< resistance 1000000) + (format "%.1f kiloohms" (/ resistance 1000.0))) + ((< resistance 1000000000) + (format "%.1f megaohms" (/ resistance 1000000.0))) + (t + (format "%.1f gigaohms" (/ resistance 1000000000.0))))))) (provide 'resistor-color-trio) diff --git a/exercises/practice/resistor-color-trio/resistor-color-trio-test.el b/exercises/practice/resistor-color-trio/resistor-color-trio-test.el index 3b0838dc..6a6e3e0d 100644 --- a/exercises/practice/resistor-color-trio/resistor-color-trio-test.el +++ b/exercises/practice/resistor-color-trio/resistor-color-trio-test.el @@ -49,5 +49,21 @@ (should (string= (label '("blue" "green" "yellow" "orange")) "650 kiloohms"))) +(ert-deftest orange-and-orange-and-red () + (should (string= (label '("orange" "orange" "red")) + "3.3 kiloohms"))) + +(ert-deftest orange-and-orange-and-green () + (should (string= (label '("orange" "orange" "green")) + "3.3 megaohms"))) + +(ert-deftest white-and-white-and-violet () + (should (string= (label '("white" "white" "violet")) + "990 megaohms"))) + +(ert-deftest white-and-white-and-grey () + (should (string= (label '("white" "white" "grey")) + "9.9 gigaohms"))) + (provide 'resistor-color-trio-test) ;;; resistor-color-trio-test.el ends here From 25e2ffc9d6c866f489737526276f07f26d2265da Mon Sep 17 00:00:00 2001 From: FAP <459631+fapdash@users.noreply.github.com> Date: Sun, 27 Apr 2025 06:14:37 +0200 Subject: [PATCH 159/162] Update README.md: Update version info of the test runner (#475) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff79e989..8faa6ffd 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This repo holds all the instructions, tests, code, & support files for Emacs Lisp _exercises_ currently under development or implemented & available for students. If you haven't already, you can check out and study the live language track [here][exercism-emacs-lisp-track]. -🌟   The test runner is currently running Emacs 29.4 +🌟   The test runner is currently running Emacs 30.1 Currently the Emacs Lisp track doesn't feature a syllabus, so it only contains practice exercises. Practice exercises are open-ended problems that allow you to build and test your knowledge of a programming language. You can find the practice exercises referenced in the [config.json][config-json] and the files in the [`exercises/practice`][emacs-lisp-exercises-practice-dir] directory. The practice exercises are shared between tracks. You can find the canonical problem description in the [problem specifications repository][problem-specifications-repository]. From 59a411b134d0c27c02eb6803f4be252571d01c07 Mon Sep 17 00:00:00 2001 From: borderite Date: Sun, 27 Apr 2025 14:37:09 -0700 Subject: [PATCH 160/162] Revised tools/install-packages.el (#469) (#470) - The function exercism//install-required-packages now perform installation only if at least one of thte required applications has not be installed. --- tools/install-packages.el | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/tools/install-packages.el b/tools/install-packages.el index 8f14e5d8..a27dd593 100644 --- a/tools/install-packages.el +++ b/tools/install-packages.el @@ -1,14 +1,15 @@ +(require 'cl-extra) (defun exercism//install-required-packages () (require 'package) (package-initialize) - (unless package-archive-contents - (add-to-list - 'package-archives '("gnu" . "https://elpa.gnu.org/packages/") - t) - (add-to-list - 'package-archives '("melpa" . "https://melpa.org/packages/") - t) - (package-refresh-contents)) - (dolist (pkg '(mustache ht string-inflection)) - (unless (package-installed-p pkg) - (package-install pkg)))) + (let ((required-packages '(mustache ht string-inflection))) + (when (not (cl-every #'package-installed-p required-packages)) + (add-to-list + 'package-archives '("gnu" . "https://elpa.gnu.org/packages/") + t) + (add-to-list + 'package-archives '("melpa" . "https://melpa.org/packages/") + t) + (package-refresh-contents) + (dolist (pkg required-packages) + (package-install pkg))))) From 2c5f028058bc51ac297e18d9b2e7379ba6dab50b Mon Sep 17 00:00:00 2001 From: borderite Date: Sun, 27 Apr 2025 14:37:40 -0700 Subject: [PATCH 161/162] Implemented all "Phone Number" problems from the canonical test data. (#465) (#472) * Corrected a few tests of "Phone Number". - Revised the following tests using the canonical test data. cleans-number-test cleans-numbers-with-dots-test valid-when-11-digits-and-first-is-1-test - Revised the following tests specific for "Phone Number" to conform the requirements for phone numbers. area-code-test pprint-test pprint-full-us-phone-number-test * Implemented all "Phone Number" problems from the canonical test data. (#465) - The track-specific three problems are still included, but their solutions have been corrected. * Revert the uuid of "Phone Number" in config.json to the original one. * Update config.json The difficulty of "phone number" is reverted back to 2. * Put the entry for "Phone Number" back to the original position in ./configu.json. * Revised the test and example files of the "Phone Number" exercise. - The tests expecting errors now check custom errors instead of error messages. - The example test has been modified so that it passes the modified tests. * Added borderite to the contributor list of "Phone Number". --- config.json | 7 +- .../practice/phone-number/.meta/config.json | 3 +- .../practice/phone-number/.meta/example.el | 91 +++++++++++++++---- .../practice/phone-number/.meta/tests.toml | 1 + .../phone-number/phone-number-test.el | 62 +++++++++---- .../practice/phone-number/phone-number.el | 2 +- 6 files changed, 123 insertions(+), 43 deletions(-) diff --git a/config.json b/config.json index a9e8694f..8fc2bb5d 100644 --- a/config.json +++ b/config.json @@ -293,12 +293,7 @@ "uuid": "c211045e-da97-479d-9df4-5d812573e2d0", "practices": [], "prerequisites": [], - "difficulty": 2, - "topics": [ - "interfaces", - "parsing", - "strings" - ] + "difficulty": 2 }, { "slug": "queen-attack", diff --git a/exercises/practice/phone-number/.meta/config.json b/exercises/practice/phone-number/.meta/config.json index c475338c..60881337 100644 --- a/exercises/practice/phone-number/.meta/config.json +++ b/exercises/practice/phone-number/.meta/config.json @@ -3,7 +3,8 @@ "cpaulbond" ], "contributors": [ - "yurrriq" + "yurrriq", + "borderite" ], "files": { "solution": [ diff --git a/exercises/practice/phone-number/.meta/example.el b/exercises/practice/phone-number/.meta/example.el index 03316fa2..79bf0bcf 100644 --- a/exercises/practice/phone-number/.meta/example.el +++ b/exercises/practice/phone-number/.meta/example.el @@ -2,32 +2,91 @@ ;;; Commentary: -;;; Code: +(define-error 'short-phone-num-error "must not be fewer than 10 digits") +(define-error 'long-phone-num-error "must not be greater than 11 digits") +(define-error 'letters-in-phone-num-error "letters not permitted") +(define-error 'punctuations-in-phone-num-error "punctuations not permitted") +(define-error 'country-code-error "country code must be 1") +(define-error 'area-code-starting-with-0-error "area code cannot start with zero") +(define-error 'area-code-starting-with-1-error "area code cannot start with one") +(define-error 'exchange-code-starting-with-0-error "exchange code cannot start with zero") +(define-error 'exchange-code-starting-with-1-error "exchange code cannot start with one") +(defun char-digit-p (x) + (<= ?0 x ?9)) -(defun numbers (num) - (let ((number (replace-regexp-in-string "[^0-9]+" "" num))) - (cond - ((= (length number) 10) number) - ((and (= (length number) 11) - (string-equal (substring number 0 1) "1")) (substring number 1)) - (t "0000000000")))) +(defun char-lowercase-p (x) + (<= ?a x ?z)) +(defun char-uppercase-p (x) + (<= ?A x ?Z)) -(defun area-code (num) - (substring (numbers num) 0 3)) - +(defun char-alphabetic-p (x) + (or (char-lowercase-p x) + (char-uppercase-p x))) -(defun prefix (num) - (substring (numbers num) 3 6)) +(defun char-punctuation-p (x) + (or (<= 33 x 39) + (= x 42) + (= x 44) + (= x 47) + (<= 58 x 64) + (<= 91 x 96) + (<= 123 x 126))) +(defun negate (pred) + (lambda (&rest args) (apply pred args))) -(defun line-number (num) - (substring (numbers num) 6)) +(defun string-remove (s pred) + (let* ((n (length s)) + (to-str (make-string n ?\0)) + (k 0)) + (dotimes (i n) + (let ((x (aref s i))) + (when (funcall pred x) + (setf (aref to-str k) x) + (cl-incf k)))) + (substring to-str 0 k))) +(defun numbers (num) + "Converts a num string into a string of digits." + (cond + ((cl-find-if #'char-alphabetic-p num) + (signal 'letters-in-phone-num-error num)) + ((cl-find-if #'char-punctuation-p num) + (signal 'punctuations-in-phone-num-error num))) + (let* ((digits (string-remove num (negate #'char-digit-p))) + (n (length digits))) + (cond + ((< n 10) (signal 'short-phone-num-error num)) + ((> n 11) (signal 'long-phone-num-error num))) + (if (= n 11) + (if (= (aref digits 0) ?1) + (setf digits (substring digits 1)) + (signal 'country-code-error num))) + (let ((y (aref digits 0))) + (cond + ((= y ?0) + (signal 'area-code-starting-with-0-error num)) + ((= y ?1) + (signal 'area-code-starting-with-1-error num))) + (let ((y (aref digits 3))) + (cond + ((= y ?0) + (signal 'exchange-code-starting-with-0-error num)) + ((= y ?1) + (signal 'exchange-code-starting-with-1-error num))))) + digits)) + +(defun area-code (num) + (let ((digits (numbers num))) + (substring digits 0 3))) (defun pprint (num) - (format "(%s) %s-%s" (area-code num) (prefix num) (line-number num))) + (let ((digits (numbers num))) + (format "(%s) %s-%s" (substring digits 0 3) + (substring digits 3 6) + (substring digits 6 10)))) (provide 'phone-number) diff --git a/exercises/practice/phone-number/.meta/tests.toml b/exercises/practice/phone-number/.meta/tests.toml index 24dbf07a..4fe47d59 100644 --- a/exercises/practice/phone-number/.meta/tests.toml +++ b/exercises/practice/phone-number/.meta/tests.toml @@ -82,3 +82,4 @@ description = "invalid if exchange code starts with 0 on valid 11-digit number" [57b32f3d-696a-455c-8bf1-137b6d171cdf] description = "invalid if exchange code starts with 1 on valid 11-digit number" + diff --git a/exercises/practice/phone-number/phone-number-test.el b/exercises/practice/phone-number/phone-number-test.el index 36a73088..b1e66134 100644 --- a/exercises/practice/phone-number/phone-number-test.el +++ b/exercises/practice/phone-number/phone-number-test.el @@ -1,4 +1,4 @@ -;;; phone-number-test.el --- Tests for phone-number (exercism) -*- lexical-binding: t; -*- +;;; phone-number-test.el --- Phone Number (exercism) -*- lexical-binding: t; -*- ;;; Commentary: @@ -9,35 +9,59 @@ (declare-function area-code "phone-number.el" (num)) (declare-function pprint "phone-number.el" (num)) -(ert-deftest cleans-number-test () - (should (equal (numbers "(223) 456-7890") "2234567890"))) +(ert-deftest cleans-the-number () + (should (string= (numbers "(223) 456-7890") "2234567890"))) +(ert-deftest cleans-numbers-with-dots () + (should (string= (numbers "223.456.7890") "2234567890"))) -(ert-deftest cleans-numbers-with-dots-test () - (should (equal (numbers "223.456.7890") "2234567890"))) +(ert-deftest cleans-numbers-with-multiple-spaces () + (should (string= (numbers "223 456 7890 ") "2234567890"))) +(ert-deftest invalid-when-9-digits () + (should-error (numbers "123456789") :type 'short-phone-num-error)) -(ert-deftest valid-when-11-digits-and-first-is-1-test () - (should (equal (numbers "12234567890") "2234567890"))) +(ert-deftest invalid-when-11-digits-does-not-start-with-a-1 () + (should-error (numbers "22234567890") :type 'country-code-error)) +(ert-deftest valid-when-11-digits-and-starting-with-1 () + (should (string= (numbers "12234567890") "2234567890"))) -(ert-deftest invalid-when-11-digits-test () - (should (equal (numbers "21234567890") "0000000000"))) +(ert-deftest valid-when-11-digits-and-starting-with-1-even-with-punctuation () + (should (string= (numbers "+1 (223) 456-7890") "2234567890"))) +(ert-deftest invalid-when-more-than-11-digits () + (should-error (numbers "321234567890") :type 'long-phone-num-error)) -(ert-deftest invalid-when-9-digits-test () - (should (equal (numbers "123456789") "0000000000"))) +(ert-deftest invalid-with-letters () + (should-error (numbers "523-abc-7890") :type 'letters-in-phone-num-error)) -(ert-deftest invalid-when-more-than-11-digits-test () - (should (equal (numbers "321234567890") "0000000000"))) +(ert-deftest invalid-with-punctuations () + (should-error (numbers "523-@:!-7890") :type 'punctuations-in-phone-num-error)) -(ert-deftest invalid-with-letters () - (should (equal (numbers "523-abc-7890") "0000000000"))) +(ert-deftest invalid-if-area-code-starts-with-0 () + (should-error (numbers "(023) 456-7890") :type 'area-code-starting-with-0-error)) +(ert-deftest invalid-if-area-code-starts-with-1 () + (should-error (numbers "(123) 456-7890") :type 'area-code-starting-with-1-error)) -(ert-deftest invalid-with-punctuations () - (should (equal (numbers "523-@:!-7890") "0000000000"))) +(ert-deftest invalid-if-exchange-code-starts-with-0 () + (should-error (numbers "(223) 056-7890") :type 'exchange-code-starting-with-0-error)) + +(ert-deftest invalid-if-exchange-code-starts-with-1 () + (should-error (numbers "(223) 156-7890") :type 'exchange-code-starting-with-1-error)) +(ert-deftest invalid-if-area-code-starts-with-0-on-valid-11-digit-number () + (should-error (numbers "1 (023) 456-7890") :type 'area-code-starting-with-0-error)) + +(ert-deftest invalid-if-area-code-starts-with-1-on-valid-11-digit-number () + (should-error (numbers "1 (123) 456-7890") :type 'area-code-starting-with-1-error)) + +(ert-deftest invalid-if-exchange-code-starts-with-0-on-valid-11-digit-number () + (should-error (numbers "1 (223) 056-7890") :type 'exchange-code-starting-with-0-error)) + +(ert-deftest invalid-if-exchange-code-starts-with-1-on-valid-11-digit-number () + (should-error (numbers "1 (223) 156-7890") :type 'exchange-code-starting-with-1-error)) (ert-deftest area-code-test () (should (equal (area-code "2234567890") "223"))) @@ -50,6 +74,6 @@ (ert-deftest pprint-full-us-phone-number-test () (should (equal (pprint "12234567890") "(223) 456-7890"))) - -(provide 'phone-number) +(provide 'phone-number-test) ;;; phone-number-test.el ends here + diff --git a/exercises/practice/phone-number/phone-number.el b/exercises/practice/phone-number/phone-number.el index 61cac595..a08eee0c 100644 --- a/exercises/practice/phone-number/phone-number.el +++ b/exercises/practice/phone-number/phone-number.el @@ -1,4 +1,4 @@ -;;; phone-number.el --- phone-number Exercise (exercism) -*- lexical-binding: t; -*- +;;; phone-number.el --- phone-number (exercism) -*- lexical-binding: t; -*- ;;; Commentary: From a977876be631897e3f2b5812a9a4e6db35af691a Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Thu, 1 May 2025 23:09:45 +1000 Subject: [PATCH 162/162] Sync instructions (#477) [no important files changed] resolves #476 --- exercises/practice/crypto-square/.meta/tests.toml | 5 +++++ exercises/practice/crypto-square/crypto-square-test.el | 2 +- exercises/practice/eliuds-eggs/.docs/introduction.md | 2 +- exercises/practice/meetup/.docs/instructions.md | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/exercises/practice/crypto-square/.meta/tests.toml b/exercises/practice/crypto-square/.meta/tests.toml index 085d142e..94ef0819 100644 --- a/exercises/practice/crypto-square/.meta/tests.toml +++ b/exercises/practice/crypto-square/.meta/tests.toml @@ -32,3 +32,8 @@ description = "8 character plaintext results in 3 chunks, the last one with a tr [fbcb0c6d-4c39-4a31-83f6-c473baa6af80] description = "54 character plaintext results in 7 chunks, the last two with trailing spaces" +include = false + +[33fd914e-fa44-445b-8f38-ff8fbc9fe6e6] +description = "54 character plaintext results in 8 chunks, the last two with trailing spaces" +reimplements = "fbcb0c6d-4c39-4a31-83f6-c473baa6af80" diff --git a/exercises/practice/crypto-square/crypto-square-test.el b/exercises/practice/crypto-square/crypto-square-test.el index f2c9ddcb..1160dbef 100644 --- a/exercises/practice/crypto-square/crypto-square-test.el +++ b/exercises/practice/crypto-square/crypto-square-test.el @@ -25,7 +25,7 @@ (ert-deftest 8-character-plaintext-results-in-3-chunks-the-last-one-with-a-trailing-space () (should (equal "clu hlt io " (encipher "Chill out.")))) -(ert-deftest 54-character-plaintext-results-in-7-chunks-the-last-two-with-trailing-spaces () +(ert-deftest 54-character-plaintext-results-in-8-chunks-the-last-two-with-trailing-spaces () (should (equal "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau " (encipher "If man was meant to stay on the ground, god would have given us roots.")))) diff --git a/exercises/practice/eliuds-eggs/.docs/introduction.md b/exercises/practice/eliuds-eggs/.docs/introduction.md index 81989748..2b2e5c43 100644 --- a/exercises/practice/eliuds-eggs/.docs/introduction.md +++ b/exercises/practice/eliuds-eggs/.docs/introduction.md @@ -58,7 +58,7 @@ The position information encoding is calculated as follows: ### Decimal number on the display -16 +8 ### Actual eggs in the coop diff --git a/exercises/practice/meetup/.docs/instructions.md b/exercises/practice/meetup/.docs/instructions.md index 000de2fd..8b1bda5e 100644 --- a/exercises/practice/meetup/.docs/instructions.md +++ b/exercises/practice/meetup/.docs/instructions.md @@ -2,7 +2,7 @@ Your task is to find the exact date of a meetup, given a month, year, weekday and week. -There are five week values to consider: `first`, `second`, `third`, `fourth`, `last`, `teenth`. +There are six week values to consider: `first`, `second`, `third`, `fourth`, `last`, `teenth`. For example, you might be asked to find the date for the meetup on the first Monday in January 2018 (January 1, 2018).