diff --git a/elixir/roman-numerals/.exercism/metadata.json b/elixir/roman-numerals/.exercism/metadata.json new file mode 100644 index 0000000..0132f44 --- /dev/null +++ b/elixir/roman-numerals/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"elixir","exercise":"roman-numerals","id":"25ed35ad01214047827de019945b902d","url":"https://exercism.io/my/solutions/25ed35ad01214047827de019945b902d","handle":"Xevion","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/elixir/roman-numerals/.formatter.exs b/elixir/roman-numerals/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/elixir/roman-numerals/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/elixir/roman-numerals/.gitignore b/elixir/roman-numerals/.gitignore new file mode 100644 index 0000000..2a676eb --- /dev/null +++ b/elixir/roman-numerals/.gitignore @@ -0,0 +1,24 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +roman_numerals-*.tar + diff --git a/elixir/roman-numerals/README.md b/elixir/roman-numerals/README.md new file mode 100644 index 0000000..697cebf --- /dev/null +++ b/elixir/roman-numerals/README.md @@ -0,0 +1,85 @@ +# Roman Numerals + +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 programmes. + +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 +``` + +There is no need to be able to convert numbers larger than about 3000. +(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 + +See also: http://www.novaroma.org/via_romana/numbers.html + +## Running tests + +Execute the tests with: + +```bash +$ mix test +``` + +### Pending tests + +In the test suites, all but the first test have been skipped. + +Once you get a test passing, you can unskip the next one by +commenting out the relevant `@tag :pending` with a `#` symbol. + +For example: + +```elixir +# @tag :pending +test "shouting" do + assert Bob.hey("WATCH OUT!") == "Whoa, chill out!" +end +``` + +Or, you can enable all the tests by commenting out the +`ExUnit.configure` line in the test suite. + +```elixir +# ExUnit.configure exclude: :pending, trace: true +``` + +If you're stuck on something, it may help to look at some of +the [available resources](https://exercism.io/tracks/elixir/resources) +out there where answers might be found. + +## Source + +The Roman Numeral Kata [http://codingdojo.org/cgi-bin/index.pl?KataRomanNumerals](http://codingdojo.org/cgi-bin/index.pl?KataRomanNumerals) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/elixir/roman-numerals/lib/roman_numerals.ex b/elixir/roman-numerals/lib/roman_numerals.ex new file mode 100644 index 0000000..af8a5d5 --- /dev/null +++ b/elixir/roman-numerals/lib/roman_numerals.ex @@ -0,0 +1,39 @@ +defmodule RomanNumerals do + @values %{ + "I" => 1, + "IV" => 4, + "V" => 5, + "IX" => 9, + "X" => 10, + "XL" => 40, + "L" => 50, + "XC" => 90, + "C" => 100, + "CD" => 400, + "D" => 500, + "CM" => 900, + "M" => 1000 + } + + @doc """ + Convert the number to a roman number. + """ + @spec numeral(pos_integer) :: String.t() + def numeral(number) do + number + |> Stream.unfold(fn + 0 -> nil + n -> get_max(n) + end) + |> Enum.join() + end + + defp get_max(n) do + numeral = + Map.keys(@values) + |> Enum.filter(&(Map.get(@values, &1) <= n)) + |> Enum.max_by(&Map.get(@values, &1)) + + {numeral, n - Map.get(@values, numeral)} + end +end diff --git a/elixir/roman-numerals/mix.exs b/elixir/roman-numerals/mix.exs new file mode 100644 index 0000000..33f5ed5 --- /dev/null +++ b/elixir/roman-numerals/mix.exs @@ -0,0 +1,28 @@ +defmodule RomanNumerals.MixProject do + use Mix.Project + + def project do + [ + app: :roman_numerals, + version: "0.1.0", + # elixir: "~> 1.8", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger] + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [ + # {:dep_from_hexpm, "~> 0.3.0"}, + # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} + ] + end +end diff --git a/elixir/roman-numerals/test/roman_numerals_test.exs b/elixir/roman-numerals/test/roman_numerals_test.exs new file mode 100644 index 0000000..d77cf6c --- /dev/null +++ b/elixir/roman-numerals/test/roman_numerals_test.exs @@ -0,0 +1,93 @@ +defmodule RomanNumeralsTest do + use ExUnit.Case + + # @tag :pending + test "1" do + assert RomanNumerals.numeral(1) == "I" + end + + @tag :pending + test "2" do + assert RomanNumerals.numeral(2) == "II" + end + + @tag :pending + test "3" do + assert RomanNumerals.numeral(3) == "III" + end + + @tag :pending + test "4" do + assert RomanNumerals.numeral(4) == "IV" + end + + @tag :pending + test "5" do + assert RomanNumerals.numeral(5) == "V" + end + + @tag :pending + test "6" do + assert RomanNumerals.numeral(6) == "VI" + end + + @tag :pending + test "9" do + assert RomanNumerals.numeral(9) == "IX" + end + + @tag :pending + test "27" do + assert RomanNumerals.numeral(27) == "XXVII" + end + + @tag :pending + test "48" do + assert RomanNumerals.numeral(48) == "XLVIII" + end + + @tag :pending + test "59" do + assert RomanNumerals.numeral(59) == "LIX" + end + + @tag :pending + test "93" do + assert RomanNumerals.numeral(93) == "XCIII" + end + + @tag :pending + test "141" do + assert RomanNumerals.numeral(141) == "CXLI" + end + + @tag :pending + test "163" do + assert RomanNumerals.numeral(163) == "CLXIII" + end + + @tag :pending + test "402" do + assert RomanNumerals.numeral(402) == "CDII" + end + + @tag :pending + test "575" do + assert RomanNumerals.numeral(575) == "DLXXV" + end + + @tag :pending + test "911" do + assert RomanNumerals.numeral(911) == "CMXI" + end + + @tag :pending + test "1024" do + assert RomanNumerals.numeral(1024) == "MXXIV" + end + + @tag :pending + test "3000" do + assert RomanNumerals.numeral(3000) == "MMM" + end +end diff --git a/elixir/roman-numerals/test/test_helper.exs b/elixir/roman-numerals/test/test_helper.exs new file mode 100644 index 0000000..0ee8618 --- /dev/null +++ b/elixir/roman-numerals/test/test_helper.exs @@ -0,0 +1,2 @@ +ExUnit.start() +# ExUnit.configure(exclude: :pending, trace: true)