trackler 2.2.1.155 → 2.2.1.156
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitmodules +3 -0
- data/lib/trackler/version.rb +1 -1
- data/problem-specifications/exercises/simple-cipher/canonical-data.json +147 -0
- data/tracks/clojure/exercises/hexadecimal/src/hexadecimal.clj +5 -0
- data/tracks/clojure/exercises/isogram/src/isogram.clj +5 -0
- data/tracks/clojure/exercises/kindergarten-garden/src/kindergarten-garden.clj +5 -0
- data/tracks/csharp/exercises/list-ops/Example.cs +14 -9
- data/tracks/csharp/exercises/list-ops/ListOps.cs +4 -4
- data/tracks/csharp/exercises/list-ops/ListOpsTest.cs +90 -88
- data/tracks/csharp/exercises/zipper/Example.cs +51 -43
- data/tracks/csharp/exercises/zipper/Zipper.cs +16 -19
- data/tracks/csharp/exercises/zipper/ZipperTest.cs +94 -45
- data/tracks/csharp/generators/Exercises/ListOps.cs +123 -0
- data/tracks/csharp/generators/Exercises/Zipper.cs +107 -0
- data/tracks/csharp/generators/Output/ValueFormatter.cs +14 -0
- data/tracks/delphi/config.json +10 -1
- data/tracks/delphi/config/maintainers.json +11 -11
- data/tracks/elisp/config.json +8 -0
- data/tracks/elisp/exercises/run-length-encoding/README.md +36 -0
- data/tracks/elisp/exercises/run-length-encoding/example.el +62 -0
- data/tracks/elisp/exercises/run-length-encoding/run-length-encoding-test.el +61 -0
- data/tracks/elisp/exercises/run-length-encoding/run-length-encoding.el +9 -0
- data/tracks/fsharp/docs/LEARNING.md +3 -0
- data/tracks/java/exercises/armstrong-numbers/.meta/hints.md +2 -0
- data/tracks/java/exercises/armstrong-numbers/README.md +6 -0
- data/tracks/java/exercises/bracket-push/.meta/version +1 -1
- data/tracks/java/exercises/bracket-push/src/test/java/BracketCheckerTest.java +7 -0
- data/tracks/java/exercises/isbn-verifier/.meta/version +1 -1
- data/tracks/java/exercises/isbn-verifier/src/test/java/IsbnVerifierTest.java +12 -1
- data/tracks/java/exercises/kindergarten-garden/.meta/version +1 -1
- data/tracks/java/exercises/list-ops/.meta/version +1 -1
- data/tracks/java/exercises/list-ops/src/test/java/ListOpsTest.java +32 -1
- data/tracks/nim/config.json +13 -2
- data/tracks/nim/exercises/bob/bob_test.nim +1 -1
- data/tracks/nim/exercises/bob/example.nim +6 -3
- data/tracks/nim/exercises/bracket-push/README.md +11 -0
- data/tracks/nim/exercises/bracket-push/bracket_push_test.nim +52 -0
- data/tracks/nim/exercises/bracket-push/example.nim +22 -0
- data/tracks/ocaml/exercises/bracket-push/test.ml +3 -1
- data/tracks/ocaml/exercises/luhn/example.ml +8 -5
- data/tracks/ocaml/exercises/luhn/test.ml +3 -1
- data/tracks/powershell/.gitignore +2 -1
- data/tracks/powershell/config.json +46 -13
- data/tracks/powershell/exercises/bob/.version +1 -0
- data/tracks/powershell/exercises/bob/BobResponse.example.ps1 +28 -0
- data/tracks/powershell/exercises/bob/BobResponse.ps1 +8 -0
- data/tracks/powershell/exercises/bob/BobResponse.tests.ps1 +109 -0
- data/tracks/powershell/exercises/bob/README.md +20 -0
- data/tracks/powershell/exercises/nucleotide-count/.version +1 -0
- data/tracks/powershell/exercises/nucleotide-count/NucleotideCount.example.ps1 +36 -0
- data/tracks/powershell/exercises/nucleotide-count/NucleotideCount.ps1 +8 -0
- data/tracks/powershell/exercises/nucleotide-count/NucleotideCount.tests.ps1 +25 -0
- data/tracks/powershell/exercises/nucleotide-count/README.md +19 -0
- data/tracks/powershell/exercises/raindrops/.version +1 -0
- data/tracks/powershell/exercises/raindrops/README.md +24 -0
- data/tracks/powershell/exercises/raindrops/Raindrops.example.ps1 +32 -0
- data/tracks/powershell/exercises/raindrops/Raindrops.ps1 +8 -0
- data/tracks/powershell/exercises/raindrops/Raindrops.tests.ps1 +34 -0
- data/tracks/prolog/exercises/complex-numbers/complex_numbers_tests.plt +28 -29
- data/tracks/reasonml/.gitignore +4 -0
- data/tracks/reasonml/.travis.yml +5 -0
- data/tracks/reasonml/LICENSE +21 -0
- data/tracks/reasonml/README.md +67 -0
- data/tracks/reasonml/bin/fetch-configlet +32 -0
- data/tracks/reasonml/config.json +11 -0
- data/tracks/reasonml/config/exercise-readme-insert.md +0 -0
- data/tracks/reasonml/config/exercise_readme.go.tmpl +16 -0
- data/tracks/reasonml/config/maintainers.json +4 -0
- data/tracks/reasonml/docs/ABOUT.md +0 -0
- data/tracks/reasonml/docs/INSTALLATION.md +0 -0
- data/tracks/reasonml/docs/LEARNING.md +0 -0
- data/tracks/reasonml/docs/RESOURCES.md +0 -0
- data/tracks/reasonml/docs/TESTS.md +0 -0
- data/tracks/reasonml/img/.keep +0 -0
- data/tracks/scala/config.json +11 -0
- data/tracks/scala/exercises/armstrong-numbers/README.md +29 -0
- data/tracks/scala/exercises/armstrong-numbers/build.sbt +3 -0
- data/tracks/scala/exercises/armstrong-numbers/example.scala +7 -0
- data/tracks/scala/exercises/armstrong-numbers/src/main/scala/.keep +0 -0
- data/tracks/scala/exercises/armstrong-numbers/src/test/scala/ArmstrongNumbersTest.scala +44 -0
- data/tracks/scala/testgen/src/main/scala/ArmstrongNumbersTestGenerator.scala +33 -0
- data/tracks/scheme/config.json +8 -0
- data/tracks/scheme/exercises/atbash-cipher/README.md +36 -0
- data/tracks/scheme/exercises/atbash-cipher/atbash-cipher-test.scm +67 -0
- data/tracks/scheme/exercises/atbash-cipher/atbash-cipher.scm +8 -0
- data/tracks/scheme/exercises/atbash-cipher/example.scm +40 -0
- metadata +57 -3
- data/tracks/python/exercises/rna-transcription/.meta/hints.md +0 -1
@@ -0,0 +1,67 @@
|
|
1
|
+
# Exercism ReasonML Track
|
2
|
+
|
3
|
+
![build status](https://travis-ci.org/exercism/reasonml.svg?branch=master)
|
4
|
+
|
5
|
+
Exercism exercises in ReasonML.
|
6
|
+
|
7
|
+
## Setup
|
8
|
+
|
9
|
+
The simplest way to install ReasonML is ...
|
10
|
+
|
11
|
+
## Contributing
|
12
|
+
|
13
|
+
Thank you so much for contributing! :tada:
|
14
|
+
|
15
|
+
Please read about how to [get involved in a track](https://github.com/exercism/docs/tree/master/contributing-to-language-tracks). Be sure to read the Exercism [Code of Conduct](https://github.com/exercism/exercism.io/blob/master/CODE_OF_CONDUCT.md).
|
16
|
+
|
17
|
+
We welcome pull requests of all kinds. No contribution is too small.
|
18
|
+
|
19
|
+
We encourage contributions that provide fixes and improvements to existing exercises. Please note that this track's exercises must conform to the Exercism-wide standards described in the [documentation](https://github.com/exercism/docs/tree/master/language-tracks/exercises). If you're unsure about how to make a change, then go ahead and open a GitHub issue, and we'll discuss it.
|
20
|
+
|
21
|
+
## Exercise Tests
|
22
|
+
|
23
|
+
At the most basic level, Exercism is all about the tests. You can read more about how we think about test suites in [the Exercism documentation](https://github.com/exercism/docs/blob/master/language-tracks/exercises/anatomy/test-suites.md).
|
24
|
+
|
25
|
+
Test files should use the following format:
|
26
|
+
|
27
|
+
```
|
28
|
+
# include the body of an example test
|
29
|
+
```
|
30
|
+
|
31
|
+
## Opening an Issue
|
32
|
+
|
33
|
+
If you plan to make significant or breaking changes, please open an issue so we can discuss it first. If this is a discussion that is relevant to more than just the ReasonML track, please open an issue in [exercism/discussions](https://github.com/exercism/discussions/issues).
|
34
|
+
|
35
|
+
## Submitting a Pull Request
|
36
|
+
|
37
|
+
Pull requests should be focused on a single exercise, issue, or conceptually cohesive change. Please refer to Exercism's [pull request guidelines](https://github.com/exercism/docs/blob/master/contributing/pull-request-guidelines.md).
|
38
|
+
|
39
|
+
Please follow the coding standards for ReasonML. (If there is a formatter for the track's language, add instructions for using it here.)
|
40
|
+
|
41
|
+
### Verifying Your Change
|
42
|
+
|
43
|
+
Before submitting your pull request, you'll want to verify the changes in two ways:
|
44
|
+
|
45
|
+
* Run all the tests for the ReasonML exercises
|
46
|
+
* Run an Exercism-specific linter to verify the track
|
47
|
+
|
48
|
+
All the tests for ReasonML exercises can be run from the top level of the repo with
|
49
|
+
|
50
|
+
```
|
51
|
+
# add this command
|
52
|
+
```
|
53
|
+
|
54
|
+
For the Exercism-specific linting, please see [the documentation](https://github.com/exercism/docs/blob/master/language-tracks/configuration/linting.md).
|
55
|
+
|
56
|
+
## Contributing a New Exercise
|
57
|
+
|
58
|
+
Please see the documentation about [adding new exercises](https://github.com/exercism/docs/blob/master/you-can-help/make-up-new-exercises.md).
|
59
|
+
|
60
|
+
Note that:
|
61
|
+
|
62
|
+
- Each exercise must stand on its own. Do not reference files outside the exercise directory. They will not be included when the user fetches the exercise.
|
63
|
+
- Exercises should use only the ReasonML core libraries.
|
64
|
+
- Exercises must conform to the Exercism-wide standards described in [the documentation](https://github.com/exercism/docs/tree/master/language-tracks/exercises).
|
65
|
+
- Each exercise should have a test suite, an example solution, a template file for the real implementation and ... (anything else that needs to go with each exercise for this track). The CI build expects files to be named using the following convention: (describe the ReasonML convention for naming the various files that make up an exercise).
|
66
|
+
- Please do not commit any configuration files or directories inside the exercise other than ...
|
67
|
+
- Be sure to add it to the appropriate place in the `config.json` file.
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
LATEST=https://github.com/exercism/configlet/releases/latest
|
4
|
+
|
5
|
+
OS=$(
|
6
|
+
case $(uname) in
|
7
|
+
(Darwin*)
|
8
|
+
echo "mac";;
|
9
|
+
(Linux*)
|
10
|
+
echo "linux";;
|
11
|
+
(Windows*)
|
12
|
+
echo "windows";;
|
13
|
+
(*)
|
14
|
+
echo "linux";;
|
15
|
+
esac)
|
16
|
+
|
17
|
+
ARCH=$(
|
18
|
+
case $(uname -m) in
|
19
|
+
(*64*)
|
20
|
+
echo 64bit;;
|
21
|
+
(*686*)
|
22
|
+
echo 32bit;;
|
23
|
+
(*386*)
|
24
|
+
echo 32bit;;
|
25
|
+
(*)
|
26
|
+
echo 64bit;;
|
27
|
+
esac)
|
28
|
+
|
29
|
+
VERSION="$(curl --head --silent $LATEST | awk -v FS=/ '/Location:/{print $NF}' | tr -d '\r')"
|
30
|
+
URL=https://github.com/exercism/configlet/releases/download/$VERSION/configlet-$OS-${ARCH}.tgz
|
31
|
+
|
32
|
+
curl -s --location $URL | tar xz -C bin/
|
File without changes
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# {{ .Spec.Name }}
|
2
|
+
|
3
|
+
{{ .Spec.Description -}}
|
4
|
+
{{- with .Hints }}
|
5
|
+
{{ . }}
|
6
|
+
{{ end }}
|
7
|
+
{{- with .TrackInsert }}
|
8
|
+
{{ . }}
|
9
|
+
{{ end }}
|
10
|
+
{{- with .Spec.Credits -}}
|
11
|
+
## Source
|
12
|
+
|
13
|
+
{{ . }}
|
14
|
+
{{ end }}
|
15
|
+
## Submitting Incomplete Solutions
|
16
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/tracks/scala/config.json
CHANGED
@@ -105,6 +105,17 @@
|
|
105
105
|
"Mathematics"
|
106
106
|
]
|
107
107
|
},
|
108
|
+
{
|
109
|
+
"uuid": "2bd9ab9e-ecc4-4331-984d-8e5f15f775b4",
|
110
|
+
"slug": "armstrong-numbers",
|
111
|
+
"core": false,
|
112
|
+
"unlocked_by": "leap",
|
113
|
+
"difficulty": 2,
|
114
|
+
"topics": [
|
115
|
+
"Integers",
|
116
|
+
"Mathematics"
|
117
|
+
]
|
118
|
+
},
|
108
119
|
{
|
109
120
|
"uuid": "5a31217f-02fd-4be4-b64f-7a93f36f5140",
|
110
121
|
"slug": "hamming",
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Armstrong Numbers
|
2
|
+
|
3
|
+
An [Armstrong number](https://en.wikipedia.org/wiki/Narcissistic_number) is a number that is the sum of its own digits each raised to the power of the number of digits.
|
4
|
+
|
5
|
+
For example:
|
6
|
+
|
7
|
+
- 9 is an Armstrong number, because `9 = 9^1 = 9`
|
8
|
+
- 10 is *not* an Armstrong number, because `10 != 1^2 + 0^2 = 1`
|
9
|
+
- 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153`
|
10
|
+
- 154 is *not* an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190`
|
11
|
+
|
12
|
+
Write some code to determine whether a number is an Armstrong number.
|
13
|
+
|
14
|
+
The Scala exercises assume an SBT project scheme. The exercise solution source
|
15
|
+
should be placed within the exercise directory/src/main/scala. The exercise
|
16
|
+
unit tests can be found within the exercise directory/src/test/scala.
|
17
|
+
|
18
|
+
To run the tests simply run the command `sbt test` in the exercise directory.
|
19
|
+
|
20
|
+
For more detailed info about the Scala track see the [help
|
21
|
+
page](http://exercism.io/languages/scala).
|
22
|
+
|
23
|
+
|
24
|
+
## Source
|
25
|
+
|
26
|
+
Wikipedia [https://en.wikipedia.org/wiki/Narcissistic_number](https://en.wikipedia.org/wiki/Narcissistic_number)
|
27
|
+
|
28
|
+
## Submitting Incomplete Solutions
|
29
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
File without changes
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import org.scalatest.{Matchers, FunSuite}
|
2
|
+
|
3
|
+
/** @version 1.0.0 */
|
4
|
+
class ArmstrongNumbersTest extends FunSuite with Matchers {
|
5
|
+
|
6
|
+
test("Single digit numbers are Armstrong numbers") {
|
7
|
+
ArmstrongNumbers.isArmstrongNumber(5) should be (true)
|
8
|
+
}
|
9
|
+
|
10
|
+
test("There are no 2 digit Armstrong numbers") {
|
11
|
+
pending
|
12
|
+
ArmstrongNumbers.isArmstrongNumber(10) should be (false)
|
13
|
+
}
|
14
|
+
|
15
|
+
test("Three digit number that is an Armstrong number") {
|
16
|
+
pending
|
17
|
+
ArmstrongNumbers.isArmstrongNumber(153) should be (true)
|
18
|
+
}
|
19
|
+
|
20
|
+
test("Three digit number that is not an Armstrong number") {
|
21
|
+
pending
|
22
|
+
ArmstrongNumbers.isArmstrongNumber(100) should be (false)
|
23
|
+
}
|
24
|
+
|
25
|
+
test("Four digit number that is an Armstrong number") {
|
26
|
+
pending
|
27
|
+
ArmstrongNumbers.isArmstrongNumber(9474) should be (true)
|
28
|
+
}
|
29
|
+
|
30
|
+
test("Four digit number that is not an Armstrong number") {
|
31
|
+
pending
|
32
|
+
ArmstrongNumbers.isArmstrongNumber(9475) should be (false)
|
33
|
+
}
|
34
|
+
|
35
|
+
test("Seven digit number that is an Armstrong number") {
|
36
|
+
pending
|
37
|
+
ArmstrongNumbers.isArmstrongNumber(9926315) should be (true)
|
38
|
+
}
|
39
|
+
|
40
|
+
test("Seven digit number that is not an Armstrong number") {
|
41
|
+
pending
|
42
|
+
ArmstrongNumbers.isArmstrongNumber(9926314) should be (false)
|
43
|
+
}
|
44
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import java.io.File
|
2
|
+
|
3
|
+
import testgen.TestSuiteBuilder._
|
4
|
+
import testgen._
|
5
|
+
|
6
|
+
object ArmstrongNumbersTestGenerator {
|
7
|
+
def main(args: Array[String]): Unit = {
|
8
|
+
val file = new File("src/main/resources/armstrong-numbers.json")
|
9
|
+
|
10
|
+
def toString(expected: CanonicalDataParser.Expected): String = {
|
11
|
+
expected match {
|
12
|
+
case Right(b: Boolean) => b.toString
|
13
|
+
case _ => throw new IllegalStateException()
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
def fromLabeledTestFromInput(argNames: String*): ToTestCaseData =
|
18
|
+
withLabeledTest { sut =>
|
19
|
+
labeledTest =>
|
20
|
+
val args = sutArgsFromInput(labeledTest.result, argNames: _*)
|
21
|
+
val property = labeledTest.property
|
22
|
+
val sutCall =
|
23
|
+
s"""$sut.$property($args)"""
|
24
|
+
val expected = toString(labeledTest.expected)
|
25
|
+
TestCaseData(labeledTest.description, sutCall, expected)
|
26
|
+
}
|
27
|
+
|
28
|
+
val code = TestSuiteBuilder.build(file, fromLabeledTestFromInput("number"))
|
29
|
+
println(s"-------------")
|
30
|
+
println(code)
|
31
|
+
println(s"-------------")
|
32
|
+
}
|
33
|
+
}
|
data/tracks/scheme/config.json
CHANGED
@@ -128,6 +128,14 @@
|
|
128
128
|
"topics": null,
|
129
129
|
"unlocked_by": null,
|
130
130
|
"uuid": "3ecc2d1c-55e0-45c9-ba35-57d7d8cfd51e"
|
131
|
+
},
|
132
|
+
{
|
133
|
+
"core": false,
|
134
|
+
"difficulty": 1,
|
135
|
+
"slug": "atbash-cipher",
|
136
|
+
"topics": null,
|
137
|
+
"unlocked_by": null,
|
138
|
+
"uuid": "82169e85-3938-48da-ada9-7394adadc57a"
|
131
139
|
}
|
132
140
|
],
|
133
141
|
"foregone": [],
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Atbash Cipher
|
2
|
+
|
3
|
+
Create an implementation of the atbash cipher, an ancient encryption system created in the Middle East.
|
4
|
+
|
5
|
+
The Atbash cipher is a simple substitution cipher that relies on
|
6
|
+
transposing all the letters in the alphabet such that the resulting
|
7
|
+
alphabet is backwards. The first letter is replaced with the last
|
8
|
+
letter, the second with the second-last, and so on.
|
9
|
+
|
10
|
+
An Atbash cipher for the Latin alphabet would be as follows:
|
11
|
+
|
12
|
+
```text
|
13
|
+
Plain: abcdefghijklmnopqrstuvwxyz
|
14
|
+
Cipher: zyxwvutsrqponmlkjihgfedcba
|
15
|
+
```
|
16
|
+
|
17
|
+
It is a very weak cipher because it only has one possible key, and it is
|
18
|
+
a simple monoalphabetic substitution cipher. However, this may not have
|
19
|
+
been an issue in the cipher's time.
|
20
|
+
|
21
|
+
Ciphertext is written out in groups of fixed length, the traditional group size
|
22
|
+
being 5 letters, and punctuation is excluded. This is to make it harder to guess
|
23
|
+
things based on word boundaries.
|
24
|
+
|
25
|
+
## Examples
|
26
|
+
|
27
|
+
- Encoding `test` gives `gvhg`
|
28
|
+
- Decoding `gvhg` gives `test`
|
29
|
+
- Decoding `gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt` gives `thequickbrownfoxjumpsoverthelazydog`
|
30
|
+
|
31
|
+
## Source
|
32
|
+
|
33
|
+
Wikipedia [http://en.wikipedia.org/wiki/Atbash](http://en.wikipedia.org/wiki/Atbash)
|
34
|
+
|
35
|
+
## Submitting Incomplete Solutions
|
36
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
@@ -0,0 +1,67 @@
|
|
1
|
+
;; Load SRFI-64 lightweight testing specification
|
2
|
+
(use-modules (srfi srfi-64))
|
3
|
+
|
4
|
+
;; Suppress log file output. To write logs, comment out the following line:
|
5
|
+
(module-define! (resolve-module '(srfi srfi-64)) 'test-log-to-file #f)
|
6
|
+
|
7
|
+
;; Require module
|
8
|
+
(add-to-load-path (dirname (current-filename)))
|
9
|
+
(use-modules (atbash-cipher))
|
10
|
+
|
11
|
+
(test-begin "atbash-cipher")
|
12
|
+
|
13
|
+
;; Tests go here
|
14
|
+
|
15
|
+
(test-equal "'yes' encoded is 'bvh'."
|
16
|
+
"bvh"
|
17
|
+
(encode "yes"))
|
18
|
+
|
19
|
+
(test-equal "'no' encoded is 'ml'."
|
20
|
+
"ml"
|
21
|
+
(encode "no"))
|
22
|
+
|
23
|
+
(test-equal "Encoding always returns lower-case letters."
|
24
|
+
"lnt"
|
25
|
+
(encode "OMG"))
|
26
|
+
|
27
|
+
(test-equal "Encoding removes spaces from input."
|
28
|
+
"lnt"
|
29
|
+
(encode "O M G"))
|
30
|
+
|
31
|
+
(test-equal "Encoded output includes a space every five characters."
|
32
|
+
"nrmwy oldrm tob"
|
33
|
+
(encode "mindblowingly"))
|
34
|
+
|
35
|
+
(test-equal "Symbols are ignored, and numbers are passed-through unmodified"
|
36
|
+
"gvhgr mt123 gvhgr mt"
|
37
|
+
(encode "Testing,1 2 3, Testing."))
|
38
|
+
|
39
|
+
(test-equal "Deep thoughts can be encoded"
|
40
|
+
"gifgs rhurx grlm"
|
41
|
+
(encode "Truth is fiction."))
|
42
|
+
|
43
|
+
(test-equal "Every lowercase less has an encoding"
|
44
|
+
"gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt"
|
45
|
+
(encode "The quick brown fox jumps over the lazy dog."))
|
46
|
+
|
47
|
+
(test-equal "Unicode-range symbols are ignored"
|
48
|
+
"mlmzh xrrrt mlivw"
|
49
|
+
(encode "non ascii éignored"))
|
50
|
+
|
51
|
+
(test-equal "Exercism can be decoded"
|
52
|
+
"exercism"
|
53
|
+
(decode "vcvix rhn"))
|
54
|
+
|
55
|
+
(test-equal "Decodes a sentence"
|
56
|
+
"anobstacleisoftenasteppingstone"
|
57
|
+
(decode "zmlyh gzxov rhlug vmzhg vkkrm thglm v"))
|
58
|
+
|
59
|
+
(test-equal "Decoding ignores symbols and passes-through numbers just like encoding"
|
60
|
+
"testing123testing"
|
61
|
+
(decode "gvhgr mt123 gvhgr mt"))
|
62
|
+
|
63
|
+
(test-equal "Every lowercase letter can be decoded"
|
64
|
+
"thequickbrownfoxjumpsoverthelazydog"
|
65
|
+
(decode "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt"))
|
66
|
+
|
67
|
+
(test-end "atbash-cipher")
|
@@ -0,0 +1,40 @@
|
|
1
|
+
(define-module (atbash-cipher)
|
2
|
+
#:autoload (srfi srfi-26) (cut)
|
3
|
+
#:autoload (srfi srfi-1) (iota)
|
4
|
+
#:autoload (ice-9 regex) (regexp-substitute/global
|
5
|
+
list-matches)
|
6
|
+
#:export (encode decode))
|
7
|
+
|
8
|
+
;; "zip" a...z and z...a together to create an alist of mappings.
|
9
|
+
(define alphamap
|
10
|
+
(let* ((alpha (map integer->char (iota 26 (char->integer #\a)))))
|
11
|
+
(map cons alpha (reverse alpha))))
|
12
|
+
|
13
|
+
;; Look up the given character in the alphamap and return its complement.
|
14
|
+
(define (convert-char chr)
|
15
|
+
(or (assoc-ref alphamap chr) chr))
|
16
|
+
|
17
|
+
;; Encode the given "val" string using the Atbash cipher.
|
18
|
+
(define (encode val)
|
19
|
+
(format-atbash (string-map convert-char (prepare-input val))))
|
20
|
+
|
21
|
+
;; Decode the given Atbash cipher.
|
22
|
+
(define (decode val)
|
23
|
+
(string-map convert-char (prepare-input val)))
|
24
|
+
|
25
|
+
;; Filter any unprocessable characters out of the plain text.
|
26
|
+
;; Only lowercase a-z and 0-9 are allowed.
|
27
|
+
(define (prepare-input val)
|
28
|
+
(regexp-substitute/global #f "[^a-z0-9]" (string-downcase val) 'pre "" 'post))
|
29
|
+
|
30
|
+
;; Format atbash ciphertext for output.
|
31
|
+
;; Add a space every 5 characters
|
32
|
+
;; Currently generates a preceeding space, which must be trimmed :(
|
33
|
+
(define (format-atbash val)
|
34
|
+
(string-trim
|
35
|
+
(string-concatenate
|
36
|
+
(map (compose (cut string-append " " <>)
|
37
|
+
match:substring)
|
38
|
+
(list-matches "[a-z0-9]{1,5}" val)))))
|
39
|
+
|
40
|
+
|