Every problem
All 15 problems from Rosalind — Bioinformatics Armory. Press Run on any block to execute it in your browser. Every problem is on this page, so it is large and takes a moment to settle — the sections are lighter.
INI — Introduction to the Bioinformatics Armory
solvedbrowser + CLI Problem statement Open in the workbench Download .bl
# Rosalind: INI — Introduction to the Bioinformatics Armory
# https://rosalind.info/problems/ini/
#
# Given: A DNA string s of length at most 1000 bp.
# Return: Four integers separated by spaces counting A, C, G, T occurrences.
let s = dna"AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC"
let counts = base_counts(s)
let result = str(counts.A) + " " + str(counts.C) + " " + str(counts.G) + " " + str(counts.T)
println("Result: " + result)
println("Expected: 20 12 17 21")
println("Match: " + str(result == "20 12 17 21"))
fn test_ini_base_counts() {
assert result == "20 12 17 21", "INI: expected '20 12 17 21', got '" + result + "'"
}
GBK — GenBank Introduction
solvedbrowser + CLI · online Problem statement Open in the workbench Download .bl
Calls NCBI, so it needs a network connection and its answer can change over time.
Entrez record counts grow as GenBank is updated, so no fixed answer can be asserted.
# Rosalind: GBK — GenBank Introduction
# https://rosalind.info/problems/gbk/
#
# Given: A genus name, two dates in YYYY/M/D format.
# Return: Number of Nucleotide GenBank entries for that genus published between the dates.
let genus = "Anthoxanthum"
let date_from = "2003/07/25"
let date_to = "2005/12/27"
# Build NCBI Entrez query with organism and date range
let query = genus + "[Organism] AND (\"" + date_from + "\"[PDAT] : \"" + date_to + "\"[PDAT])"
try {
let result = ncbi_search("nucleotide", query)
println("Result: " + str(len(result)))
println("Expected: 7")
println("Note: Count may differ as GenBank is updated over time")
} catch e {
println("NCBI query failed: " + str(e))
println("Expected: 7 (from Rosalind sample)")
}
FRMT — Data Formats
solvedbrowser + CLI · online Problem statement Open in the workbench Download .bl
Calls NCBI, so it needs a network connection and its answer can change over time.
# Rosalind: FRMT — Data Formats
# https://rosalind.info/problems/frmt/
#
# Given: A collection of n (n <= 10) GenBank entry IDs.
# Return: The shortest of the strings in FASTA format.
let ids = ["FJ817486", "JX069768", "JX469983"]
try {
# Fetch each sequence as FASTA string, extract sequence length
let results = ids |> map(|id| {
let fasta_str = ncbi_sequence(id)
# Parse: first line is header (>...), rest is sequence
let lines = split(fasta_str, "\n")
let header = lines[0]
# drop(_, 1) removes the ">" header. tail() would not: it returns the
# *last* n lines and defaults to 5, so the length below counted only
# the tail of each record and the comparison was decided by luck.
let seq = drop(lines, 1) |> join("")
{id: id, header: header, seq_len: len(seq)}
})
# Find shortest
let shortest = results |> reduce(|a, b| {
if a.seq_len <= b.seq_len then a else b
})
println("Shortest: " + shortest.id + " (" + str(shortest.seq_len) + " bp)")
println("Header: " + shortest.header)
println("Expected: JX469983.1 is the shortest")
} catch e {
println("NCBI fetch failed: " + str(e))
println("Expected: JX469983.1 is the shortest sequence")
}
MEME — New Motif Discovery
partialbrowser + CLI Problem statement Open in the workbench Download .bl
Partial: no probabilistic motif discovery; finds exact shared substrings instead of a MEME position-weight motif.
# Rosalind: MEME — New Motif Discovery
# https://rosalind.info/problems/meme/
#
# Given: FASTA protein sequences sharing a common motif (length >= 20).
# Return: Regular expression for the best-scoring motif.
#
# Note: This problem requires the MEME Suite external tool.
# BioLang can find exact shared substrings but not probabilistic motifs
# with position-specific variation. We demonstrate substring search instead.
let seqs = [
"MSNLHTHHLRLQAKLHEQHPGLHVSPFEVDFDMKAIDLLGKYNNKRGFYKTLRAVRMFMILPTAIAFFDSWTLNMDLWWCWIPVHKNPHSFLKTWSPAAGHRGWQFDHNFFKDMGHHYLDQKRALQHIRHYQHVCEDWMYRCRSIWEHTPYVSHNDLCLWMAPRPCEQMISRVSSMWTLDGFPFHFRMHYPQNHESRHGQKQPLSYNFHICDDRHFGMHFPHPQNNHQEHLSHHDCMTQVYAH",
"MCYRMTAWSSGKQFNKGADIFRMSFDLWWCWIPVHKNPHSFLKTWSPAAGHRGWQFDHNFFKQPQHVIWNHCQPFQHQMHRNFATMDYNAHKWMLRSLAGKFLDLGYRQMSRVLQHVINATPHESYNFHAKQRLSYIPVNEKIQPQETSWQVEEPF",
"MSHKADMRSSRKKCSIGIDLWWCWIPVHKKPHSFLKTWSPAAGHRGWQFDHNFFKALGEKVRQTEKQEYFLEKFPHHEQFMISEPQKQESRCWRAVMKPEDAYNEIQTLGKQHCHFWQRHMIFVQKGVKAVQNWLSFRYTQCPYRGSQR"
]
# Find shared substrings of length >= 20 using a simple sliding window
let min_motif = 20
let first_seq = seqs[0]
let shared = []
let i = 0
while i <= len(first_seq) - min_motif {
let candidate = substr(first_seq, i, min_motif)
let found_in_all = true
for seq in seqs {
if !(seq |> contains(candidate)) then
found_in_all = false
}
if found_in_all then
shared = shared + [candidate]
i = i + 1
}
if len(shared) > 0 then {
println("Shared substring(s) of length " + str(min_motif) + ":")
# Show unique shared substrings
let seen = []
shared |> each(|s| {
if !(seen |> contains(s)) then {
println(" " + s)
seen = seen + [s]
}
})
}
println("\nExpected (from MEME): DLWWCWIPVHK[NK]PHSFLKTWSPAAGHRGWQFDHNFF")
println("Note: MEME finds probabilistic motifs with position-specific variants;")
println(" BioLang finds exact shared substrings as an approximation.")
fn test_meme_shared_substrings() {
assert len(shared) == 6, "MEME: expected 6 shared 20-mers, got " + str(len(shared))
assert shared[0] == "PHSFLKTWSPAAGHRGWQFD", "MEME: unexpected first shared substring " + shared[0]
}
NEED — Pairwise Global Alignment
solvedbrowser + CLI · online Problem statement Open in the workbench Download .bl
Calls NCBI, so it needs a network connection and its answer can change over time.
Reproduces the EMBOSS Needle score of 257 using align() with affine gaps (match 5, mismatch -4, gap_open -9, gap_extend -1). Asserted, but excluded from the hermetic CI gate because it fetches from NCBI.
# Rosalind: NEED — Pairwise Global Alignment
# https://rosalind.info/problems/need/
#
# Given: Two GenBank IDs.
# Return: Maximum global alignment score (DNAfull matrix, gap_open=10, gap_extend=1).
let ids = ["JX205496.1", "JX469991.1"]
# Fetch each record and drop the ">" header line. drop(_, 1) rather than
# tail(): tail() returns the *last* n lines and defaults to 5.
let sequences = ids |> map(|id| drop(split(ncbi_sequence(id), "\n"), 1) |> join(""))
println("Sequences:")
range(0, len(ids)) |> each(|i| println(" " + ids[i] + ": " + str(len(sequences[i])) + " bp"))
# DNAfull scores an ACGT match +5 and a mismatch -4.
#
# EMBOSS charges `gapopen` for the first position of a gap and `gapextend` for
# each further one. This aligner charges `gap_open + gap_extend` to start a gap
# and `gap_extend` to continue it, so gapopen=10 / gapextend=1 becomes
# gap_open = -9 and gap_extend = -1.
let result = align(sequences[0], sequences[1], "global", 5, -4, -1, -9)
println("\nResult: " + str(result.score))
println("Expected: 257")
println("Match: " + str(result.score == 257))
println("\nAlignment detail:")
println(" Identity: " + str(result.identity))
println(" Gaps: " + str(result.gaps))
fn test_need_global_alignment_score() {
assert result.score == 257, "NEED: expected 257, got " + str(result.score)
}
TFSQ — FASTQ format introduction
solvedbrowser + CLI Problem statement Open in the workbench Download .bl
# Rosalind: TFSQ — FASTQ Format Introduction
# https://rosalind.info/problems/tfsq/
#
# Given: FASTQ entries.
# Return: Corresponding FASTA records (strip quality, change @ to >).
# Sample FASTQ data
let fastq_id = "SEQ_ID"
let fastq_seq = "GATTTGGGGTTCAAAGCAGTATCGATCAAATAGTAAATCCATTTGTTCAACTCACAGTTT"
# Convert to FASTA format
let fasta_text = ">" + fastq_id + "\n" + fastq_seq
println("Result:")
println(fasta_text)
println("")
println("Expected:")
println(">SEQ_ID")
println("GATTTGGGGTTCAAAGCAGTATCGATCAAATAGTAAATCCATTTGTTCAACTCACAGTTT")
let ok = fasta_text == ">SEQ_ID\nGATTTGGGGTTCAAAGCAGTATCGATCAAATAGTAAATCCATTTGTTCAACTCACAGTTT"
println("\nMatch: " + str(ok))
fn test_tfsq_fastq_to_fasta() {
assert ok, "TFSQ: FASTA conversion did not match the expected record"
}
PHRE — Read Quality Distribution
solvedbrowser + CLI Problem statement Open in the workbench Download .bl
# Rosalind: PHRE — Read Quality Distribution
# https://rosalind.info/problems/phre/
#
# Given: A quality threshold and FASTQ entries.
# Return: Number of reads whose average quality is below the threshold.
let threshold = 28
# Sample reads with Phred33 quality strings
let quality_strings = [
"6.3536354;.151<211/0?::6/-2051)-*\"40/.,+%)",
"AH@FGGGJ<GB<<9:GD=D@GG9=?A@DC=;:?>839/4856",
"@DJEJEA?JHJ@8?F?IA3=;8@C95=;=?;>D/:;74792."
]
# Parse Phred33: each character's ASCII value minus 33 gives quality score
let below_count = 0
for qual_str in quality_strings {
let chars = split(qual_str, "")
let scores = chars |> filter(|c| c != "") |> map(|c| ascii(c) - 33)
let avg = (scores |> reduce(|a, b| a + b)) / len(scores)
if avg < threshold then
below_count = below_count + 1
}
println("Result: " + str(below_count))
println("Expected: 1")
println("Match: " + str(below_count == 1))
fn test_phre_reads_below_threshold() {
assert below_count == 1, "PHRE: expected 1, got " + str(below_count)
}
PTRA — Protein Translation
solvedbrowser + CLI Problem statement Open in the workbench Download .bl
# Rosalind: PTRA — Protein Translation
# https://rosalind.info/problems/ptra/
#
# Given: A DNA string s and a protein string p.
# Return: The genetic code variant table number used for translation.
#
# BioLang uses standard genetic code (table 1). We verify by translating
# and comparing the result.
let dna_seq = dna"ATGGCCATGGCGCCCAGAACTGAGATCAATAGTACCCGTATTAACGGGTGA"
let expected_protein = protein"MAMAPRTEINSTRING"
# translate() stops at the first stop codon
let result = translate(dna_seq)
println("Translated: " + str(result))
println("Expected: " + str(expected_protein))
# Standard genetic code (table 1) should produce the expected protein
let grid = if result == expected_protein then 1 else 0
println("Table: " + str(grid))
println("Expected: 1")
println("Match: " + str(grid == 1))
fn test_ptra_standard_genetic_code() {
assert grid == 1, "PTRA: standard code (grid 1) should reproduce " + str(expected_protein)
}
FILT — Read Filtration by Quality
solvedbrowser + CLI Problem statement Open in the workbench Download .bl
# Rosalind: FILT — Read Filtration by Quality
# https://rosalind.info/problems/filt/
#
# Given: Quality threshold q, percentage p, and FASTQ entries.
# Return: Number of reads where at least p% of bases have quality >= q.
let q = 20
let p = 90
let reads = [
{id: "Rosalind_0049_1", seq: "GCAGAGACCAGTAGATGTGTTTGCGGACGGTCGGGCTCCATGTGACACAG",
qual: "FD@@;C<AI?4BA:=>C<G=:AE=><A??>764A8B797@A:58:527+,"},
{id: "Rosalind_0049_2", seq: "AATGGGGGGGGGAGACAAAATACGGCTAAGGCAGGGGTCCTTGATGTCAT",
qual: "1<<65:793967<4:92568-34:.>1;2752)24')*15;1,.3*3+*!"},
{id: "Rosalind_0049_3", seq: "ACCCCATACGGCGAGCGTCAGCATCTGATATCCTCTTTCAATCCTAGCTA",
qual: "B:EI>JDB5=>DA?E6B@@CA?C;=;@@C:6D:3=@49;@87;::;;?8+"}
]
let passing = 0
for read in reads {
let chars = split(read.qual, "") |> filter(|c| c != "")
let scores = chars |> map(|c| ascii(c) - 33)
let good = scores |> filter(|s| s >= q) |> count()
let pct = (good * 100) / len(scores)
if pct >= p then
passing = passing + 1
}
println("Result: " + str(passing))
println("Expected: 2")
println("Match: " + str(passing == 2))
fn test_filt_reads_passing() {
assert passing == 2, "FILT: expected 2, got " + str(passing)
}
RVCO — Complementing a Strand of DNA
solvedbrowser + CLI Problem statement Open in the workbench Download .bl
# Rosalind: RVCO — Complementing a Strand of DNA
# https://rosalind.info/problems/rvco/
#
# Given: A collection of n (n <= 10) DNA strings.
# Return: The number of strings that match their own reverse complement.
let sequences = [
dna"ATAT",
dna"GCATA"
]
let palindrome_count = 0
for seq in sequences {
let rc = reverse_complement(seq)
if str(seq) == str(rc) then
palindrome_count = palindrome_count + 1
}
println("Result: " + str(palindrome_count))
println("Expected: 1")
println("Match: " + str(palindrome_count == 1))
# Verify: ATAT -> rev_comp = ATAT (palindrome), GCATA -> rev_comp = TATGC (not)
println("\nDetail:")
for seq in sequences {
let rc = reverse_complement(seq)
let is_palindrome = str(seq) == str(rc)
println(" " + str(seq) + " -> rc=" + str(rc) + " palindrome=" + str(is_palindrome))
}
fn test_rvco_palindrome_count() {
assert palindrome_count == 1, "RVCO: expected 1, got " + str(palindrome_count)
}
SUBO — Suboptimal Local Alignment
solvedbrowser + CLI Problem statement Open in the workbench Download .bl
Brute-force O(n^3) window scan; ~25 s. A motif-index approach would be the natural follow-up.
# Rosalind: SUBO — Suboptimal Local Alignment
# https://rosalind.info/problems/subo/
#
# Given: Two DNA strings with a shared inexact repeat (32-40 bp, <=3 changes).
# Return: Total occurrences of the repeat in each string.
let seq1 = "GACTCCTTTGTTTGCCTTAAATAGATACATATTTACTCTTGACTCTTTTGTTGGCCTTAAATAGATACATATTTGTGCGACTCCACGAGTGATTCGTA"
let seq2 = "ATGGACTCCTTTGTTTGCCTTAAATAGATACATATTCAACAAGTGTGCACTTAGCCTTGCCGACTCCTTTGTTTGCCTTAAATAGATACATATTTG"
# Strategy: find all 32-bp substrings of seq1 that appear in seq2 with <=3 mismatches
let motif_len = 33
# Helper: count mismatches between two strings of equal length
# (hamming_distance works on sequences; we use manual counting for strings)
let s1 = seq1
let s2 = seq2
# Find the best shared motif by checking each 33-bp window of s1 against all windows of s2
let best_motif = ""
let best_total = 0
let i = 0
while i <= len(s1) - motif_len {
let candidate = substr(s1, i, motif_len)
# Count approximate matches in s2
let hits_s2 = 0
let j = 0
while j <= len(s2) - motif_len {
let target = substr(s2, j, motif_len)
let dist = hamming_distance(candidate, target)
if dist <= 3 then
hits_s2 = hits_s2 + 1
j = j + 1
}
if hits_s2 > 0 then {
# Also count in s1
let hits_s1 = 0
let k = 0
while k <= len(s1) - motif_len {
let target = substr(s1, k, motif_len)
let dist = hamming_distance(candidate, target)
if dist <= 3 then
hits_s1 = hits_s1 + 1
k = k + 1
}
let total = hits_s1 + hits_s2
if total > best_total then {
best_total = total
best_motif = candidate
}
}
i = i + 1
}
# Now count non-overlapping occurrences using the best motif
# Count all approximate matches (overlapping) — Rosalind counts overlapping instances
let count1 = 0
let i = 0
while i <= len(s1) - motif_len {
let window = substr(s1, i, motif_len)
if hamming_distance(best_motif, window) <= 3 then
count1 = count1 + 1
i = i + 1
}
let count2 = 0
let j = 0
while j <= len(s2) - motif_len {
let window = substr(s2, j, motif_len)
if hamming_distance(best_motif, window) <= 3 then
count2 = count2 + 1
j = j + 1
}
println("Motif: " + best_motif)
println("Result: " + str(count1) + " " + str(count2))
println("Expected: 2 2")
println("Match: " + str(count1 == 2 && count2 == 2))
fn test_subo_repeat_occurrences() {
assert count1 == 2 && count2 == 2, "SUBO: expected 2 2, got " + str(count1) + " " + str(count2)
}
BPHR — Base Quality Distribution
solvedbrowser + CLI Problem statement Open in the workbench Download .bl
# Rosalind: BPHR — Base Quality Distribution
# https://rosalind.info/problems/bphr/
#
# Given: FASTQ file and quality threshold q.
# Return: Number of positions where mean base quality falls below q.
let threshold = 26
let quality_strings = [
">?F?@6<C<HF?<85486B;85:8488/2/",
"@J@H@>B9:B;<D==:<;:,<::?463-,,",
"=88;99637@5,4664-65)/?4-2+)$)$",
"<@BGE@8C9=B9:B<>>>7?B>7:02+33."
]
# All reads should be the same length
let read_len = len(split(quality_strings[0], "") |> filter(|c| c != ""))
# Calculate mean quality at each position across all reads
let below_count = 0
let i = 0
while i < read_len {
let total = 0
for qual_str in quality_strings {
let chars = split(qual_str, "") |> filter(|c| c != "")
total = total + ascii(chars[i]) - 33
}
let mean = total / len(quality_strings)
if mean < threshold then
below_count = below_count + 1
i = i + 1
}
println("Result: " + str(below_count))
println("Expected: 17")
println("Match: " + str(below_count == 17))
fn test_bphr_positions_below_threshold() {
assert below_count == 17, "BPHR: expected 17, got " + str(below_count)
}
CLUS — Global Multiple Alignment
solvedbrowser + CLI Problem statement Open in the workbench Download .bl
# Rosalind: CLUS — Global Multiple Alignment
# https://rosalind.info/problems/clus/
#
# Given: Set of DNA strings in FASTA format.
# Return: ID of the string most different from the others.
#
# We compute pairwise edit distances and find the sequence with
# the highest average distance to all others.
let sequences = [
{id: "Rosalind_18", seq: dna"GACATGTTTGTTTGCCTTAAACTCGTGGCGGCCTAGCCGTAAGTTAAG"},
{id: "Rosalind_23", seq: dna"ACTCATGTTTGTTTGCCTTAAACTCTTGGCGGCTTAGCCGTAACTTAAG"},
{id: "Rosalind_51", seq: dna"TCCTATGTTTGTTTGCCTCAAACTCTTGGCGGCCTAGCCGTAAGGTAAG"},
{id: "Rosalind_7", seq: dna"CACGTCTGTTCGCCTAAAACTTTGATTGCCGGCCTACGCTAGTTAGTTA"},
{id: "Rosalind_28", seq: dna"GGGGTCATGGCTGTTTGCCTTAAACCCTTGGCGGCCTAGCCGTAATGTTT"}
]
# Compute pairwise distances and find the most distant sequence
let most_different_id = ""
let max_avg_dist = 0
for i_seq in sequences {
let total_dist = 0
let pair_count = 0
for j_seq in sequences {
if i_seq.id != j_seq.id then {
let dist = edit_distance(str(i_seq.seq), str(j_seq.seq))
total_dist = total_dist + dist
pair_count = pair_count + 1
}
}
let avg_dist = total_dist / pair_count
if avg_dist > max_avg_dist then {
max_avg_dist = avg_dist
most_different_id = i_seq.id
}
}
println("Result: " + most_different_id)
println("Expected: Rosalind_7")
println("Match: " + str(most_different_id == "Rosalind_7"))
fn test_clus_most_different_sequence() {
assert most_different_id == "Rosalind_7", "CLUS: expected Rosalind_7, got " + most_different_id
}
ORFR — Finding Genes with ORFs
solvedbrowser + CLI Problem statement Open in the workbench Download .bl
# Rosalind: ORFR — Finding Genes with ORFs
# https://rosalind.info/problems/orfr/
#
# Given: A DNA string s of length at most 1 kbp.
# Return: The longest protein string from any ORF (all six reading frames).
let s = dna"AGCCATGTAGCTAACTCAGGTTACATGGGGATGACCCCGCGACTTGGATTAGAGTCTCTTTTGGAATAAGCCTGAATGATCCGAGTAGCATCTCAG"
# find_orfs searches 3 forward reading frames; we also need the reverse complement
let fwd_orfs = find_orfs(s, 1)
let rc = reverse_complement(s)
let rev_orfs = find_orfs(rc, 1)
let all_orfs = fwd_orfs + rev_orfs
# Find the longest protein
let longest = all_orfs |> reduce(|a, b| {
if seq_len(a.protein) >= seq_len(b.protein) then a else b
})
let result = longest.protein
let expected = protein"MLLGSFRLIPKETLIQVAGSSPCNLS"
println("Result: " + str(result))
println("Expected: " + str(expected))
println("Match: " + str(result == expected))
println("\nAll ORFs found (" + str(len(all_orfs)) + "):")
all_orfs |> each(|o| println(" frame=" + str(o.frame) + " len=" + str(seq_len(o.protein)) + " " + str(o.protein)))
fn test_orfr_longest_protein() {
assert result == expected, "ORFR: expected " + str(expected) + ", got " + str(result)
}
BFIL — Base Filtration by Quality
solvedbrowser + CLI Problem statement Open in the workbench Download .bl
# Rosalind: BFIL — Base Filtration by Quality
# https://rosalind.info/problems/bfil/
#
# Given: FASTQ file and quality threshold q (Phred33).
# Return: FASTQ with leading and trailing low-quality bases trimmed.
let q = 20
let reads = [
{id: "Rosalind_0049",
seq: "GCAGAGACCAGTAGATGTGTTTGCGGACGGTCGGGCTCCATGTGACACAG",
qual: "FD@@;C<AI?4BA:=>C<G=:AE=><A??>764A8B797@A:58:527+,"},
{id: "Rosalind_0049",
seq: "AATGGGGGGGGGAGACAAAATACGGCTAAGGCAGGGGTCCTTGATGTCAT",
qual: "1<<65:793967<4:92568-34:.>1;2752)24')*15;1,.3*3+*!"},
{id: "Rosalind_0049",
seq: "ACCCCATACGGCGAGCGTCAGCATCTGATATCCTCTTTCAATCCTAGCTA",
qual: "B:EI>JDB5=>DA?E6B@@CA?C;=;@@C:6D:3=@49;@87;::;;?8+"}
]
let trimmed_reads = []
println("Result:")
for read in reads {
let chars_seq = split(read.seq, "") |> filter(|c| c != "")
let chars_qual = split(read.qual, "") |> filter(|c| c != "")
let scores = chars_qual |> map(|c| ascii(c) - 33)
# Find first position from left with quality >= q
let start = 0
while start < len(scores) && scores[start] < q {
start = start + 1
}
# Find last position from right with quality >= q
let end_pos = len(scores) - 1
while end_pos >= 0 && scores[end_pos] < q {
end_pos = end_pos - 1
}
let trimmed_seq = chars_seq |> slice(start, end_pos + 1) |> join("")
let trimmed_qual = chars_qual |> slice(start, end_pos + 1) |> join("")
trimmed_reads = push(trimmed_reads, trimmed_seq)
println("@" + read.id)
println(trimmed_seq)
println("+")
println(trimmed_qual)
}
println("\nExpected:")
println("@Rosalind_0049")
println("GCAGAGACCAGTAGATGTGTTTGCGGACGGTCGGGCTCCATGTGACAC")
println("+")
println("FD@@;C<AI?4BA:=>C<G=:AE=><A??>764A8B797@A:58:527")
println("@Rosalind_0049")
println("ATGGGGGGGGGAGACAAAATACGGCTAAGGCAGGGGTCCT")
println("+")
println("<<65:793967<4:92568-34:.>1;2752)24')*15;")
println("@Rosalind_0049")
println("ACCCCATACGGCGAGCGTCAGCATCTGATATCCTCTTTCAATCCTAGCT")
println("+")
println("B:EI>JDB5=>DA?E6B@@CA?C;=;@@C:6D:3=@49;@87;::;;?8")
fn test_bfil_trims_low_quality_ends() {
let expected = [
"GCAGAGACCAGTAGATGTGTTTGCGGACGGTCGGGCTCCATGTGACAC",
"ATGGGGGGGGGAGACAAAATACGGCTAAGGCAGGGGTCCT",
"ACCCCATACGGCGAGCGTCAGCATCTGATATCCTCTTTCAATCCTAGCT"
]
assert len(trimmed_reads) == 3, "BFIL: expected 3 reads, got " + str(len(trimmed_reads))
let i = 0
while i < 3 {
assert trimmed_reads[i] == expected[i], "BFIL: read " + str(i + 1) + " trimmed to " + trimmed_reads[i]
i = i + 1
}
}