From 1d31f5f404f1921f2a9e10465549b9ec18b07d36 Mon Sep 17 00:00:00 2001 From: Julio Biason Date: Mon, 8 May 2023 15:42:08 -0300 Subject: [PATCH] Hamming comparison --- groovy/hamming/.exercism/config.json | 25 +++++ groovy/hamming/.exercism/metadata.json | 1 + groovy/hamming/HELP.md | 48 +++++++++ groovy/hamming/README.md | 47 ++++++++ groovy/hamming/build.gradle | 18 ++++ groovy/hamming/src/main/groovy/Hamming.groovy | 16 +++ .../src/test/groovy/HammingSpec.groovy | 101 ++++++++++++++++++ 7 files changed, 256 insertions(+) create mode 100644 groovy/hamming/.exercism/config.json create mode 100644 groovy/hamming/.exercism/metadata.json create mode 100644 groovy/hamming/HELP.md create mode 100644 groovy/hamming/README.md create mode 100644 groovy/hamming/build.gradle create mode 100644 groovy/hamming/src/main/groovy/Hamming.groovy create mode 100644 groovy/hamming/src/test/groovy/HammingSpec.groovy diff --git a/groovy/hamming/.exercism/config.json b/groovy/hamming/.exercism/config.json new file mode 100644 index 0000000..73e6f04 --- /dev/null +++ b/groovy/hamming/.exercism/config.json @@ -0,0 +1,25 @@ +{ + "authors": [], + "contributors": [ + "alexanderific", + "amscotti", + "Dispader", + "ikhadykin", + "kytrinyx", + "sjwarner-bp" + ], + "files": { + "solution": [ + "src/main/groovy/Hamming.groovy" + ], + "test": [ + "src/test/groovy/HammingSpec.groovy" + ], + "example": [ + ".meta/src/reference/groovy/Hamming.groovy" + ] + }, + "blurb": "Calculate the Hamming difference between two DNA strands.", + "source": "The Calculating Point Mutations problem at Rosalind", + "source_url": "https://rosalind.info/problems/hamm/" +} diff --git a/groovy/hamming/.exercism/metadata.json b/groovy/hamming/.exercism/metadata.json new file mode 100644 index 0000000..ee4f091 --- /dev/null +++ b/groovy/hamming/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"groovy","exercise":"hamming","id":"4c068a639a254bbba7c9136ad8c97948","url":"https://exercism.org/tracks/groovy/exercises/hamming","handle":"JBiason","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/groovy/hamming/HELP.md b/groovy/hamming/HELP.md new file mode 100644 index 0000000..f60e5b1 --- /dev/null +++ b/groovy/hamming/HELP.md @@ -0,0 +1,48 @@ +# Help + +## Running the tests + +On MacOS/Linux, please run: + +```sh +$ chmod +x gradlew +``` + +Execute the tests with: + +```sh +$ ./gradlew test +``` + +> Use `gradlew.bat` if you're on Windows + +## Skipped tests + +After the first test(s) pass, continue by commenting out or removing the `@Ignore` annotations prepending other tests. + +## Submitting your solution + +You can submit your solution using the `exercism submit src/main/groovy/Hamming.groovy` 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 [Groovy track's documentation](https://exercism.org/docs/tracks/groovy) +- [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. + +To get help if you're having trouble, you can use one of the following resources: + +- The [Groovy Language Documentation](http://docs.groovy-lang.org/docs/latest/html/documentation/) +- The [Groovy Community](http://www.groovy-lang.org/community.html) entry of the Groovy Language Documentation +- [/r/groovy](https://www.reddit.com/r/groovy) is the Groovy subreddit. +- [StackOverflow](http://stackoverflow.com/questions/tagged/groovy) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. \ No newline at end of file diff --git a/groovy/hamming/README.md b/groovy/hamming/README.md new file mode 100644 index 0000000..bfbbb3a --- /dev/null +++ b/groovy/hamming/README.md @@ -0,0 +1,47 @@ +# Hamming + +Welcome to Hamming on Exercism's Groovy Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +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: + + GAGCCTACTAACGGGAT + CATCGTAATGACGGCCT + ^ ^ ^ ^ ^ ^^ + +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. + +## Source + +### Contributed to by + +- @alexanderific +- @amscotti +- @Dispader +- @ikhadykin +- @kytrinyx +- @sjwarner-bp + +### Based on + +The Calculating Point Mutations problem at Rosalind - https://rosalind.info/problems/hamm/ \ No newline at end of file diff --git a/groovy/hamming/build.gradle b/groovy/hamming/build.gradle new file mode 100644 index 0000000..e16cd99 --- /dev/null +++ b/groovy/hamming/build.gradle @@ -0,0 +1,18 @@ +apply plugin: "groovy" + +repositories { + mavenCentral() +} + +dependencies { + testImplementation "org.spockframework:spock-core:2.0-M2-groovy-3.0" + implementation "org.codehaus.groovy:groovy-all:3.0.2" +} + +test { + useJUnitPlatform() + testLogging { + exceptionFormat = 'full' + events = ["passed", "failed", "skipped"] + } +} \ No newline at end of file diff --git a/groovy/hamming/src/main/groovy/Hamming.groovy b/groovy/hamming/src/main/groovy/Hamming.groovy new file mode 100644 index 0000000..7efac66 --- /dev/null +++ b/groovy/hamming/src/main/groovy/Hamming.groovy @@ -0,0 +1,16 @@ +class Hamming { + + def distance(strand1, strand2) { + if (strand1.empty && strand2.empty) { + 0 + } else if (strand1.size() != strand2.size()) { + throw new ArithmeticException() + } else { + [strand1.chars, strand2.chars] + .transpose() + .collect { record -> record[0] == record[1]? 0: 1 } + .sum() + } + } + +} diff --git a/groovy/hamming/src/test/groovy/HammingSpec.groovy b/groovy/hamming/src/test/groovy/HammingSpec.groovy new file mode 100644 index 0000000..a70ae68 --- /dev/null +++ b/groovy/hamming/src/test/groovy/HammingSpec.groovy @@ -0,0 +1,101 @@ +import spock.lang.* + +class HammingSpec extends Specification { + + @Shared + def hamming = new Hamming() + + def "Empty strands"() { + expect: + hamming.distance(strand1, strand2) == expected + + where: + strand1 | strand2 || expected + '' | '' || 0 + } + + def "Single letter identical strands"() { + expect: + hamming.distance(strand1, strand2) == expected + + where: + strand1 | strand2 || expected + 'A' | 'A' || 0 + } + + def "Single letter different strands"() { + expect: + hamming.distance(strand1, strand2) == expected + + where: + strand1 | strand2 || expected + 'G' | 'T' || 1 + } + + def "Long identical strands"() { + expect: + hamming.distance(strand1, strand2) == expected + + where: + strand1 | strand2 || expected + 'GGACTGAAATCTG' | 'GGACTGAAATCTG' || 0 + } + + def "Long different strands"() { + expect: + hamming.distance(strand1, strand2) == expected + + where: + strand1 | strand2 || expected + 'GGACGGATTCTG' | 'AGGACGGATTCT' || 9 + } + + def "Disallow first strand longer"() { + when: + hamming.distance(strand1, strand2) + + then: + thrown(ArithmeticException) + + where: + strand1 | strand2 + 'AATG' | 'AAA' + } + + def "Disallow second strand longer"() { + when: + hamming.distance(strand1, strand2) + + then: + thrown(ArithmeticException) + + where: + strand1 | strand2 + 'ATA' | 'AGTG' + } + + def "Disallow left empty strand"() { + when: + hamming.distance(strand1, strand2) + + then: + thrown(ArithmeticException) + + where: + strand1 | strand2 + '' | 'G' + } + + def "Disallow right empty strand"() { + when: + hamming.distance(strand1, strand2) + + then: + thrown(ArithmeticException) + + where: + strand1 | strand2 + 'G' | '' + } + +}