ICFP 2007 Contest: https://web.archive.org/web/20090301164728/https://save-endo.cs.uu.nl/

Add match replace code

Changed files
+281 -2
dna2rna
+3 -1
dna2rna/src/dna.rs
···
}
}
+
#[cfg(test)]
fn to_char(&self) -> char {
match self {
Base::I => 'I',
···
Self::DnaRef(Rc::new(Dna::Empty))
}
-
fn from_base(b: Base) -> Self {
+
pub fn from_base(b: Base) -> Self {
Self::DnaRef(Rc::new(Dna::Leaf(b)))
}
···
}
}
+
#[cfg(test)]
pub fn to_string(&self) -> String {
self.iter().map(|b| Base::to_char(&b)).collect::<String>()
}
+273
dna2rna/src/match_replace.rs
···
+
use crate::dna::Base;
+
use crate::dna::DnaRef;
+
use crate::parser::Parser;
+
use crate::pattern::Pattern;
+
use crate::pattern::PatternItem;
+
use crate::rna::Rna;
+
use crate::template::TemplateItem;
+
+
struct MatchResult {
+
end: usize,
+
groups: Vec<(usize, usize)>,
+
}
+
+
fn do_match(dna: &DnaRef, start: usize, pattern: &Pattern) -> Option<MatchResult> {
+
let mut index = start;
+
let mut env = Vec::new();
+
let mut opens = Vec::new();
+
for p in pattern.iter() {
+
match p {
+
PatternItem::Base(b) => {
+
if index >= dna.len() || dna[index] != *b {
+
return None;
+
}
+
+
index += 1;
+
}
+
PatternItem::Skip(n) => {
+
index += n;
+
if index > dna.len() {
+
return None;
+
}
+
}
+
PatternItem::Search(s) => {
+
let mut fallback = Vec::new();
+
fallback.reserve(s.len());
+
fallback.push(0);
+
fallback.push(0);
+
for i in 2..s.len() {
+
let mut j = fallback[i - 1];
+
while j > 0 && s[j] != s[i - 1] {
+
j = fallback[j];
+
}
+
if s[i - 1] == s[j] {
+
fallback.push(j + 1);
+
} else {
+
fallback.push(0);
+
}
+
}
+
+
let mut cur = 0;
+
loop {
+
if cur == s.len() {
+
break;
+
} else if index >= dna.len() {
+
return None;
+
} else if dna[index] == s[cur] {
+
index += 1;
+
cur += 1;
+
} else if cur == 0 {
+
index += 1;
+
} else {
+
cur = fallback[cur];
+
}
+
}
+
}
+
PatternItem::Open => {
+
opens.push(index);
+
}
+
PatternItem::Close => {
+
let start = opens.pop()?;
+
env.push((start, index));
+
}
+
}
+
}
+
+
return Some(MatchResult {
+
end: index,
+
groups: env,
+
});
+
}
+
+
pub fn protect(dna: DnaRef, level: usize) -> DnaRef {
+
if level == 0 {
+
return dna;
+
}
+
+
let mut cur = dna.clone();
+
for _ in 0..level {
+
cur = cur
+
.iter()
+
.flat_map(|b| match b {
+
Base::I => [Base::C].iter(),
+
Base::C => [Base::F].iter(),
+
Base::F => [Base::P].iter(),
+
Base::P => [Base::I, Base::C].iter(),
+
})
+
.map(|b| DnaRef::from_base(*b))
+
.collect::<DnaRef>();
+
}
+
+
return cur;
+
}
+
+
pub fn asnat(n: usize) -> DnaRef {
+
let mut v = Vec::new();
+
let mut cur = n;
+
while cur > 0 {
+
if cur % 2 == 1 {
+
v.push(Base::C);
+
} else {
+
v.push(Base::I);
+
}
+
+
cur /= 2;
+
}
+
v.push(Base::P);
+
return v.iter().map(|b| DnaRef::from_base(*b)).collect::<DnaRef>();
+
}
+
+
pub fn match_replace(dna: DnaRef, rna: &mut Vec<Rna>) -> Option<DnaRef> {
+
let mut parser = Parser::new(&dna);
+
let pattern = parser.pattern(rna)?;
+
let template = parser.template(rna)?;
+
let index = parser.index();
+
+
if let Some(matched) = do_match(&dna, index, &pattern) {
+
let mut replace = DnaRef::new();
+
for t in template.into_iter() {
+
match t {
+
TemplateItem::Base(b) => {
+
// TODO: Implement AddAssign
+
replace = replace + DnaRef::from_base(b);
+
}
+
TemplateItem::Ref(n, l) => {
+
let (start, end) = matched.groups[n];
+
let (_, rhs) = dna.split(start);
+
let (group, _) = rhs.split(end - start);
+
replace = replace + protect(group, l);
+
}
+
TemplateItem::Len(n) => {
+
let (start, end) = matched.groups[n];
+
replace = replace + asnat(end - start);
+
}
+
}
+
}
+
let (_, remainder) = dna.split(matched.end);
+
return Some(replace + remainder);
+
} else {
+
let (_, rhs) = dna.split(index);
+
return Some(rhs);
+
}
+
}
+
+
#[cfg(test)]
+
mod tests {
+
use super::*;
+
+
#[test]
+
fn test_match_bases() {
+
// ICFP -> III on ICFP
+
let dna = DnaRef::from_string("CFPICIIC CCCIIC ICFP");
+
let mut rna = Vec::new();
+
let res = match_replace(dna, &mut rna);
+
assert!(res.is_some());
+
assert_eq!(res.unwrap().to_string(), "III");
+
}
+
+
#[test]
+
fn test_match_skip() {
+
// !{10} -> III on ICFPICFPICFP
+
let dna = DnaRef::from_string("IPICICPIIC CCCIIC ICFPICFPICFP");
+
let mut rna = Vec::new();
+
let res = match_replace(dna, &mut rna);
+
assert!(res.is_some());
+
assert_eq!(res.unwrap().to_string(), "IIIFP");
+
}
+
+
#[test]
+
fn test_match_search() {
+
// ?{IIIC} -> <empty> on ICIICIIICICFP
+
let dna = DnaRef::from_string("IFFCCCFIIC IIC ICIICIIICICFP");
+
let mut rna = Vec::new();
+
let res = match_replace(dna, &mut rna);
+
assert!(res.is_some());
+
assert_eq!(res.unwrap().to_string(), "ICFP");
+
}
+
+
#[test]
+
fn test_match_groups() {
+
// (!{1})(!{1})(!{1})(!{1}) -> {3}{2}{1}{0} on ICFP
+
let dna = DnaRef::from_string(
+
"IIPIPCPIICIIPIPCPIICIIPIPCPIICIIPIPCPIICIIC IPPCCPIPPICPIPPCPIPPPIIC ICFP",
+
);
+
let mut rna = Vec::new();
+
let res = match_replace(dna, &mut rna);
+
assert!(res.is_some());
+
assert_eq!(res.unwrap().to_string(), "PFCI");
+
}
+
+
#[test]
+
fn test_match_protect() {
+
// (!{4}) -> {0}{0,1}{0,2}{0,3} on ICFP
+
let dna = DnaRef::from_string("IIPIPIICPIICIIC IPPPIPCPPIPICPPIPCCPPIIC ICFP");
+
let mut rna = Vec::new();
+
let res = match_replace(dna, &mut rna);
+
assert!(res.is_some());
+
assert_eq!(res.unwrap().to_string(), "ICFPCFPICFPICCFPICCFFP");
+
}
+
+
#[test]
+
fn test_match_asnat() {
+
// (!{10}) -> |0| on ICFPICFPICFP
+
let dna = DnaRef::from_string("IIPIPICICPIICIIC IIPPIIC ICFPICFPICFP");
+
let mut rna = Vec::new();
+
let res = match_replace(dna, &mut rna);
+
assert!(res.is_some());
+
assert_eq!(res.unwrap().to_string(), "ICICPFP");
+
}
+
+
#[test]
+
fn test_match_rna() {
+
// RIPIPIPI -> RCFCFCFC on ICFP
+
let dna = DnaRef::from_string("IIIIPIPIPIIIC IIICFCFCFCIIC ICFP");
+
let mut rna = Vec::new();
+
let res = match_replace(dna, &mut rna);
+
assert!(res.is_some());
+
assert_eq!(res.unwrap().to_string(), "ICFP");
+
assert_eq!(
+
rna,
+
vec![
+
[
+
Base::I,
+
Base::P,
+
Base::I,
+
Base::P,
+
Base::I,
+
Base::P,
+
Base::I
+
],
+
[
+
Base::C,
+
Base::F,
+
Base::C,
+
Base::F,
+
Base::C,
+
Base::F,
+
Base::C
+
]
+
]
+
)
+
}
+
+
#[test]
+
fn test_from_task() {
+
let dna = DnaRef::from_string("IIPIPICPIICICIIFICCIFPPIICCFPC");
+
let mut rna = Vec::new();
+
let res = match_replace(dna, &mut rna);
+
assert!(res.is_some());
+
assert_eq!(res.unwrap().to_string(), "PICFC");
+
+
let dna = DnaRef::from_string("IIPIPICPIICICIIFICCIFCCCPPIICCFPC");
+
let mut rna = Vec::new();
+
let res = match_replace(dna, &mut rna);
+
assert!(res.is_some());
+
assert_eq!(res.unwrap().to_string(), "PIICCFCFFPC");
+
+
let dna = DnaRef::from_string("IIPIPIICPIICIICCIICFCFC");
+
let mut rna = Vec::new();
+
let res = match_replace(dna, &mut rna);
+
assert!(res.is_some());
+
assert_eq!(res.unwrap().to_string(), "I");
+
}
+
}
+5 -1
dna2rna/src/parser.rs
···
use crate::template::Template;
use crate::template::TemplateItem;
-
struct Parser<'a> {
+
pub struct Parser<'a> {
buf: &'a DnaRef,
index: usize,
}
···
impl<'a> Parser<'a> {
pub fn new(buf: &'a DnaRef) -> Parser<'a> {
Parser { buf: buf, index: 0 }
+
}
+
+
pub fn index(&self) -> usize {
+
self.index
}
pub fn next_is(&mut self, next: &[Base]) -> bool {