diff --git a/config.json b/config.json index c134eb1..3c36054 100644 --- a/config.json +++ b/config.json @@ -343,6 +343,14 @@ "practices": [], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "protein-translation", + "name": "Protein Translation", + "uuid": "b61ac6a8-b40d-48ea-8a72-89608506c256", + "practices": [], + "prerequisites": [], + "difficulty": 1 } ] }, diff --git a/exercises/practice/protein-translation/.docs/instructions.md b/exercises/practice/protein-translation/.docs/instructions.md new file mode 100644 index 0000000..7dc34d2 --- /dev/null +++ b/exercises/practice/protein-translation/.docs/instructions.md @@ -0,0 +1,45 @@ +# Instructions + +Translate RNA sequences into proteins. + +RNA can be broken into three nucleotide sequences called codons, and then translated to a polypeptide like so: + +RNA: `"AUGUUUUCU"` => translates to + +Codons: `"AUG", "UUU", "UCU"` +=> which become a polypeptide with the following sequence => + +Protein: `"Methionine", "Phenylalanine", "Serine"` + +There are 64 codons which in turn correspond to 20 amino acids; however, all of the codon sequences and resulting amino acids are not important in this exercise. +If it works for one codon, the program should work for all of them. +However, feel free to expand the list in the test suite to include them all. + +There are also three terminating codons (also known as 'STOP' codons); if any of these codons are encountered (by the ribosome), all translation ends and the protein is terminated. + +All subsequent codons after are ignored, like this: + +RNA: `"AUGUUUUCUUAAAUG"` => + +Codons: `"AUG", "UUU", "UCU", "UAA", "AUG"` => + +Protein: `"Methionine", "Phenylalanine", "Serine"` + +Note the stop codon `"UAA"` terminates the translation and the final methionine is not translated into the protein sequence. + +Below are the codons and resulting Amino Acids needed for the exercise. + +| Codon | Protein | +| :----------------- | :------------ | +| AUG | Methionine | +| UUU, UUC | Phenylalanine | +| UUA, UUG | Leucine | +| UCU, UCC, UCA, UCG | Serine | +| UAU, UAC | Tyrosine | +| UGU, UGC | Cysteine | +| UGG | Tryptophan | +| UAA, UAG, UGA | STOP | + +Learn more about [protein translation on Wikipedia][protein-translation]. + +[protein-translation]: https://en.wikipedia.org/wiki/Translation_(biology) diff --git a/exercises/practice/protein-translation/.meta/config.json b/exercises/practice/protein-translation/.meta/config.json new file mode 100644 index 0000000..3c4ea45 --- /dev/null +++ b/exercises/practice/protein-translation/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "kahgoh" + ], + "files": { + "solution": [ + "src/protein-translation.lfe" + ], + "test": [ + "test/protein-translation-tests.lfe" + ], + "example": [ + ".meta/example.lfe" + ] + }, + "blurb": "Translate RNA sequences into proteins.", + "source": "Tyler Long" +} diff --git a/exercises/practice/protein-translation/.meta/example.lfe b/exercises/practice/protein-translation/.meta/example.lfe new file mode 100644 index 0000000..cead747 --- /dev/null +++ b/exercises/practice/protein-translation/.meta/example.lfe @@ -0,0 +1,41 @@ +(defmodule protein-translation + (export (proteins 1))) + +(defun proteins + ((strand) (when (!= (rem (length strand) 3) 0)) (tuple 'error "Invalid codon") ) + ((strand) (translate strand '())) +) + +(defun translate + (("" acc) (tuple 'ok acc)) + ((strand acc) + (case (codon (string:slice strand 0 3)) + ((tuple 'ok codon) (translate (string:slice strand 3 (length strand)) (++ acc (list codon)))) + ((tuple 'stop) (tuple 'ok acc)) + (t t) + ) + ) +) + +(defun codon (seq) + (case seq + ("AUG" (tuple 'ok 'Methionine)) + ("UUU" (tuple 'ok 'Phenylalanine)) + ("UUC" (tuple 'ok 'Phenylalanine)) + ("UUA" (tuple 'ok 'Leucine)) + ("UUG" (tuple 'ok 'Leucine)) + ("UCU" (tuple 'ok 'Serine)) + ("UCC" (tuple 'ok 'Serine)) + ("UCA" (tuple 'ok 'Serine)) + ("UCG" (tuple 'ok 'Serine)) + ("UAU" (tuple 'ok 'Tyrosine)) + ("UAC" (tuple 'ok 'Tyrosine)) + ("UGU" (tuple 'ok 'Cysteine)) + ("UGC" (tuple 'ok 'Cysteine)) + ("UGG" (tuple 'ok 'Tryptophan)) + ("UAA" (tuple 'stop)) + ("UAG" (tuple 'stop)) + ("UGA" (tuple 'stop)) + (t (tuple 'error "Invalid codon")) + ) +) diff --git a/exercises/practice/protein-translation/.meta/tests.toml b/exercises/practice/protein-translation/.meta/tests.toml new file mode 100644 index 0000000..5fb1890 --- /dev/null +++ b/exercises/practice/protein-translation/.meta/tests.toml @@ -0,0 +1,100 @@ +# 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. + +[2c44f7bf-ba20-43f7-a3bf-f2219c0c3f98] +description = "Empty RNA sequence results in no proteins" + +[96d3d44f-34a2-4db4-84cd-fff523e069be] +description = "Methionine RNA sequence" + +[1b4c56d8-d69f-44eb-be0e-7b17546143d9] +description = "Phenylalanine RNA sequence 1" + +[81b53646-bd57-4732-b2cb-6b1880e36d11] +description = "Phenylalanine RNA sequence 2" + +[42f69d4f-19d2-4d2c-a8b0-f0ae9ee1b6b4] +description = "Leucine RNA sequence 1" + +[ac5edadd-08ed-40a3-b2b9-d82bb50424c4] +description = "Leucine RNA sequence 2" + +[8bc36e22-f984-44c3-9f6b-ee5d4e73f120] +description = "Serine RNA sequence 1" + +[5c3fa5da-4268-44e5-9f4b-f016ccf90131] +description = "Serine RNA sequence 2" + +[00579891-b594-42b4-96dc-7ff8bf519606] +description = "Serine RNA sequence 3" + +[08c61c3b-fa34-4950-8c4a-133945570ef6] +description = "Serine RNA sequence 4" + +[54e1e7d8-63c0-456d-91d2-062c72f8eef5] +description = "Tyrosine RNA sequence 1" + +[47bcfba2-9d72-46ad-bbce-22f7666b7eb1] +description = "Tyrosine RNA sequence 2" + +[3a691829-fe72-43a7-8c8e-1bd083163f72] +description = "Cysteine RNA sequence 1" + +[1b6f8a26-ca2f-43b8-8262-3ee446021767] +description = "Cysteine RNA sequence 2" + +[1e91c1eb-02c0-48a0-9e35-168ad0cb5f39] +description = "Tryptophan RNA sequence" + +[e547af0b-aeab-49c7-9f13-801773a73557] +description = "STOP codon RNA sequence 1" + +[67640947-ff02-4f23-a2ef-816f8a2ba72e] +description = "STOP codon RNA sequence 2" + +[9c2ad527-ebc9-4ace-808b-2b6447cb54cb] +description = "STOP codon RNA sequence 3" + +[f4d9d8ee-00a8-47bf-a1e3-1641d4428e54] +description = "Sequence of two protein codons translates into proteins" + +[dd22eef3-b4f1-4ad6-bb0b-27093c090a9d] +description = "Sequence of two different protein codons translates into proteins" + +[d0f295df-fb70-425c-946c-ec2ec185388e] +description = "Translate RNA strand into correct protein list" + +[e30e8505-97ec-4e5f-a73e-5726a1faa1f4] +description = "Translation stops if STOP codon at beginning of sequence" + +[5358a20b-6f4c-4893-bce4-f929001710f3] +description = "Translation stops if STOP codon at end of two-codon sequence" + +[ba16703a-1a55-482f-bb07-b21eef5093a3] +description = "Translation stops if STOP codon at end of three-codon sequence" + +[4089bb5a-d5b4-4e71-b79e-b8d1f14a2911] +description = "Translation stops if STOP codon in middle of three-codon sequence" + +[2c2a2a60-401f-4a80-b977-e0715b23b93d] +description = "Translation stops if STOP codon in middle of six-codon sequence" + +[1e75ea2a-f907-4994-ae5c-118632a1cb0f] +description = "Non-existing codon can't translate" + +[9eac93f3-627a-4c90-8653-6d0a0595bc6f] +description = "Unknown amino acids, not part of a codon, can't translate" + +[9d73899f-e68e-4291-b1e2-7bf87c00f024] +description = "Incomplete RNA sequence can't translate" + +[43945cf7-9968-402d-ab9f-b8a28750b050] +description = "Incomplete RNA sequence can translate if valid until a STOP codon" diff --git a/exercises/practice/protein-translation/Makefile b/exercises/practice/protein-translation/Makefile new file mode 100644 index 0000000..fbb5a7d --- /dev/null +++ b/exercises/practice/protein-translation/Makefile @@ -0,0 +1,21 @@ +ERL := $(shell which erl) +REBAR3 := $(shell which rebar3) + +null := +space := $(null) # +comma := , + +ifeq ($(ERL),) + $(error Can't find Erlang executable 'erl') +else ifeq ($(REBAR3),) + $(error Can't find rebar3) +endif + +compile: ; $(REBAR3) compile + +clean: ; $(REBAR3) clean + +.PHONY: test +test: + $(REBAR3) eunit \ + -m $(subst $(space),$(comma),$(basename $(notdir $(wildcard test/*.lfe)))) diff --git a/exercises/practice/protein-translation/rebar.config b/exercises/practice/protein-translation/rebar.config new file mode 100644 index 0000000..d53487a --- /dev/null +++ b/exercises/practice/protein-translation/rebar.config @@ -0,0 +1,11 @@ +{plugins, [{rebar3_lfe, "0.4.3"}]}. + +{provider_hooks, [{post, [{compile, {lfe, compile}}]}]}. + +{deps, [{lfe, "2.1.1"}]}. + +{profiles, + [{test, + [{eunit_compile_opts, [{src_dirs, ["src", "test"]}]}, + {deps, + [{ltest, "0.13.3"}]}]}]}. diff --git a/exercises/practice/protein-translation/rebar.lock b/exercises/practice/protein-translation/rebar.lock new file mode 100644 index 0000000..d5a6b3b --- /dev/null +++ b/exercises/practice/protein-translation/rebar.lock @@ -0,0 +1,8 @@ +{"1.2.0", +[{<<"lfe">>,{pkg,<<"lfe">>,<<"2.1.1">>},0}]}. +[ +{pkg_hash,[ + {<<"lfe">>, <<"4A888B26172D198DC7A5AFEB897E8248AF7D56E1638D9C8249AAF933AE811B96">>}]}, +{pkg_hash_ext,[ + {<<"lfe">>, <<"C484D3B655D40DED58BC41B17B22F173711C681BF36063A234A9BAA9506947E1">>}]} +]. diff --git a/exercises/practice/protein-translation/src/protein-translation.app.src b/exercises/practice/protein-translation/src/protein-translation.app.src new file mode 100644 index 0000000..c48e9c5 --- /dev/null +++ b/exercises/practice/protein-translation/src/protein-translation.app.src @@ -0,0 +1,11 @@ +%% -*- erlang -*- +{application, 'protein-translation', + [{description, "Translate RNA sequences into proteins."}, + {vsn, "0.0.1"}, + {modules, + ['raindrops']}, + {registered, []}, + {applications, + [kernel, stdlib]}, + {included_applications, []}, + {env, []}]}. diff --git a/exercises/practice/protein-translation/src/protein-translation.lfe b/exercises/practice/protein-translation/src/protein-translation.lfe new file mode 100644 index 0000000..9209449 --- /dev/null +++ b/exercises/practice/protein-translation/src/protein-translation.lfe @@ -0,0 +1,4 @@ +(defmodule protein-translation + (export (proteins 1))) + +; Please implement the 'proteins' function \ No newline at end of file diff --git a/exercises/practice/protein-translation/test/protein-translation-tests.lfe b/exercises/practice/protein-translation/test/protein-translation-tests.lfe new file mode 100644 index 0000000..ced4c6c --- /dev/null +++ b/exercises/practice/protein-translation/test/protein-translation-tests.lfe @@ -0,0 +1,89 @@ +(defmodule protein-translation-tests + (behaviour ltest-unit) + (export all)) + +(include-lib "ltest/include/ltest-macros.lfe") + +(deftest empty-rna-sequence-no-protein + (is-equal (tuple 'ok '()) (protein-translation:proteins ""))) + +(deftest methione-rna-sequence + (is-equal (tuple 'ok (list 'Methionine)) (protein-translation:proteins "AUG"))) + +(deftest phenylalanine-rna-sequence-1 + (is-equal (tuple 'ok (list 'Phenylalanine)) (protein-translation:proteins "UUU"))) + +(deftest phenylalanine-rna-sequence-2 + (is-equal (tuple 'ok (list 'Phenylalanine)) (protein-translation:proteins "UUC"))) + +(deftest leucine-rna-sequence-1 + (is-equal (tuple 'ok (list 'Leucine)) (protein-translation:proteins "UUA"))) + +(deftest serine-rna-sequence-1 + (is-equal (tuple 'ok (list 'Serine)) (protein-translation:proteins "UCU"))) + +(deftest serine-rna-sequence-2 + (is-equal (tuple 'ok (list 'Serine)) (protein-translation:proteins "UCC"))) + +(deftest serine-rna-sequence-3 + (is-equal (tuple 'ok (list 'Serine)) (protein-translation:proteins "UCA"))) + +(deftest serine-rna-sequence-4 + (is-equal (tuple 'ok (list 'Serine)) (protein-translation:proteins "UCG"))) + +(deftest tyrosine-rna-sequence-1 + (is-equal (tuple 'ok (list 'Tyrosine)) (protein-translation:proteins "UAU"))) + +(deftest tyrosine-rna-sequence-2 + (is-equal (tuple 'ok (list 'Tyrosine)) (protein-translation:proteins "UAC"))) + +(deftest cysteine-rna-sequence-1 + (is-equal (tuple 'ok (list 'Cysteine)) (protein-translation:proteins "UGU"))) + +(deftest cysteine-rna-sequence-2 + (is-equal (tuple 'ok (list 'Cysteine)) (protein-translation:proteins "UGC"))) + +(deftest tryptophan-rna-sequence + (is-equal (tuple 'ok (list 'Tryptophan)) (protein-translation:proteins "UGG"))) + +(deftest stop-codon-rna-sequence-1 + (is-equal (tuple 'ok '()) (protein-translation:proteins "UAA"))) + +(deftest stop-codon-rna-sequence-2 + (is-equal (tuple 'ok '()) (protein-translation:proteins "UAG"))) + +(deftest stop-codon-rna-sequence-3 + (is-equal (tuple 'ok '()) (protein-translation:proteins "UGA"))) + +(deftest sequence-of-two-proteins-codons-translates-into-proteins + (is-equal (tuple 'ok (list 'Phenylalanine 'Phenylalanine)) (protein-translation:proteins "UUUUUU"))) + +(deftest sequence-of-two-different-protein-codons-translates-into-proteins + (is-equal (tuple 'ok (list 'Leucine 'Leucine)) (protein-translation:proteins "UUAUUG"))) + +(deftest translate-rna-strand-into-correct-protein-list + (is-equal (tuple 'ok (list 'Methionine 'Phenylalanine 'Tryptophan)) (protein-translation:proteins "AUGUUUUGG"))) + +(deftest translation-stops-if-stop-codon-at-beginning-of-sequence + (is-equal (tuple 'ok '()) (protein-translation:proteins "UAGUGG"))) + +(deftest translation-stops-if-stop-codon-at-end-of-two-codon-sequence + (is-equal (tuple 'ok (list 'Tryptophan)) (protein-translation:proteins "UGGUAG"))) + +(deftest translation-stops-if-stop-codon-at-end-of-three-codon-sequence + (is-equal (tuple 'ok (list 'Methionine 'Phenylalanine)) (protein-translation:proteins "AUGUUUUAA"))) + +(deftest translation-stops-if-stop-codon-in-middle-of-three-codon-sequence + (is-equal (tuple 'ok (list 'Tryptophan)) (protein-translation:proteins "UGGUAGUGG"))) + +(deftest translation-stops-if-stop-codon-in-middle-of-six-codon-sequence + (is-equal (tuple 'ok (list 'Tryptophan 'Cysteine 'Tyrosine)) (protein-translation:proteins "UGGUGUUAUUAAUGGUUU"))) + +(deftest non-existing-condon-cant-translate + (is-equal (tuple 'error "Invalid codon") (protein-translation:proteins "AAA"))) + +(deftest unknown-amino-acides-not-part-of-a-codon-cant-translate + (is-equal (tuple 'error "Invalid codon") (protein-translation:proteins "XYZ"))) + +(deftest incomplete-rna-sequence-cant-translate + (is-equal (tuple 'error "Invalid codon") (protein-translation:proteins "AUGU")))