From 38d620b786c7c972a8df5972ec59038e95580a77 Mon Sep 17 00:00:00 2001 From: Glenn Jackman Date: Fri, 10 Apr 2026 07:17:57 -0400 Subject: [PATCH] Add protein-translation --- config.json | 8 + .../practice/protein-translation/.busted | 5 + .../protein-translation/.docs/instructions.md | 38 +++++ .../protein-translation/.meta/config.json | 18 +++ .../protein-translation/.meta/example.moon | 30 ++++ .../.meta/spec_generator.moon | 21 +++ .../protein-translation/.meta/tests.toml | 105 ++++++++++++ .../protein_translation.moon | 4 + .../protein_translation_spec.moon | 150 ++++++++++++++++++ 9 files changed, 379 insertions(+) create mode 100644 exercises/practice/protein-translation/.busted create mode 100644 exercises/practice/protein-translation/.docs/instructions.md create mode 100644 exercises/practice/protein-translation/.meta/config.json create mode 100644 exercises/practice/protein-translation/.meta/example.moon create mode 100644 exercises/practice/protein-translation/.meta/spec_generator.moon create mode 100644 exercises/practice/protein-translation/.meta/tests.toml create mode 100644 exercises/practice/protein-translation/protein_translation.moon create mode 100644 exercises/practice/protein-translation/protein_translation_spec.moon diff --git a/config.json b/config.json index 3af7674..354bed6 100644 --- a/config.json +++ b/config.json @@ -338,6 +338,14 @@ "prerequisites": [], "difficulty": 3 }, + { + "slug": "protein-translation", + "name": "Protein Translation", + "uuid": "951babbe-0acb-4ce8-a02a-6b2f2b8db216", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "proverb", "name": "Proverb", diff --git a/exercises/practice/protein-translation/.busted b/exercises/practice/protein-translation/.busted new file mode 100644 index 0000000..86b84e7 --- /dev/null +++ b/exercises/practice/protein-translation/.busted @@ -0,0 +1,5 @@ +return { + default = { + ROOT = { '.' } + } +} diff --git a/exercises/practice/protein-translation/.docs/instructions.md b/exercises/practice/protein-translation/.docs/instructions.md new file mode 100644 index 0000000..35c953b --- /dev/null +++ b/exercises/practice/protein-translation/.docs/instructions.md @@ -0,0 +1,38 @@ +# Instructions + +Your job is to translate RNA sequences into proteins. + +RNA strands are made up of three-nucleotide sequences called **codons**. +Each codon translates to an **amino acid**. +When joined together, those amino acids make a protein. + +In the real world, there are 64 codons, which in turn correspond to 20 amino acids. +However, for this exercise, you’ll only use a few of the possible 64. +They are listed below: + +| Codon | Amino Acid | +| ------------------ | ------------- | +| 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 | + +For example, the RNA string “AUGUUUUCU” has three codons: “AUG”, “UUU” and “UCU”. +These map to Methionine, Phenylalanine, and Serine. + +## “STOP” Codons + +You’ll note from the table above that there are three **“STOP” codons**. +If you encounter any of these codons, ignore the rest of the sequence — the protein is complete. + +For example, “AUGUUUUCUUAAAUG” contains a STOP codon (“UAA”). +Once we reach that point, we stop processing. +We therefore only consider the part before it (i.e. “AUGUUUUCU”), not any further codons after it (i.e. “AUG”). + +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..6604604 --- /dev/null +++ b/exercises/practice/protein-translation/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "glennj" + ], + "files": { + "solution": [ + "protein_translation.moon" + ], + "test": [ + "protein_translation_spec.moon" + ], + "example": [ + ".meta/example.moon" + ] + }, + "blurb": "Translate RNA sequences into proteins.", + "source": "Tyler Long" +} diff --git a/exercises/practice/protein-translation/.meta/example.moon b/exercises/practice/protein-translation/.meta/example.moon new file mode 100644 index 0000000..8eea16e --- /dev/null +++ b/exercises/practice/protein-translation/.meta/example.moon @@ -0,0 +1,30 @@ +codon_map = + AUG: 'Methionine' + UUC: 'Phenylalanine' + UUU: 'Phenylalanine' + UUA: 'Leucine' + UUG: 'Leucine' + UCU: 'Serine' + UCC: 'Serine' + UCA: 'Serine' + UCG: 'Serine' + UAU: 'Tyrosine' + UAC: 'Tyrosine' + UGU: 'Cysteine' + UGC: 'Cysteine' + UGG: 'Tryptophan' + UAA: 'STOP' + UAG: 'STOP' + UGA: 'STOP' + +translate = (strand) -> + proteins = {} + while #strand > 0 + codon, strand = strand\match '(...)(.*)' + switch codon_map[codon] + when nil then error 'Invalid codon' + when 'STOP' then break + else table.insert proteins, codon_map[codon] + proteins + +{ proteins: translate } diff --git a/exercises/practice/protein-translation/.meta/spec_generator.moon b/exercises/practice/protein-translation/.meta/spec_generator.moon new file mode 100644 index 0000000..11de3fe --- /dev/null +++ b/exercises/practice/protein-translation/.meta/spec_generator.moon @@ -0,0 +1,21 @@ +string_list = (list) -> + "{#{table.concat [quote word for word in *list], ', '}}" + +{ + module_imports: {'proteins'}, + + generate_test: (case, level) -> + local lines + if case.expected.error + lines = { + "f = -> proteins #{quote case.input.strand}", + "assert.has.errors f, #{quote case.expected.error}" + } + else + lines = { + "result = proteins #{quote case.input.strand}", + "expected = #{string_list case.expected}", + "assert.are.same expected, result" + } + table.concat [indent line, level for line in *lines], '\n' +} diff --git a/exercises/practice/protein-translation/.meta/tests.toml b/exercises/practice/protein-translation/.meta/tests.toml new file mode 100644 index 0000000..de680e3 --- /dev/null +++ b/exercises/practice/protein-translation/.meta/tests.toml @@ -0,0 +1,105 @@ +# 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" + +[f6f92714-769f-4187-9524-e353e8a41a80] +description = "Sequence of two non-STOP codons does not translate to a STOP codon" + +[1e75ea2a-f907-4994-ae5c-118632a1cb0f] +description = "Non-existing codon can't translate" +include = false + +[9eac93f3-627a-4c90-8653-6d0a0595bc6f] +description = "Unknown amino acids, not part of a codon, can't translate" +reimplements = "1e75ea2a-f907-4994-ae5c-118632a1cb0f" + +[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/protein_translation.moon b/exercises/practice/protein-translation/protein_translation.moon new file mode 100644 index 0000000..455ca60 --- /dev/null +++ b/exercises/practice/protein-translation/protein_translation.moon @@ -0,0 +1,4 @@ +{ + proteins: (strand) -> + error 'Implement me' +} diff --git a/exercises/practice/protein-translation/protein_translation_spec.moon b/exercises/practice/protein-translation/protein_translation_spec.moon new file mode 100644 index 0000000..b0363fb --- /dev/null +++ b/exercises/practice/protein-translation/protein_translation_spec.moon @@ -0,0 +1,150 @@ +import proteins from require 'protein_translation' + +describe 'protein-translation', -> + it 'Empty RNA sequence results in no proteins', -> + result = proteins '' + expected = {} + assert.are.same expected, result + + pending 'Methionine RNA sequence', -> + result = proteins 'AUG' + expected = {'Methionine'} + assert.are.same expected, result + + pending 'Phenylalanine RNA sequence 1', -> + result = proteins 'UUU' + expected = {'Phenylalanine'} + assert.are.same expected, result + + pending 'Phenylalanine RNA sequence 2', -> + result = proteins 'UUC' + expected = {'Phenylalanine'} + assert.are.same expected, result + + pending 'Leucine RNA sequence 1', -> + result = proteins 'UUA' + expected = {'Leucine'} + assert.are.same expected, result + + pending 'Leucine RNA sequence 2', -> + result = proteins 'UUG' + expected = {'Leucine'} + assert.are.same expected, result + + pending 'Serine RNA sequence 1', -> + result = proteins 'UCU' + expected = {'Serine'} + assert.are.same expected, result + + pending 'Serine RNA sequence 2', -> + result = proteins 'UCC' + expected = {'Serine'} + assert.are.same expected, result + + pending 'Serine RNA sequence 3', -> + result = proteins 'UCA' + expected = {'Serine'} + assert.are.same expected, result + + pending 'Serine RNA sequence 4', -> + result = proteins 'UCG' + expected = {'Serine'} + assert.are.same expected, result + + pending 'Tyrosine RNA sequence 1', -> + result = proteins 'UAU' + expected = {'Tyrosine'} + assert.are.same expected, result + + pending 'Tyrosine RNA sequence 2', -> + result = proteins 'UAC' + expected = {'Tyrosine'} + assert.are.same expected, result + + pending 'Cysteine RNA sequence 1', -> + result = proteins 'UGU' + expected = {'Cysteine'} + assert.are.same expected, result + + pending 'Cysteine RNA sequence 2', -> + result = proteins 'UGC' + expected = {'Cysteine'} + assert.are.same expected, result + + pending 'Tryptophan RNA sequence', -> + result = proteins 'UGG' + expected = {'Tryptophan'} + assert.are.same expected, result + + pending 'STOP codon RNA sequence 1', -> + result = proteins 'UAA' + expected = {} + assert.are.same expected, result + + pending 'STOP codon RNA sequence 2', -> + result = proteins 'UAG' + expected = {} + assert.are.same expected, result + + pending 'STOP codon RNA sequence 3', -> + result = proteins 'UGA' + expected = {} + assert.are.same expected, result + + pending 'Sequence of two protein codons translates into proteins', -> + result = proteins 'UUUUUU' + expected = {'Phenylalanine', 'Phenylalanine'} + assert.are.same expected, result + + pending 'Sequence of two different protein codons translates into proteins', -> + result = proteins 'UUAUUG' + expected = {'Leucine', 'Leucine'} + assert.are.same expected, result + + pending 'Translate RNA strand into correct protein list', -> + result = proteins 'AUGUUUUGG' + expected = {'Methionine', 'Phenylalanine', 'Tryptophan'} + assert.are.same expected, result + + pending 'Translation stops if STOP codon at beginning of sequence', -> + result = proteins 'UAGUGG' + expected = {} + assert.are.same expected, result + + pending 'Translation stops if STOP codon at end of two-codon sequence', -> + result = proteins 'UGGUAG' + expected = {'Tryptophan'} + assert.are.same expected, result + + pending 'Translation stops if STOP codon at end of three-codon sequence', -> + result = proteins 'AUGUUUUAA' + expected = {'Methionine', 'Phenylalanine'} + assert.are.same expected, result + + pending 'Translation stops if STOP codon in middle of three-codon sequence', -> + result = proteins 'UGGUAGUGG' + expected = {'Tryptophan'} + assert.are.same expected, result + + pending 'Translation stops if STOP codon in middle of six-codon sequence', -> + result = proteins 'UGGUGUUAUUAAUGGUUU' + expected = {'Tryptophan', 'Cysteine', 'Tyrosine'} + assert.are.same expected, result + + pending 'Sequence of two non-STOP codons does not translate to a STOP codon', -> + result = proteins 'AUGAUG' + expected = {'Methionine', 'Methionine'} + assert.are.same expected, result + + pending "Unknown amino acids, not part of a codon, can't translate", -> + f = -> proteins 'XYZ' + assert.has.errors f, 'Invalid codon' + + pending "Incomplete RNA sequence can't translate", -> + f = -> proteins 'AUGU' + assert.has.errors f, 'Invalid codon' + + pending 'Incomplete RNA sequence can translate if valid until a STOP codon', -> + result = proteins 'UUCUUCUAAUGGU' + expected = {'Phenylalanine', 'Phenylalanine'} + assert.are.same expected, result