From 1f500522ad4cdf7465edf211fb8a240842d69c85 Mon Sep 17 00:00:00 2001 From: Peter Tseng Date: Sat, 2 Jul 2016 16:15:12 -0700 Subject: [PATCH 1/2] tournament: Put inputs/expectations inline, not in files The previous iteration of reading/writing files is a valuable experience in itself, but dilutes the focus of this exercise. We should consider an exercise dedicated to that task if necessary, as discussed in #122. Note that this preserves all behavior of existing test files. In particular, the expectation that an invalid line is ignored is preserved. If you wish for this behavior to be changed, you should discuss that at https://github.com/exercism/x-common/issues/286 before we make that change here. The function `tally` now takes only a `&str` (it previously took two `Path`, one for input and one for output) and now returns only a `String` (it previously returned a `Result` where the `Ok` counted the number of valid lines). This commit is necessary but not sufficient for the closing of #122. Points not covered by this commit but requested by #122 include: * Explain the input format. Covered by https://github.com/exercism/x-common/pull/254 * Explain behavior on invalid lines. Covered by https://github.com/exercism/x-common/issues/286 --- exercises/tournament/example.rs | 31 +++------- exercises/tournament/tests/expected1.txt | 5 -- exercises/tournament/tests/expected2.txt | 5 -- exercises/tournament/tests/expected3.txt | 5 -- exercises/tournament/tests/input1.txt | 6 -- exercises/tournament/tests/input2.txt | 11 ---- exercises/tournament/tests/input3.txt | 4 -- exercises/tournament/tests/tournament.rs | 78 +++++++++++++----------- 8 files changed, 52 insertions(+), 93 deletions(-) delete mode 100644 exercises/tournament/tests/expected1.txt delete mode 100644 exercises/tournament/tests/expected2.txt delete mode 100644 exercises/tournament/tests/expected3.txt delete mode 100644 exercises/tournament/tests/input1.txt delete mode 100644 exercises/tournament/tests/input2.txt delete mode 100644 exercises/tournament/tests/input3.txt diff --git a/exercises/tournament/example.rs b/exercises/tournament/example.rs index d244c9ad7..4a5a5bc1a 100644 --- a/exercises/tournament/example.rs +++ b/exercises/tournament/example.rs @@ -1,8 +1,5 @@ use std::cmp::Ordering::Equal; use std::collections::HashMap; -use std::fs::File; -use std::io::{BufRead, BufReader, Write, Result}; -use std::path::Path; enum GameResult { Win, @@ -29,12 +26,9 @@ impl TeamResult { } } -pub fn tally(input_filename: &Path, output_filename: &Path) -> Result { - let reader = BufReader::with_capacity(2048, File::open(input_filename).unwrap()); - let mut count = 0; +pub fn tally(input: &str) -> String { let mut results: HashMap = HashMap::new(); - for line in reader.lines() { - let line = line.unwrap(); + for line in input.to_string().lines() { let parts: Vec<&str> = line.trim_right().split(';').collect(); if parts.len() != 3 { continue; } let team1 = parts[0]; @@ -44,26 +38,22 @@ pub fn tally(input_filename: &Path, output_filename: &Path) -> Result { "win" => { add_game_result(&mut results, team1.to_string(), GameResult::Win); add_game_result(&mut results, team2.to_string(), GameResult::Loss); - count += 1; }, "draw" => { add_game_result(&mut results, team1.to_string(), GameResult::Draw); add_game_result(&mut results, team2.to_string(), GameResult::Draw); - count += 1; }, "loss" => { add_game_result(&mut results, team1.to_string(), GameResult::Loss); add_game_result(&mut results, team2.to_string(), GameResult::Win); - count += 1; }, _ => () // Ignore bad lines } } - try!(write_tally(&results, output_filename)); - Ok(count) + write_tally(&results) } -fn write_tally(results: &HashMap, output_filename: &Path) -> Result<()> { +fn write_tally(results: &HashMap) -> String { let mut v: Vec<_> = results.iter().map(|(team, r)| { let games = r.wins + r.draws + r.losses; let points = r.wins * 3 + r.draws; @@ -75,13 +65,12 @@ fn write_tally(results: &HashMap, output_filename: &Path) -> Equal => a.1.cmp(&(b.1)).reverse(), other => other }); - let mut f = try!(File::create(output_filename)); - try!(writeln!(&mut f, "{:30} | MP | W | D | L | P", "Team")); - for &(ref team, games, r, points) in v.iter() { - try!(writeln!(&mut f, "{:30} | {:2} | {:2} | {:2} | {:2} | {:2}", - team, games, r.wins, r.draws, r.losses, points)); - } - Ok(()) + let header = format!("{:30} | MP | W | D | L | P\n", "Team"); + let lines: Vec<_> = v.iter().map(|&(ref team, games, r, points)| { + format!("{:30} | {:2} | {:2} | {:2} | {:2} | {:2}", + team, games, r.wins, r.draws, r.losses, points) + }).collect(); + header + &lines.join("\n") } fn add_game_result(results: &mut HashMap, team: String, result: GameResult) { diff --git a/exercises/tournament/tests/expected1.txt b/exercises/tournament/tests/expected1.txt deleted file mode 100644 index 666e6be37..000000000 --- a/exercises/tournament/tests/expected1.txt +++ /dev/null @@ -1,5 +0,0 @@ -Team | MP | W | D | L | P -Devastating Donkeys | 3 | 2 | 1 | 0 | 7 -Allegoric Alaskians | 3 | 2 | 0 | 1 | 6 -Blithering Badgers | 3 | 1 | 0 | 2 | 3 -Courageous Californians | 3 | 0 | 1 | 2 | 1 diff --git a/exercises/tournament/tests/expected2.txt b/exercises/tournament/tests/expected2.txt deleted file mode 100644 index 666e6be37..000000000 --- a/exercises/tournament/tests/expected2.txt +++ /dev/null @@ -1,5 +0,0 @@ -Team | MP | W | D | L | P -Devastating Donkeys | 3 | 2 | 1 | 0 | 7 -Allegoric Alaskians | 3 | 2 | 0 | 1 | 6 -Blithering Badgers | 3 | 1 | 0 | 2 | 3 -Courageous Californians | 3 | 0 | 1 | 2 | 1 diff --git a/exercises/tournament/tests/expected3.txt b/exercises/tournament/tests/expected3.txt deleted file mode 100644 index 079b7a1cf..000000000 --- a/exercises/tournament/tests/expected3.txt +++ /dev/null @@ -1,5 +0,0 @@ -Team | MP | W | D | L | P -Allegoric Alaskians | 3 | 2 | 0 | 1 | 6 -Blithering Badgers | 2 | 1 | 0 | 1 | 3 -Devastating Donkeys | 1 | 1 | 0 | 0 | 3 -Courageous Californians | 2 | 0 | 0 | 2 | 0 diff --git a/exercises/tournament/tests/input1.txt b/exercises/tournament/tests/input1.txt deleted file mode 100644 index 120c625aa..000000000 --- a/exercises/tournament/tests/input1.txt +++ /dev/null @@ -1,6 +0,0 @@ -Allegoric Alaskians;Blithering Badgers;win -Devastating Donkeys;Courageous Californians;draw -Devastating Donkeys;Allegoric Alaskians;win -Courageous Californians;Blithering Badgers;loss -Blithering Badgers;Devastating Donkeys;loss -Allegoric Alaskians;Courageous Californians;win diff --git a/exercises/tournament/tests/input2.txt b/exercises/tournament/tests/input2.txt deleted file mode 100644 index a688099bb..000000000 --- a/exercises/tournament/tests/input2.txt +++ /dev/null @@ -1,11 +0,0 @@ -Allegoric Alaskians;Blithering Badgers;win -Devastating Donkeys_Courageous Californians;draw -Devastating Donkeys;Allegoric Alaskians;win - -Courageous Californians;Blithering Badgers;loss -Bla;Bla;Bla -Blithering Badgers;Devastating Donkeys;loss -# Yackity yackity yack -Allegoric Alaskians;Courageous Californians;win -Devastating Donkeys;Courageous Californians;draw -Devastating Donkeys@Courageous Californians;draw diff --git a/exercises/tournament/tests/input3.txt b/exercises/tournament/tests/input3.txt deleted file mode 100644 index a203d3303..000000000 --- a/exercises/tournament/tests/input3.txt +++ /dev/null @@ -1,4 +0,0 @@ -Allegoric Alaskians;Blithering Badgers;win -Devastating Donkeys;Allegoric Alaskians;win -Courageous Californians;Blithering Badgers;loss -Allegoric Alaskians;Courageous Californians;win diff --git a/exercises/tournament/tests/tournament.rs b/exercises/tournament/tests/tournament.rs index 88b39cfd6..c34ced5c1 100644 --- a/exercises/tournament/tests/tournament.rs +++ b/exercises/tournament/tests/tournament.rs @@ -1,51 +1,57 @@ -use std::fs::File; -use std::path::Path; -use std::io::Read; - extern crate tournament; -fn file_equal(output_file: &str, expected_file: &str) { - let output = match File::open(&Path::new(output_file)) { - Err(e) => panic!("Couldn't open {}: {}", output_file, e), - Ok(mut f) => { - let mut buf = String::new(); - match f.read_to_string(&mut buf) { - Err(e) => panic!("Couldn't read {}: {}", output_file, e), - Ok(_) => buf - } - } - }; - let expected = match File::open(&Path::new(expected_file)) { - Err(e) => panic!("Couldn't open {}: {}", expected_file, e), - Ok(mut f) => { - let mut buf = String::new(); - match f.read_to_string(&mut buf) { - Err(e) => panic!("Couldn't read {}: {}", expected_file, e), - Ok(_) => buf - } - } - }; - assert_eq!("\n".to_string() + output.as_ref(), "\n".to_string() + expected.as_ref()); - -} - - #[test] fn test_good() { - assert_eq!(tournament::tally(&Path::new("tests/input1.txt"), &Path::new("tests/output1.txt")).unwrap(), 6); - file_equal("tests/output1.txt", "tests/expected1.txt"); + let input = "Allegoric Alaskians;Blithering Badgers;win\n".to_string() + + "Devastating Donkeys;Courageous Californians;draw\n" + + "Devastating Donkeys;Allegoric Alaskians;win\n" + + "Courageous Californians;Blithering Badgers;loss\n" + + "Blithering Badgers;Devastating Donkeys;loss\n" + + "Allegoric Alaskians;Courageous Californians;win"; + let expected = "Team | MP | W | D | L | P\n".to_string() + + "Devastating Donkeys | 3 | 2 | 1 | 0 | 7\n" + + "Allegoric Alaskians | 3 | 2 | 0 | 1 | 6\n" + + "Blithering Badgers | 3 | 1 | 0 | 2 | 3\n" + + "Courageous Californians | 3 | 0 | 1 | 2 | 1"; + + assert_eq!(tournament::tally(&input), expected); } #[test] #[ignore] fn test_ignore_bad_lines() { - assert_eq!(tournament::tally(&Path::new("tests/input2.txt"), &Path::new("tests/output2.txt")).unwrap(), 6); - file_equal("tests/output2.txt", "tests/expected2.txt"); + let input = "Allegoric Alaskians;Blithering Badgers;win\n".to_string() + + "Devastating Donkeys_Courageous Californians;draw\n" + + "Devastating Donkeys;Allegoric Alaskians;win\n" + + "\n" + + "Courageous Californians;Blithering Badgers;loss\n" + + "Bla;Bla;Bla\n" + + "Blithering Badgers;Devastating Donkeys;loss\n" + + "# Yackity yackity yack\n" + + "Allegoric Alaskians;Courageous Californians;win\n" + + "Devastating Donkeys;Courageous Californians;draw\n" + + "Devastating Donkeys@Courageous Californians;draw"; + let expected = "Team | MP | W | D | L | P\n".to_string() + + "Devastating Donkeys | 3 | 2 | 1 | 0 | 7\n" + + "Allegoric Alaskians | 3 | 2 | 0 | 1 | 6\n" + + "Blithering Badgers | 3 | 1 | 0 | 2 | 3\n" + + "Courageous Californians | 3 | 0 | 1 | 2 | 1"; + + assert_eq!(tournament::tally(&input), expected); } #[test] #[ignore] fn test_incomplete_competition() { - assert_eq!(tournament::tally(&Path::new("tests/input3.txt"), &Path::new("tests/output3.txt")).unwrap(), 4); - file_equal("tests/output3.txt", "tests/expected3.txt"); + let input = "Allegoric Alaskians;Blithering Badgers;win\n".to_string() + + "Devastating Donkeys;Allegoric Alaskians;win\n" + + "Courageous Californians;Blithering Badgers;loss\n" + + "Allegoric Alaskians;Courageous Californians;win"; + let expected = "Team | MP | W | D | L | P\n".to_string() + + "Allegoric Alaskians | 3 | 2 | 0 | 1 | 6\n" + + "Blithering Badgers | 2 | 1 | 0 | 1 | 3\n" + + "Devastating Donkeys | 1 | 1 | 0 | 0 | 3\n" + + "Courageous Californians | 2 | 0 | 0 | 2 | 0"; + + assert_eq!(tournament::tally(&input), expected); } From 5fd2b6df8ad4ffaab98a01b3e29a81ef87b2c082 Mon Sep 17 00:00:00 2001 From: Peter Tseng Date: Mon, 4 Jul 2016 22:06:24 -0700 Subject: [PATCH 2/2] config: Move tournament -> between grade-school and robot-simulator With the removal of the file I/O portion of this exercise (via the previous commit and through discussion in #122) now this exercise becomes easier and can be moved. The list of skills are now roughly: string parsing, string formatting, custom sorting. Also HashMap usage seems natural, as you want to store the results of each team. Moving it to after grade-school, another problem that may see HashMap in its solution. --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 5e3b91fc9..328573d17 100644 --- a/config.json +++ b/config.json @@ -22,6 +22,7 @@ "roman-numerals", "hexadecimal", "grade-school", + "tournament", "robot-simulator", "queen-attack", "sublist", @@ -35,7 +36,6 @@ "minesweeper", "dominoes", "parallel-letter-frequency", - "tournament", "rectangles", "forth", "circular-buffer"