====== Solution Ghostleg en Rust ====== Solution de ce [[nsi:tds:jeux:ghostleg|problème]]. // src/lib.rs use std::fs::File; use std::io::{ self, BufRead, BufReader }; fn transposition(line:&str, indice:usize) -> String { /* indice: rang d'un caractère fait la transpositon entre le rang voulu et le rang +1 renvoie une copie de la ligne avec la modif faite */ let n = line.len(); if indice >= n-1 { panic!("dépassement d'indice !"); } let mut out = String::new(); let mut right = ' '; for (i,c) in line.chars().enumerate() { if i == indice { right = c; } else { out.push(c); } if i == indice + 1 { out.push(right); } } out } fn ghostleg_line(line:&str, gline:&str) -> String { /* partant d'une ligne, ex: "ABC" et d'une ligne de ghostleg, ex |--| | calcule la ligne suivante, ex "BAC */ let mut s = String::from(line); for (i,c) in gline.chars().enumerate() { if i % 3 == 1 && c == '-' { s = transposition(&s, i/3); } } s } fn get_head(line:&str) -> String { /* renvoie une copie de line sans les espace */ let mut s = String::new(); for c in line.chars() { if c != ' ' && c != '\n' { s.push(c); } } s } fn read_lines(filename: &str) -> io::Lines> { let file = match File::open(filename){ Ok(f) => f, Err(erreur) => panic!("Erreur d'ouverture du fichier : {:?}", erreur), }; return io::BufReader::new(file).lines(); } pub fn ghostleg(filename: &str) -> String { /* text: ensemble du texte du ghostleg renvoie la chaîne finale */ let mut lines = read_lines(filename); let first_line = match lines.next() { Some(Ok(line)) => line, Some(Err(erreur)) => panic!("Erreur lecture première ligne : {:?}", erreur), None => panic!("Texte vide !"), }; let mut s = get_head(&first_line); for getline in lines { let line = match getline { Ok(l) => l, Err(_erreur) => continue, }; if line.starts_with('|') { s = ghostleg_line(&s, &line); } } s } #[cfg(test)] mod tests { #[test] fn transposition_test() { let in_str = "ABCDEF"; assert_eq!(crate::transposition(in_str, 3), String::from("ABCEDF")); assert_eq!(crate::transposition(in_str, 0), String::from("BACDEF")); } #[test] #[should_panic] fn transposition_panic_test() { let in_str = "ABCDEF"; crate::transposition(in_str, 8); } #[test] fn ghostleg_line_test() { assert_eq!(crate::ghostleg_line("ABC", "|--| |"), String::from("BAC")); assert_eq!(crate::ghostleg_line("ABCDEF", "| |--| | |--|"), String::from("ACBDFE")); } #[test] fn get_head() { assert_eq!(crate::get_head("A B C \n"), String::from("ABC")); } } Vous noterez la présence de ''match'' un peu lourds qui sont là pour palier à toute erreur possible, notamment en cours de lecture de la prochaine ligne. J'ai trouvé sur internet le système de Buffer utilisé pour la lecture de ligne. L'objet ''Lines'' produit des item compliqué puisqu'ils sont enveloppé dans ''Option'' (soit quelque chose ''Some'', soit ''None'') et une possibilité d'erreur ''Result'' (soit ''Ok'' soi ''Err''). // src/main.rs use std::env; use ghostleg::ghostleg; fn main() { let args: Vec = env::args().collect(); if args.len() < 2 { panic!("Usage : {} filename", args[0]); } let filename = &args[1]; let s = ghostleg(filename); print!("{}\n", s); }