diff --git a/.github/workflows/no-important-files-changed.yml b/.github/workflows/no-important-files-changed.yml new file mode 100644 index 00000000..26b068bc --- /dev/null +++ b/.github/workflows/no-important-files-changed.yml @@ -0,0 +1,68 @@ +name: No important files changed + +on: + pull_request: + types: [opened] + branches: [main] + +permissions: + pull-requests: write + +jobs: + no_important_files_changed: + name: No important files changed + runs-on: ubuntu-22.04 + steps: + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Check if important files changed + id: check + run: | + set -exo pipefail + + # fetch a ref to the main branch so we can diff against it + git remote set-branches origin main + git fetch --depth 1 origin main + + for changed_file in $(git diff --diff-filter=M --name-only origin/main); do + if ! echo "$changed_file" | grep --quiet --extended-regexp 'exercises/(practice|concept)' ; then + continue + fi + slug="$(echo "$changed_file" | sed --regexp-extended 's#exercises/[^/]+/([^/]+)/.*#\1#' )" + path_before_slug="$(echo "$changed_file" | sed --regexp-extended "s#(.*)/$slug/.*#\\1#" )" + path_after_slug="$( echo "$changed_file" | sed --regexp-extended "s#.*/$slug/(.*)#\\1#" )" + + if ! [ -f "$path_before_slug/$slug/.meta/config.json" ]; then + # cannot determine if important files changed without .meta/config.json + continue + fi + + # returns 0 if the filter matches, 1 otherwise + # | contains($path_after_slug) + if jq --exit-status \ + --arg path_after_slug "$path_after_slug" \ + '[.files.test, .files.invalidator, .files.editor] | flatten | index($path_after_slug)' \ + "$path_before_slug/$slug/.meta/config.json" \ + > /dev/null; + then + echo "important_files_changed=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + done + + echo "important_files_changed=false" >> "$GITHUB_OUTPUT" + + - name: Suggest to add [no important files changed] + if: steps.check.outputs.important_files_changed == 'true' + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea + with: + github-token: ${{ github.token }} + script: | + const body = "This PR touches files which potentially affect the outcome of the tests of an exercise. This will cause all students' solutions to affected exercises to be re-tested.\n\nIf this PR does **not** affect the result of the test (or, for example, adds an edge case that is not worth rerunning all tests for), **please add the following to the merge-commit message** which will stops student's tests from re-running. Please copy-paste to avoid typos.\n```\n[no important files changed]\n```\n\n For more information, refer to the [documentation](https://exercism.org/docs/building/tracks#h-avoiding-triggering-unnecessary-test-runs). If you are unsure whether to add the message or not, please ping `@exercism/maintainers-admin` in a comment. Thank you!" + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }) diff --git a/config.json b/config.json index 6ed84e85..c0270990 100644 --- a/config.json +++ b/config.json @@ -50,7 +50,9 @@ "slug": "lasagna", "name": "Lasagna", "uuid": "6fd75bbd-8654-4d6a-80b5-29344ceb8a48", - "concepts": ["basics"], + "concepts": [ + "basics" + ], "prerequisites": [], "status": "wip" }, @@ -579,8 +581,8 @@ "prerequisites": [ "booleans" ], - "difficulty": 1, - "status": "wip" + "difficulty": 1, + "status": "wip" }, { "slug": "pythagorean-triplet", @@ -602,6 +604,14 @@ "prerequisites": [], "difficulty": 1 }, + { + "slug": "roman-numerals", + "name": "Roman Numerals", + "uuid": "366d83ae-a069-457e-ace9-f79417ed311f", + "practices": [], + "prerequisites": [], + "difficulty": 1 + }, { "slug": "protein-translation", "name": "Protein Translation", @@ -609,6 +619,14 @@ "practices": [], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "eliuds-eggs", + "name": "Eliud's Eggs", + "uuid": "118e27fe-fe97-45fa-82cc-6480cf777e34", + "practices": [], + "prerequisites": [], + "difficulty": 1 } ] }, @@ -636,45 +654,45 @@ ], "key_features": [ { - "icon": "scientific", "title": "Domain Specific", - "content": "R is a language and environment for statistical computing and graphics." + "content": "R is a language and environment for statistical computing and graphics.", + "icon": "scientific" }, { - "icon": "cross-platform", "title": "Cross-platform", - "content": "It is free, open source, and available on every major platform." + "content": "It is free, open source, and available on every major platform.", + "icon": "cross-platform" }, { - "icon": "multi-paradigm", "title": "Multi-paradigm", - "content": "R has a functional programming foundation, but facilitates procedural or object-oriented approaches." + "content": "R has a functional programming foundation, but facilitates procedural or object-oriented approaches.", + "icon": "multi-paradigm" }, { - "icon": "powerful", "title": "Metaprogramming", - "content": "R’s metaprogramming capabilities allow for magically succinct and concise functions." + "content": "R’s metaprogramming capabilities allow for magically succinct and concise functions.", + "icon": "powerful" }, { - "icon": "tooling", "title": "Tooling", - "content": "R provides powerful tools for data manipulation, visualisation, modelling, and machine learning." + "content": "R provides powerful tools for data manipulation, visualisation, modelling, and machine learning.", + "icon": "tooling" }, { - "icon": "community", "title": "Community", - "content": "R has a diverse and welcoming community." + "content": "R has a diverse and welcoming community.", + "icon": "community" } ], "tags": [ + "execution_mode/interpreted", "paradigm/functional", "paradigm/object_oriented", - "typing/dynamic", - "execution_mode/interpreted", - "platform/windows", - "platform/mac", "platform/linux", + "platform/mac", + "platform/windows", "runtime/language_specific", + "typing/dynamic", "used_for/artificial_intelligence", "used_for/scientific_calculations", "used_for/scripts", diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index ea512c67..8cbbf7bb 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -3,11 +3,16 @@ ## Install the R runtime Visit the [CRAN homepage](https://cran.r-project.org/). There you will find download links for Linux, Mac OSX, and Windows. Download and run the installer for your operating system. -## Install the RStudio IDE +## Install the RStudio IDE (Recommended) RStudio is a popular cross-platform integrated development environment (IDE) for programming in R (and also supports other languages like Python, JavaScript, and Markdown). Using RStudio will make writing your code solutions and running tests easier. Download and install the [current stable version of RStudio](https://www.rstudio.com/products/rstudio/download/). Or, alternatively, get the [preview version](https://www.rstudio.com/products/rstudio/download/preview/) of an upcoming release. +## Install the Visual Studio Code extension for R (Alternative) +The R extension for Visual Studio Code supports extended syntax highlighting, code completion, linting, formatting, interacting with R terminals, viewing data, plots, workspace variables, help pages, managing packages and working with R Markdown documents. + +Download and install the [current version of R extension](https://code.visualstudio.com/docs/languages/r) + ## Install the R packages for running tests The test runner for the specs is the [`testthat`](https://github.com/hadley/testthat) library from Hadley Wickham, which is a popular choice for R package authors. @@ -17,9 +22,9 @@ To install this library, type the following in your RStudio console (or wherever install.packages("testthat") ``` -While it is unlikely that you will _need_ to install packages to solve the exercism problems, you may want to bring in a general-purpose utility packages like [`magrittr`](https://github.com/smbache/magrittr) that suit your programming style. To install and load a package like `magrittr`: +While it is unlikely that you will _need_ to install packages to solve the exercism problems, you may want to bring in a general-purpose utility package like [`tidyverse`](https://github.com/tidyverse/tidyverse) that suit your programming style. To install and load a package like `tidyverse`: ```{R} -install.packages("magrittr") -library(magrittr) +install.packages("tidyverse") +library(tidyverse) ``` diff --git a/exercises/concept/annalyns-infiltration/.meta/config.json b/exercises/concept/annalyns-infiltration/.meta/config.json index a5bcb8ad..8f03eda8 100644 --- a/exercises/concept/annalyns-infiltration/.meta/config.json +++ b/exercises/concept/annalyns-infiltration/.meta/config.json @@ -1,11 +1,23 @@ { - "authors": ["colinleach"], - "contributors": ["jonmcalder"], + "authors": [ + "colinleach" + ], + "contributors": [ + "jonmcalder" + ], "files": { - "solution": ["annalyns-infiltration.R"], - "test": ["test_annalyns-infiltration.R"], - "exemplar": [".meta/exemplar.R"] + "solution": [ + "annalyns-infiltration.R" + ], + "test": [ + "test_annalyns-infiltration.R" + ], + "exemplar": [ + ".meta/exemplar.R" + ] }, - "forked_from": ["Csharp/annalyns-infiltration"], + "forked_from": [ + "Csharp/annalyns-infiltration" + ], "blurb": "Learn about booleans by contributing to a strategy game" } diff --git a/exercises/concept/cars-assemble/.meta/config.json b/exercises/concept/cars-assemble/.meta/config.json index 106a2d4f..99f7249f 100644 --- a/exercises/concept/cars-assemble/.meta/config.json +++ b/exercises/concept/cars-assemble/.meta/config.json @@ -1,11 +1,20 @@ { - "authors": ["colinleach"], - "contributors": [], + "authors": [ + "colinleach" + ], "files": { - "solution": ["cars-assemble.R"], - "test": ["test_cars-assemble.R"], - "exemplar": [".meta/exemplar.R"] + "solution": [ + "cars-assemble.R" + ], + "test": [ + "test_cars-assemble.R" + ], + "exemplar": [ + ".meta/exemplar.R" + ] }, - "forked_from": ["Csharp/cars-assemble"], + "forked_from": [ + "Csharp/cars-assemble" + ], "blurb": "Learn about conditionals by analyzing the production of an assembly line." } diff --git a/exercises/concept/elyses-enchantments/.meta/config.json b/exercises/concept/elyses-enchantments/.meta/config.json index 7bb08b46..6813e11c 100644 --- a/exercises/concept/elyses-enchantments/.meta/config.json +++ b/exercises/concept/elyses-enchantments/.meta/config.json @@ -1,11 +1,20 @@ { - "authors": ["colinleach"], - "contributors": [], + "authors": [ + "colinleach" + ], "files": { - "solution": ["elyses-enchantments.R"], - "test": ["test_elyses-enchantments.R"], - "exemplar": [".meta/exemplar.R"] + "solution": [ + "elyses-enchantments.R" + ], + "test": [ + "test_elyses-enchantments.R" + ], + "exemplar": [ + ".meta/exemplar.R" + ] }, - "forked_from": ["javascript/elyses-enchantments"], + "forked_from": [ + "javascript/elyses-enchantments" + ], "blurb": "Help Elyse with her Enchantments and learn about vectors in the process." } diff --git a/exercises/concept/lasagna/.meta/config.json b/exercises/concept/lasagna/.meta/config.json index 4fa6c521..2e37d6d6 100644 --- a/exercises/concept/lasagna/.meta/config.json +++ b/exercises/concept/lasagna/.meta/config.json @@ -1,11 +1,22 @@ { - "authors": ["jonmcalder"], - "blurb": "Learn the basics of R by following a lasagna recipe.", - "icon": "lasagna", + "authors": [ + "jonmcalder" + ], "files": { - "solution": ["lasagna.R"], - "test": ["test_lasagna.R"], - "exemplar": [".meta/examplar.R"] + "solution": [ + "lasagna.R" + ], + "test": [ + "test_lasagna.R" + ], + "exemplar": [ + ".meta/examplar.R" + ] }, - "forked_from": ["csharp/basics", "ruby/basics"] + "forked_from": [ + "csharp/basics", + "ruby/basics" + ], + "icon": "lasagna", + "blurb": "Learn the basics of R by following a lasagna recipe." } diff --git a/exercises/practice/armstrong-numbers/.meta/config.json b/exercises/practice/armstrong-numbers/.meta/config.json index bd38b888..932a05e6 100644 --- a/exercises/practice/armstrong-numbers/.meta/config.json +++ b/exercises/practice/armstrong-numbers/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": ["colinleach"], + "authors": [ + "colinleach" + ], "files": { "solution": [ "armstrong-numbers.R" diff --git a/exercises/practice/darts/.meta/config.json b/exercises/practice/darts/.meta/config.json index 801ef798..325580ec 100644 --- a/exercises/practice/darts/.meta/config.json +++ b/exercises/practice/darts/.meta/config.json @@ -13,7 +13,6 @@ ".meta/example.R" ] }, - "title": "Darts", "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/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..ea83a0c7 --- /dev/null +++ b/exercises/practice/eliuds-eggs/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "Nerwosolek" + ], + "files": { + "solution": [ + "eliuds-eggs.R" + ], + "test": [ + "test_eliuds-eggs.R" + ], + "example": [ + ".meta/example.R" + ] + }, + "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.R b/exercises/practice/eliuds-eggs/.meta/example.R new file mode 100644 index 00000000..193a06a2 --- /dev/null +++ b/exercises/practice/eliuds-eggs/.meta/example.R @@ -0,0 +1,6 @@ +egg_count <- function(display_value) { + display_value |> + intToBits() |> + as.integer() |> + sum() +} 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.R b/exercises/practice/eliuds-eggs/eliuds-eggs.R new file mode 100644 index 00000000..e33d0f44 --- /dev/null +++ b/exercises/practice/eliuds-eggs/eliuds-eggs.R @@ -0,0 +1,3 @@ +egg_count <- function(display_value) { + +} diff --git a/exercises/practice/eliuds-eggs/test_eliuds-eggs.R b/exercises/practice/eliuds-eggs/test_eliuds-eggs.R new file mode 100644 index 00000000..a2f5ec96 --- /dev/null +++ b/exercises/practice/eliuds-eggs/test_eliuds-eggs.R @@ -0,0 +1,18 @@ +source("./eliuds-eggs.R") +library(testthat) + +test_that("0 eggs", { + expect_equal(egg_count(0), 0) +}) + +test_that("1 egg", { + expect_equal(egg_count(16), 1) +}) + +test_that("4 eggs", { + expect_equal(egg_count(89), 4) +}) + +test_that("13 eggs", { + expect_equal(egg_count(2000000000), 13) +}) diff --git a/exercises/practice/leap/.approaches/config.json b/exercises/practice/leap/.approaches/config.json index 3c0e1250..a46bcbfa 100644 --- a/exercises/practice/leap/.approaches/config.json +++ b/exercises/practice/leap/.approaches/config.json @@ -10,14 +10,18 @@ "slug": "boolean-chain", "title": "Boolean chain", "blurb": "Use a chain of boolean expressions.", - "authors": ["jonmcalder"] + "authors": [ + "jonmcalder" + ] }, { "uuid": "aa5cd568-60e7-4d9d-9573-752ecdbb92f7", "slug": "conditional-expression", "title": "Conditional expression", "blurb": "Use an if / else statement.", - "authors": ["jonmcalder"] + "authors": [ + "jonmcalder" + ] } ] } diff --git a/exercises/practice/queen-attack/.meta/config.json b/exercises/practice/queen-attack/.meta/config.json index 5bc29e95..16079e17 100644 --- a/exercises/practice/queen-attack/.meta/config.json +++ b/exercises/practice/queen-attack/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": ["colinleach"], + "authors": [ + "colinleach" + ], "files": { "solution": [ "queen-attack.R" 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. diff --git a/exercises/practice/raindrops/.meta/config.json b/exercises/practice/raindrops/.meta/config.json index 7e5d556e..df07e35b 100644 --- a/exercises/practice/raindrops/.meta/config.json +++ b/exercises/practice/raindrops/.meta/config.json @@ -18,7 +18,7 @@ ".meta/example.R" ] }, - "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/reverse-string/.approaches/config.json b/exercises/practice/reverse-string/.approaches/config.json index d490a026..7fa0317a 100644 --- a/exercises/practice/reverse-string/.approaches/config.json +++ b/exercises/practice/reverse-string/.approaches/config.json @@ -7,54 +7,54 @@ }, "approaches": [ { - "slug": "split-reverse", "uuid": "b5a796ed-874e-4998-af8e-9757e46e5d77", + "slug": "split-reverse", "title": "Split, reverse", + "blurb": "Use an intermediate vector of characters.", "authors": [ "jonmcalder", "colinleach" - ], - "blurb": "Use an intermediate vector of characters." + ] }, { - "slug": "utf8-reverse", "uuid": "223c062a-9070-4136-8aca-4adba0335898", + "slug": "utf8-reverse", "title": "UTF-8 reverse", + "blurb": "Use an intermediate vector of UTF-8 codes.", "authors": [ "jonmcalder", "colinleach" - ], - "blurb": "Use an intermediate vector of UTF-8 codes." + ] }, { - "slug": "native-pipes", "uuid": "f5d765b1-f75d-47a0-8c51-2e6ba58fca9f", + "slug": "native-pipes", "title": "Native pipes", + "blurb": "Use a fuctional approach with native pipes.", "authors": [ "jonmcalder", "colinleach" - ], - "blurb": "Use a fuctional approach with native pipes." + ] }, { - "slug": "vector-operations", "uuid": "e8631640-4a0e-4993-8529-6685fe1ef98e", + "slug": "vector-operations", "title": "Vectorised solution", + "blurb": "Use code that will work on vectors of strings.", "authors": [ "jonmcalder", "colinleach" - ], - "blurb": "Use code that will work on vectors of strings." + ] }, { - "slug": "stri-reverse", "uuid": "15b4c8c7-51fd-4251-8305-401b006095a8", + "slug": "stri-reverse", "title": "stringi reverse", + "blurb": "Use the built-in stri_reverse() function from the stringi library.", "authors": [ "jonmcalder", "colinleach" - ], - "blurb": "Use the built-in stri_reverse() function from the stringi library." + ] } ] } diff --git a/exercises/practice/roman-numerals/.docs/instructions.md b/exercises/practice/roman-numerals/.docs/instructions.md new file mode 100644 index 00000000..247ea089 --- /dev/null +++ b/exercises/practice/roman-numerals/.docs/instructions.md @@ -0,0 +1,41 @@ +# Instructions + +Write a function to convert from normal numbers 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. + +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). + +```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 diff --git a/exercises/practice/roman-numerals/.meta/config.json b/exercises/practice/roman-numerals/.meta/config.json new file mode 100644 index 00000000..63ac24dd --- /dev/null +++ b/exercises/practice/roman-numerals/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "colinleach" + ], + "files": { + "solution": [ + "roman-numerals.R" + ], + "test": [ + "test_roman-numerals.R" + ], + "example": [ + ".meta/example.R" + ] + }, + "blurb": "Write a function to convert from normal numbers to Roman Numerals.", + "source": "The Roman Numeral Kata", + "source_url": "https://codingdojo.org/kata/RomanNumerals/" +} diff --git a/exercises/practice/roman-numerals/.meta/example.R b/exercises/practice/roman-numerals/.meta/example.R new file mode 100644 index 00000000..5c84bf91 --- /dev/null +++ b/exercises/practice/roman-numerals/.meta/example.R @@ -0,0 +1,15 @@ +roman <- function(arabic) { + nums <- c(1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1) + romans <- c("M", "CM", "D", "CD", "C", "XC", + "L", "XL", "X", "IX", "V", "IV", "I") + result <- c() + + for (i in seq_along(nums)) { + num <- nums[i] + while (num <= arabic) { + result <- append(result, romans[i]) + arabic <- arabic - num + } + } + paste(result, sep = "", collapse = "") +} diff --git a/exercises/practice/roman-numerals/.meta/tests.toml b/exercises/practice/roman-numerals/.meta/tests.toml new file mode 100644 index 00000000..57c6c4be --- /dev/null +++ b/exercises/practice/roman-numerals/.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. + +[19828a3a-fbf7-4661-8ddd-cbaeee0e2178] +description = "1 is I" + +[f088f064-2d35-4476-9a41-f576da3f7b03] +description = "2 is II" + +[b374a79c-3bea-43e6-8db8-1286f79c7106] +description = "3 is III" + +[05a0a1d4-a140-4db1-82e8-fcc21fdb49bb] +description = "4 is IV" + +[57c0f9ad-5024-46ab-975d-de18c430b290] +description = "5 is V" + +[20a2b47f-e57f-4797-a541-0b3825d7f249] +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" + +[a1f812ef-84da-4e02-b4f0-89c907d0962c] +description = "48 is XLVIII" + +[607ead62-23d6-4c11-a396-ef821e2e5f75] +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" + +[30494be1-9afb-4f84-9d71-db9df18b55e3] +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" + +[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" + +[4e18e96b-5fbb-43df-a91b-9cb511fe0856] +description = "3999 is MMMCMXCIX" diff --git a/exercises/practice/roman-numerals/roman-numerals.R b/exercises/practice/roman-numerals/roman-numerals.R new file mode 100644 index 00000000..63c8189a --- /dev/null +++ b/exercises/practice/roman-numerals/roman-numerals.R @@ -0,0 +1,3 @@ +roman <- function(arabic) { + +} diff --git a/exercises/practice/roman-numerals/test_roman-numerals.R b/exercises/practice/roman-numerals/test_roman-numerals.R new file mode 100644 index 00000000..8931f8f7 --- /dev/null +++ b/exercises/practice/roman-numerals/test_roman-numerals.R @@ -0,0 +1,107 @@ +source("./roman-numerals.R") +library(testthat) + +test_that("1 is I", { + expect_equal(roman(1), "I") +}) + +test_that("2 is II", { + expect_equal(roman(2), "II") +}) + +test_that("3 is III", { + expect_equal(roman(3), "III") +}) + +test_that("4 is IV", { + expect_equal(roman(4), "IV") +}) + +test_that("5 is V", { + expect_equal(roman(5), "V") +}) + +test_that("6 is VI", { + expect_equal(roman(6), "VI") +}) + +test_that("9 is IX", { + expect_equal(roman(9), "IX") +}) + +test_that("16 is XVI", { + expect_equal(roman(16), "XVI") +}) + +test_that("27 is XXVII", { + expect_equal(roman(27), "XXVII") +}) + +test_that("48 is XLVIII", { + expect_equal(roman(48), "XLVIII") +}) + +test_that("49 is XLIX", { + expect_equal(roman(49), "XLIX") +}) + +test_that("59 is LIX", { + expect_equal(roman(59), "LIX") +}) + +test_that("66 is LXVI", { + expect_equal(roman(66), "LXVI") +}) + +test_that("93 is XCIII", { + expect_equal(roman(93), "XCIII") +}) + +test_that("141 is CXLI", { + expect_equal(roman(141), "CXLI") +}) + +test_that("163 is CLXIII", { + expect_equal(roman(163), "CLXIII") +}) + +test_that("166 is CLXVI", { + expect_equal(roman(166), "CLXVI") +}) + +test_that("402 is CDII", { + expect_equal(roman(402), "CDII") +}) + +test_that("575 is DLXXV", { + expect_equal(roman(575), "DLXXV") +}) + +test_that("666 is DCLXVI", { + expect_equal(roman(666), "DCLXVI") +}) + +test_that("911 is CMXI", { + expect_equal(roman(911), "CMXI") +}) + +test_that("1024 is MXXIV", { + expect_equal(roman(1024), "MXXIV") +}) + +test_that("1666 is MDCLXVI", { + expect_equal(roman(1666), "MDCLXVI") +}) + +test_that("3000 is MMM", { + expect_equal(roman(3000), "MMM") +}) + +test_that("3001 is MMMI", { + expect_equal(roman(3001), "MMMI") +}) + +test_that("3999 is MMMCMXCIX", { + expect_equal(roman(3999), "MMMCMXCIX") +}) + diff --git a/exercises/practice/vehicle-purchase/.meta/config.json b/exercises/practice/vehicle-purchase/.meta/config.json index 6db80171..b3e61aec 100644 --- a/exercises/practice/vehicle-purchase/.meta/config.json +++ b/exercises/practice/vehicle-purchase/.meta/config.json @@ -1,11 +1,20 @@ { - "authors": ["colinleach"], - "contributors": ["jonmcalder"], + "authors": [ + "colinleach" + ], + "contributors": [ + "jonmcalder" + ], "files": { - "solution": ["vehicle-purchase.R"], - "test": ["test_vehicle-purchase.R"], - "example": [".meta/example.R"] + "solution": [ + "vehicle-purchase.R" + ], + "test": [ + "test_vehicle-purchase.R" + ], + "example": [ + ".meta/example.R" + ] }, - "forked_from": ["javascript/vehicle-purchase"], "blurb": "Learn about comparison and conditionals while preparing for your next vehicle purchase" }