From 79f77f009aba6a0cbbed29b24e379ace719c18dd Mon Sep 17 00:00:00 2001 From: Danylo Negrienko Date: Thu, 22 Aug 2024 10:12:28 -0400 Subject: [PATCH] crypto_square started --- elixir/crypto-square/.exercism/config.json | 31 ++++++ elixir/crypto-square/.exercism/metadata.json | 1 + elixir/crypto-square/.formatter.exs | 4 + elixir/crypto-square/.gitignore | 24 +++++ elixir/crypto-square/HELP.md | 75 ++++++++++++++ elixir/crypto-square/README.md | 99 +++++++++++++++++++ elixir/crypto-square/lib/crypto_square.ex | 31 ++++++ elixir/crypto-square/mix.exs | 28 ++++++ .../crypto-square/test/crypto_square_test.exs | 45 +++++++++ elixir/crypto-square/test/test_helper.exs | 2 + 10 files changed, 340 insertions(+) create mode 100644 elixir/crypto-square/.exercism/config.json create mode 100644 elixir/crypto-square/.exercism/metadata.json create mode 100644 elixir/crypto-square/.formatter.exs create mode 100644 elixir/crypto-square/.gitignore create mode 100644 elixir/crypto-square/HELP.md create mode 100644 elixir/crypto-square/README.md create mode 100644 elixir/crypto-square/lib/crypto_square.ex create mode 100644 elixir/crypto-square/mix.exs create mode 100644 elixir/crypto-square/test/crypto_square_test.exs create mode 100644 elixir/crypto-square/test/test_helper.exs diff --git a/elixir/crypto-square/.exercism/config.json b/elixir/crypto-square/.exercism/config.json new file mode 100644 index 0000000..12235b5 --- /dev/null +++ b/elixir/crypto-square/.exercism/config.json @@ -0,0 +1,31 @@ +{ + "authors": [ + "jimmbraddock" + ], + "contributors": [ + "amencarini", + "angelikatyborska", + "Cohen-Carlisle", + "devonestes", + "ggpasqualino", + "lpil", + "neenjaw", + "parkerl", + "sotojuan", + "waiting-for-dev" + ], + "files": { + "solution": [ + "lib/crypto_square.ex" + ], + "test": [ + "test/crypto_square_test.exs" + ], + "example": [ + ".meta/example.ex" + ] + }, + "blurb": "Implement the classic method for composing secret messages called a square code.", + "source": "J Dalbey's Programming Practice problems", + "source_url": "https://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html" +} diff --git a/elixir/crypto-square/.exercism/metadata.json b/elixir/crypto-square/.exercism/metadata.json new file mode 100644 index 0000000..485b763 --- /dev/null +++ b/elixir/crypto-square/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"elixir","exercise":"crypto-square","id":"1037f974f1844ed2b31c6a84f83a8e18","url":"https://exercism.org/tracks/elixir/exercises/crypto-square","handle":"negrienko","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/elixir/crypto-square/.formatter.exs b/elixir/crypto-square/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/elixir/crypto-square/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/elixir/crypto-square/.gitignore b/elixir/crypto-square/.gitignore new file mode 100644 index 0000000..da2aaeb --- /dev/null +++ b/elixir/crypto-square/.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"). +crypto_square-*.tar + diff --git a/elixir/crypto-square/HELP.md b/elixir/crypto-square/HELP.md new file mode 100644 index 0000000..4ce6895 --- /dev/null +++ b/elixir/crypto-square/HELP.md @@ -0,0 +1,75 @@ +# Help + +## Running the tests + +From the terminal, change to the base directory of the exercise then execute the tests with: + +```bash +$ mix test +``` + +This will execute the test file found in the `test` subfolder -- a file ending in `_test.exs` + +Documentation: + +* [`mix test` - Elixir's test execution tool](https://hexdocs.pm/mix/Mix.Tasks.Test.html) +* [`ExUnit` - Elixir's unit test library](https://hexdocs.pm/ex_unit/ExUnit.html) + +## Pending tests + +In test suites of practice exercises, all but the first test have been tagged to be 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 +``` + +If you wish to run all tests at once, you can include all skipped test by using the `--include` flag on the `mix test` command: + +```bash +$ mix test --include pending +``` + +Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the file `test/test_helper.exs`. + +```elixir +# ExUnit.configure(exclude: :pending, trace: true) +``` + +## Useful `mix test` options + +* `test/.exs:LINENUM` - runs only a single test, the test from `.exs` whose definition is on line `LINENUM` +* `--failed` - runs only tests that failed the last time they ran +* `--max-failures` - the suite stops evaluating tests when this number of test failures +is reached +* `--seed 0` - disables randomization so the tests in a single file will always be ran +in the same order they were defined in + +## Submitting your solution + +You can submit your solution using the `exercism submit lib/crypto_square.ex` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Elixir track's documentation](https://exercism.org/docs/tracks/elixir) +- The [Elixir track's programming category on the forum](https://forum.exercism.org/c/programming/elixir) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +If you're stuck on something, it may help to look at some of the [available resources](https://exercism.org/docs/tracks/elixir/resources) out there where answers might be found. \ No newline at end of file diff --git a/elixir/crypto-square/README.md b/elixir/crypto-square/README.md new file mode 100644 index 0000000..5d8e46b --- /dev/null +++ b/elixir/crypto-square/README.md @@ -0,0 +1,99 @@ +# Crypto Square + +Welcome to Crypto Square on Exercism's Elixir Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Implement the classic method for composing secret messages called a square code. + +Given an English text, output the encoded version of that text. + +First, the input is normalized: the spaces and punctuation are removed from the English text and the message is down-cased. + +Then, the normalized characters are broken into rows. +These rows can be regarded as forming a rectangle when printed with intervening newlines. + +For example, the sentence + +```text +"If man was meant to stay on the ground, god would have given us roots." +``` + +is normalized to: + +```text +"ifmanwasmeanttostayonthegroundgodwouldhavegivenusroots" +``` + +The plaintext should be organized into a rectangle as square as possible. +The size of the rectangle should be decided by the length of the message. + +If `c` is the number of columns and `r` is the number of rows, then for the rectangle `r` x `c` find the smallest possible integer `c` such that: + +- `r * c >= length of message`, +- and `c >= r`, +- and `c - r <= 1`. + +Our normalized text is 54 characters long, dictating a rectangle with `c = 8` and `r = 7`: + +```text +"ifmanwas" +"meanttos" +"tayonthe" +"groundgo" +"dwouldha" +"vegivenu" +"sroots " +``` + +The coded message is obtained by reading down the columns going left to right. + +The message above is coded as: + +```text +"imtgdvsfearwermayoogoanouuiontnnlvtwttddesaohghnsseoau" +``` + +Output the encoded text in chunks that fill perfect rectangles `(r X c)`, with `c` chunks of `r` length, separated by spaces. +For phrases that are `n` characters short of the perfect rectangle, pad each of the last `n` chunks with a single trailing space. + +```text +"imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau " +``` + +Notice that were we to stack these, we could visually decode the ciphertext back in to the original message: + +```text +"imtgdvs" +"fearwer" +"mayoogo" +"anouuio" +"ntnnlvt" +"wttddes" +"aohghn " +"sseoau " +``` + +## Source + +### Created by + +- @jimmbraddock + +### Contributed to by + +- @amencarini +- @angelikatyborska +- @Cohen-Carlisle +- @devonestes +- @ggpasqualino +- @lpil +- @neenjaw +- @parkerl +- @sotojuan +- @waiting-for-dev + +### Based on + +J Dalbey's Programming Practice problems - https://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html \ No newline at end of file diff --git a/elixir/crypto-square/lib/crypto_square.ex b/elixir/crypto-square/lib/crypto_square.ex new file mode 100644 index 0000000..c1bb6a2 --- /dev/null +++ b/elixir/crypto-square/lib/crypto_square.ex @@ -0,0 +1,31 @@ +defmodule CryptoSquare do + @doc """ + Encode string square methods + ## Examples + + iex> CryptoSquare.encode("abcd") + "ac bd" + """ + @spec encode(String.t()) :: String.t() + def encode(str) do + str + |> normalize() + |> square() + end + + defp normalize(str) do + str + |> String.downcase() + |> String.replace(~r/[^a-z0-9]/, "") + end + + defp square(str) do + length = String.length(str) + row = :math.ceil(length ** 0.5) + col = :math.ceil(length / row) + + str + |> String.split("", trim: true) + |> Enum.chunk_every(col, col) + end +end diff --git a/elixir/crypto-square/mix.exs b/elixir/crypto-square/mix.exs new file mode 100644 index 0000000..d07cbde --- /dev/null +++ b/elixir/crypto-square/mix.exs @@ -0,0 +1,28 @@ +defmodule CryptoSquare.MixProject do + use Mix.Project + + def project do + [ + app: :crypto_square, + 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/crypto-square/test/crypto_square_test.exs b/elixir/crypto-square/test/crypto_square_test.exs new file mode 100644 index 0000000..8d2fcfb --- /dev/null +++ b/elixir/crypto-square/test/crypto_square_test.exs @@ -0,0 +1,45 @@ +defmodule CryptoSquareTest do + use ExUnit.Case + + # @tag :pending + test "empty plaintext results in an empty ciphertext" do + assert CryptoSquare.encode("") == "" + end + + @tag :pending + test "normalization results in empty plaintext" do + assert CryptoSquare.encode("... --- ...") == "" + end + + @tag :pending + test "lowercase" do + assert CryptoSquare.encode("A") == "a" + end + + @tag :pending + test "remove spaces" do + assert CryptoSquare.encode(" b ") == "b" + end + + @tag :pending + test "remove punctuation" do + assert CryptoSquare.encode("@1,%!") == "1" + end + + @tag :pending + test "9 character plaintext results in 3 chunks of 3 characters" do + assert CryptoSquare.encode("This is fun!") == "tsf hiu isn" + end + + @tag :pending + test "8 character plaintext results in 3 chunks, the last one with a trailing space" do + assert CryptoSquare.encode("Chill out.") == "clu hlt io " + end + + @tag :pending + test "54 character plaintext results in 7 chunks, the last two with trailing spaces" do + msg = "If man was meant to stay on the ground, god would have given us roots." + cipher = "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau " + assert CryptoSquare.encode(msg) == cipher + end +end diff --git a/elixir/crypto-square/test/test_helper.exs b/elixir/crypto-square/test/test_helper.exs new file mode 100644 index 0000000..35fc5bf --- /dev/null +++ b/elixir/crypto-square/test/test_helper.exs @@ -0,0 +1,2 @@ +ExUnit.start() +ExUnit.configure(exclude: :pending, trace: true)