ICFP 2007 Contest: https://web.archive.org/web/20090301164728/https://save-endo.cs.uu.nl/
1use crate::dna::Base; 2use crate::dna::DnaRef; 3use crate::parser::Parser; 4use crate::pattern::Pattern; 5use crate::pattern::PatternItem; 6use crate::rna::Rna; 7use crate::template::TemplateItem; 8 9struct MatchResult { 10 end: usize, 11 groups: Vec<(usize, usize)>, 12} 13 14fn do_match(dna: &DnaRef, start: usize, pattern: &Pattern) -> Option<MatchResult> { 15 let mut index = start; 16 let mut env = Vec::new(); 17 let mut opens = Vec::new(); 18 for p in pattern.iter() { 19 match p { 20 PatternItem::Base(b) => { 21 if index >= dna.len() || dna[index] != *b { 22 return None; 23 } 24 25 index += 1; 26 } 27 PatternItem::Skip(n) => { 28 index += n; 29 if index > dna.len() { 30 return None; 31 } 32 } 33 PatternItem::Search(s) => { 34 let mut fallback = Vec::new(); 35 fallback.reserve(s.len()); 36 fallback.push(0); 37 fallback.push(0); 38 for i in 2..s.len() { 39 let mut j = fallback[i - 1]; 40 while j > 0 && s[j] != s[i - 1] { 41 j = fallback[j]; 42 } 43 if s[i - 1] == s[j] { 44 fallback.push(j + 1); 45 } else { 46 fallback.push(0); 47 } 48 } 49 50 let mut cur = 0; 51 loop { 52 if cur == s.len() { 53 break; 54 } else if index >= dna.len() { 55 return None; 56 } else if dna[index] == s[cur] { 57 index += 1; 58 cur += 1; 59 } else if cur == 0 { 60 index += 1; 61 } else { 62 cur = fallback[cur]; 63 } 64 } 65 } 66 PatternItem::Open => { 67 opens.push(index); 68 } 69 PatternItem::Close => { 70 let start = opens.pop()?; 71 env.push((start, index)); 72 } 73 } 74 } 75 76 return Some(MatchResult { 77 end: index, 78 groups: env, 79 }); 80} 81 82pub fn protect(dna: DnaRef, level: usize) -> DnaRef { 83 if level == 0 { 84 return dna; 85 } 86 87 let mut cur = dna.clone(); 88 for _ in 0..level { 89 cur = cur 90 .iter() 91 .flat_map(|b| match b { 92 Base::I => [Base::C].iter(), 93 Base::C => [Base::F].iter(), 94 Base::F => [Base::P].iter(), 95 Base::P => [Base::I, Base::C].iter(), 96 }) 97 .map(|b| DnaRef::from_base(*b)) 98 .collect::<DnaRef>(); 99 } 100 101 return cur; 102} 103 104pub fn asnat(n: usize) -> DnaRef { 105 let mut v = Vec::new(); 106 let mut cur = n; 107 while cur > 0 { 108 if cur % 2 == 1 { 109 v.push(Base::C); 110 } else { 111 v.push(Base::I); 112 } 113 114 cur /= 2; 115 } 116 v.push(Base::P); 117 return v.iter().map(|b| DnaRef::from_base(*b)).collect::<DnaRef>(); 118} 119 120pub fn match_replace(dna: DnaRef, rna: &mut Vec<Rna>) -> Option<DnaRef> { 121 let mut parser = Parser::new(&dna); 122 let pattern = parser.pattern(rna)?; 123 let template = parser.template(rna)?; 124 let index = parser.index(); 125 126 if let Some(matched) = do_match(&dna, index, &pattern) { 127 let mut replace = DnaRef::new(); 128 for t in template.into_iter() { 129 match t { 130 TemplateItem::Base(b) => { 131 replace += DnaRef::from_base(b); 132 } 133 TemplateItem::Ref(n, l) => { 134 let (start, end) = matched.groups[n]; 135 let (_, rhs) = dna.split(start); 136 let (group, _) = rhs.split(end - start); 137 replace += protect(group, l); 138 } 139 TemplateItem::Len(n) => { 140 let (start, end) = matched.groups[n]; 141 replace += asnat(end - start); 142 } 143 } 144 } 145 let (_, remainder) = dna.split(matched.end); 146 return Some(replace + remainder); 147 } else { 148 let (_, rhs) = dna.split(index); 149 return Some(rhs); 150 } 151} 152 153#[cfg(test)] 154mod tests { 155 use super::*; 156 157 #[test] 158 fn test_match_bases() { 159 // ICFP -> III on ICFP 160 let dna = DnaRef::from_string("CFPICIIC CCCIIC ICFP"); 161 let mut rna = Vec::new(); 162 let res = match_replace(dna, &mut rna); 163 assert!(res.is_some()); 164 assert_eq!(res.unwrap().to_string(), "III"); 165 } 166 167 #[test] 168 fn test_match_skip() { 169 // !{10} -> III on ICFPICFPICFP 170 let dna = DnaRef::from_string("IPICICPIIC CCCIIC ICFPICFPICFP"); 171 let mut rna = Vec::new(); 172 let res = match_replace(dna, &mut rna); 173 assert!(res.is_some()); 174 assert_eq!(res.unwrap().to_string(), "IIIFP"); 175 } 176 177 #[test] 178 fn test_match_search() { 179 // ?{IIIC} -> <empty> on ICIICIIICICFP 180 let dna = DnaRef::from_string("IFFCCCFIIC IIC ICIICIIICICFP"); 181 let mut rna = Vec::new(); 182 let res = match_replace(dna, &mut rna); 183 assert!(res.is_some()); 184 assert_eq!(res.unwrap().to_string(), "ICFP"); 185 } 186 187 #[test] 188 fn test_match_groups() { 189 // (!{1})(!{1})(!{1})(!{1}) -> {3}{2}{1}{0} on ICFP 190 let dna = DnaRef::from_string( 191 "IIPIPCPIICIIPIPCPIICIIPIPCPIICIIPIPCPIICIIC IPPCCPIPPICPIPPCPIPPPIIC ICFP", 192 ); 193 let mut rna = Vec::new(); 194 let res = match_replace(dna, &mut rna); 195 assert!(res.is_some()); 196 assert_eq!(res.unwrap().to_string(), "PFCI"); 197 } 198 199 #[test] 200 fn test_match_protect() { 201 // (!{4}) -> {0}{0,1}{0,2}{0,3} on ICFP 202 let dna = DnaRef::from_string("IIPIPIICPIICIIC IPPPIPCPPIPICPPIPCCPPIIC ICFP"); 203 let mut rna = Vec::new(); 204 let res = match_replace(dna, &mut rna); 205 assert!(res.is_some()); 206 assert_eq!(res.unwrap().to_string(), "ICFPCFPICFPICCFPICCFFP"); 207 } 208 209 #[test] 210 fn test_match_asnat() { 211 // (!{10}) -> |0| on ICFPICFPICFP 212 let dna = DnaRef::from_string("IIPIPICICPIICIIC IIPPIIC ICFPICFPICFP"); 213 let mut rna = Vec::new(); 214 let res = match_replace(dna, &mut rna); 215 assert!(res.is_some()); 216 assert_eq!(res.unwrap().to_string(), "ICICPFP"); 217 } 218 219 #[test] 220 fn test_match_rna() { 221 // RIPIPIPI -> RCFCFCFC on ICFP 222 let dna = DnaRef::from_string("IIIIPIPIPIIIC IIICFCFCFCIIC ICFP"); 223 let mut rna = Vec::new(); 224 let res = match_replace(dna, &mut rna); 225 assert!(res.is_some()); 226 assert_eq!(res.unwrap().to_string(), "ICFP"); 227 assert_eq!( 228 rna, 229 vec![ 230 [ 231 Base::I, 232 Base::P, 233 Base::I, 234 Base::P, 235 Base::I, 236 Base::P, 237 Base::I 238 ], 239 [ 240 Base::C, 241 Base::F, 242 Base::C, 243 Base::F, 244 Base::C, 245 Base::F, 246 Base::C 247 ] 248 ] 249 ) 250 } 251 252 #[test] 253 fn test_from_task() { 254 let dna = DnaRef::from_string("IIPIPICPIICICIIFICCIFPPIICCFPC"); 255 let mut rna = Vec::new(); 256 let res = match_replace(dna, &mut rna); 257 assert!(res.is_some()); 258 assert_eq!(res.unwrap().to_string(), "PICFC"); 259 260 let dna = DnaRef::from_string("IIPIPICPIICICIIFICCIFCCCPPIICCFPC"); 261 let mut rna = Vec::new(); 262 let res = match_replace(dna, &mut rna); 263 assert!(res.is_some()); 264 assert_eq!(res.unwrap().to_string(), "PIICCFCFFPC"); 265 266 let dna = DnaRef::from_string("IIPIPIICPIICIICCIICFCFC"); 267 let mut rna = Vec::new(); 268 let res = match_replace(dna, &mut rna); 269 assert!(res.is_some()); 270 assert_eq!(res.unwrap().to_string(), "I"); 271 } 272}