diff --git a/src/lib.rs b/src/lib.rs index 4aeea9c..739c26a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::fmt; use std::fmt::{Formatter, Write}; use std::str::FromStr; @@ -87,50 +87,50 @@ pub struct Cell { coordinates: Coordinates, } - -pub struct Dictionary { - words: Vec, - scores: Vec, +trait Dictionary { + fn create(path: &str) -> Self; + fn filter_to_sub_dictionary(&self, proportion: f64) -> Self; + fn substring_set(&self) -> HashSet<&str>; + fn is_word_valid(&self, word: &Word) -> bool; } -impl Dictionary { - fn new() -> Self { - let mut reader = csv::Reader::from_path("resources/dictionary.csv").unwrap(); - let mut words: Vec = Vec::new(); - let mut scores: Vec = Vec::new(); +impl Dictionary for HashMap { + + fn create(path: &str) -> Self { + let mut reader = csv::Reader::from_path(path).unwrap(); + let mut map = HashMap::new(); for result in reader.records() { let record = result.unwrap(); - words.push(record.get(0).unwrap().to_string()); + let word = record.get(0).unwrap().to_string(); + let score = record.get(1).unwrap(); - scores.push(f64::from_str(score).unwrap()); + let score = f64::from_str(score).unwrap(); + + map.insert(word, score); } - Dictionary { - words, - scores, - } + map } fn filter_to_sub_dictionary(&self, proportion: f64) -> Self { - let mut words: Vec = Vec::new(); - let mut scores: Vec = Vec::new(); + let mut map = HashMap::new(); - for (word, score) in self.words.iter().zip(self.scores.iter()) { + for (word, score) in self.iter() { if *score >= proportion { - words.push(word.clone()); - scores.push(*score); + map.insert(word.clone(), *score); } } - Dictionary {words, scores} + map + } fn substring_set(&self) -> HashSet<&str> { let mut set = HashSet::new(); - for word in self.words.iter() { + for (word, _score) in self.iter() { for j in 0..word.len() { for k in (j+1)..(word.len()+1) { set.insert(&word[j..k]); @@ -142,7 +142,11 @@ impl Dictionary { set } + fn is_word_valid(&self, word: &Word) -> bool { + + todo!() + } } @@ -156,6 +160,18 @@ struct Word<'a> { coords: Coordinates, } +impl<'a> ToString for Word<'a> { + fn to_string(&self) -> String { + let mut text = String::with_capacity(self.cells.len()); + for cell in self.cells.as_slice() { + text.push(cell.value.as_ref().unwrap().text); + } + + text + + } +} + impl <'a> Word<'a> { fn calculate_score(&self) -> u32{ @@ -368,8 +384,15 @@ impl Board { return Err("Played tiles cannot have empty gap"); } + // don't want the case of a single letter word + if main_word.cells.len() > 1 { + words.push(main_word); + } else if words.is_empty() { + return Err("All words must be at least one letter"); + } + + - words.push(main_word); // need to verify that the play is 'anchored' let mut anchored = false; @@ -552,15 +575,6 @@ mod tests { board.get_cell_mut(Coordinates(9, 8)).unwrap().value = Some(Letter::new_fixed( 'G', 0)); board.get_cell_mut(Coordinates(10, 8)).unwrap().value = Some(Letter::new_fixed( 'G', 0)); - fn word_to_text(word: Word) -> String { - let mut text = String::with_capacity(word.cells.len()); - for cell in word.cells { - text.push(cell.value.as_ref().unwrap().text); - } - - text - } - for x in vec![6, 7, 8, 9] { println!("x is {}", x); let first_word = board.find_word_at_position(Coordinates(8, x), Direction::Column); @@ -570,7 +584,7 @@ mod tests { assert_eq!(x.coords.0, 8); assert_eq!(x.coords.1, 6); - assert_eq!(word_to_text(x), "JOEL"); + assert_eq!(x.to_string(), "JOEL"); } } @@ -583,7 +597,7 @@ mod tests { assert_eq!(x.coords.0, 8); assert_eq!(x.coords.1, 9); - assert_eq!(word_to_text(x), "L"); + assert_eq!(x.to_string(), "L"); } } @@ -596,7 +610,7 @@ mod tests { assert_eq!(x.coords.0, 0); assert_eq!(x.coords.1, 0); - assert_eq!(word_to_text(x), "IS"); + assert_eq!(x.to_string(), "IS"); } } @@ -611,7 +625,7 @@ mod tests { assert_eq!(x.coords.0, 3); assert_eq!(x.coords.1, 0); - assert_eq!(word_to_text(x), "COOL"); + assert_eq!(x.to_string(), "COOL"); } } @@ -627,7 +641,7 @@ mod tests { assert_eq!(x.coords.0, 8); assert_eq!(x.coords.1, 8); - assert_eq!(word_to_text(x), "EGG"); + assert_eq!(x.to_string(), "EGG"); } } @@ -636,6 +650,63 @@ mod tests { } + #[test] + fn test_word_finding_one_letter() { + let mut board = Board::new(); + + board.get_cell_mut(Coordinates(7, 7)).unwrap().value = Some(Letter { + text: 'I', + points: 1, + ephemeral: true, + is_blank: false, + }); + + match board.find_played_words() { + Ok(_) => {panic!("Expected error")} + Err(e) => {assert_eq!(e, "All words must be at least one letter");} + } + + board.get_cell_mut(Coordinates(7, 7)).unwrap().value = Some(Letter { + text: 'I', + points: 1, + ephemeral: false, // fixed now + is_blank: false, + }); + + board.get_cell_mut(Coordinates(7, 8)).unwrap().value = Some(Letter { + text: 'S', + points: 1, + ephemeral: true, + is_blank: false, + }); + + let words = board.find_played_words().unwrap(); + assert_eq!(words.len(), 1); + let word = words.first().unwrap(); + assert_eq!(word.calculate_score(), 2); + + // making fixed + board.get_cell_mut(Coordinates(7, 8)).unwrap().value = Some(Letter { + text: 'S', + points: 1, + ephemeral: false, + is_blank: false, + }); + + // trying other orientation + board.get_cell_mut(Coordinates(8, 7)).unwrap().value = Some(Letter { + text: 'S', + points: 1, + ephemeral: true, + is_blank: false, + }); + + let words = board.find_played_words().unwrap(); + assert_eq!(words.len(), 1); + let word = words.first().unwrap(); + assert_eq!(word.calculate_score(), 2); + } + #[test] fn test_word_finding_anchor() { let mut board = Board::new(); @@ -741,15 +812,6 @@ mod tests { board.get_cell_mut(Coordinates(5, 0)).unwrap().value = Some(Letter::new_fixed('O', 1)); board.get_cell_mut(Coordinates(6, 0)).unwrap().value = Some(Letter::new_fixed('L', 1)); - fn word_to_text(word: &Word) -> String { - let mut text = String::with_capacity(word.cells.len()); - for cell in word.cells.as_slice() { - text.push(cell.value.as_ref().unwrap().text); - } - - text - } - fn check_board(board: &mut Board, inverted: bool) { println!("{}", board); let words = board.find_played_words(); @@ -757,7 +819,7 @@ mod tests { Ok(x) => { assert_eq!(x.len(), 1); let word = x.get(0).unwrap(); - assert_eq!(word_to_text(word), "JOEL"); + assert_eq!(word.to_string(), "JOEL"); assert_eq!(word.calculate_score(), 8 + 1 + 2 + 1); } @@ -788,7 +850,7 @@ mod tests { assert_eq!(x.coords.0, 8); assert_eq!(x.coords.1, 8); - assert_eq!(word_to_text(&x), "EGG"); + assert_eq!(x.to_string(), "EGG"); assert_eq!(x.calculate_score(), 2 + 2 + 2); } @@ -799,11 +861,11 @@ mod tests { Ok(x) => { assert_eq!(x.len(), 2); let word = x.get(0).unwrap(); - assert_eq!(word_to_text(word), "EGG"); + assert_eq!(word.to_string(), "EGG"); assert_eq!(word.calculate_score(), 2 + 2 + 2); let word = x.get(1).unwrap(); - assert_eq!(word_to_text(word), "JOEL"); + assert_eq!(word.to_string(), "JOEL"); assert_eq!(word.calculate_score(), 8 + 1 + 2 + 1); } Err(e) => { panic!("Expected to find a word to play; found error {}", e) } @@ -847,29 +909,28 @@ mod tests { #[test] fn test_dictionary() { - let dictionary = Dictionary::new(); + let dictionary = HashMap::create("resources/dictionary.csv"); - assert_eq!(dictionary.words.len(), dictionary.scores.len()); - assert_eq!(dictionary.words.len(), 279429); + assert_eq!(dictionary.len(), 279429); - assert_eq!(dictionary.words.get(0).unwrap(), "AA"); - assert_eq!(dictionary.words.get(9).unwrap(), "AARDVARK"); + assert!(dictionary.contains_key("AA")); + assert!(dictionary.contains_key("AARDVARK")); - assert!((dictionary.scores.get(9).unwrap() - 0.5798372).abs() < 0.0001) + assert!((dictionary.get("AARDVARK").unwrap() - 0.5798372).abs() < 0.0001) } #[test] fn test_dictionary_sets() { - let dictionary = Dictionary { - words: vec!["JOEL".to_string(), "JOHN".to_string(), "XYZ".to_string()], - scores: vec![0.7, 0.5, 0.1], - }; + let mut dictionary = HashMap::new(); + dictionary.insert("JOEL".to_string(), 0.7); + dictionary.insert("JOHN".to_string(), 0.5); + dictionary.insert("XYZ".to_string(), 0.1); let dictionary = dictionary.filter_to_sub_dictionary(0.3); - assert_eq!(dictionary.words.len(), 2); - assert_eq!(dictionary.words.get(0).unwrap(), "JOEL"); - assert_eq!(dictionary.words.get(1).unwrap(), "JOHN"); + assert_eq!(dictionary.len(), 2); + assert!(dictionary.contains_key("JOEL")); + assert!(dictionary.contains_key("JOHN")); let set = dictionary.substring_set();