Re-do dictionary, fix bug in word-finding

This commit is contained in:
Joel Therrien 2023-07-30 12:57:36 -07:00
parent 6f14579f3a
commit 37fe5bac56

View file

@ -1,4 +1,4 @@
use std::collections::HashSet; use std::collections::{HashMap, HashSet};
use std::fmt; use std::fmt;
use std::fmt::{Formatter, Write}; use std::fmt::{Formatter, Write};
use std::str::FromStr; use std::str::FromStr;
@ -87,50 +87,50 @@ pub struct Cell {
coordinates: Coordinates, coordinates: Coordinates,
} }
trait Dictionary {
pub struct Dictionary { fn create(path: &str) -> Self;
words: Vec<String>, fn filter_to_sub_dictionary(&self, proportion: f64) -> Self;
scores: Vec<f64>, fn substring_set(&self) -> HashSet<&str>;
fn is_word_valid(&self, word: &Word) -> bool;
} }
impl Dictionary { impl Dictionary for HashMap<String, f64> {
fn new() -> Self {
let mut reader = csv::Reader::from_path("resources/dictionary.csv").unwrap(); fn create(path: &str) -> Self {
let mut words: Vec<String> = Vec::new(); let mut reader = csv::Reader::from_path(path).unwrap();
let mut scores: Vec<f64> = Vec::new(); let mut map = HashMap::new();
for result in reader.records() { for result in reader.records() {
let record = result.unwrap(); 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(); 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 { map
words,
scores,
}
} }
fn filter_to_sub_dictionary(&self, proportion: f64) -> Self { fn filter_to_sub_dictionary(&self, proportion: f64) -> Self {
let mut words: Vec<String> = Vec::new(); let mut map = HashMap::new();
let mut scores: Vec<f64> = Vec::new();
for (word, score) in self.words.iter().zip(self.scores.iter()) { for (word, score) in self.iter() {
if *score >= proportion { if *score >= proportion {
words.push(word.clone()); map.insert(word.clone(), *score);
scores.push(*score);
} }
} }
Dictionary {words, scores} map
} }
fn substring_set(&self) -> HashSet<&str> { fn substring_set(&self) -> HashSet<&str> {
let mut set = HashSet::new(); let mut set = HashSet::new();
for word in self.words.iter() { for (word, _score) in self.iter() {
for j in 0..word.len() { for j in 0..word.len() {
for k in (j+1)..(word.len()+1) { for k in (j+1)..(word.len()+1) {
set.insert(&word[j..k]); set.insert(&word[j..k]);
@ -142,7 +142,11 @@ impl Dictionary {
set set
} }
fn is_word_valid(&self, word: &Word) -> bool {
todo!()
}
} }
@ -156,6 +160,18 @@ struct Word<'a> {
coords: Coordinates, 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> { impl <'a> Word<'a> {
fn calculate_score(&self) -> u32{ fn calculate_score(&self) -> u32{
@ -368,8 +384,15 @@ impl Board {
return Err("Played tiles cannot have empty gap"); 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' // need to verify that the play is 'anchored'
let mut anchored = false; 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(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)); 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] { for x in vec![6, 7, 8, 9] {
println!("x is {}", x); println!("x is {}", x);
let first_word = board.find_word_at_position(Coordinates(8, x), Direction::Column); 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.0, 8);
assert_eq!(x.coords.1, 6); 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.0, 8);
assert_eq!(x.coords.1, 9); 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.0, 0);
assert_eq!(x.coords.1, 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.0, 3);
assert_eq!(x.coords.1, 0); 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.0, 8);
assert_eq!(x.coords.1, 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] #[test]
fn test_word_finding_anchor() { fn test_word_finding_anchor() {
let mut board = Board::new(); 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(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)); 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) { fn check_board(board: &mut Board, inverted: bool) {
println!("{}", board); println!("{}", board);
let words = board.find_played_words(); let words = board.find_played_words();
@ -757,7 +819,7 @@ mod tests {
Ok(x) => { Ok(x) => {
assert_eq!(x.len(), 1); assert_eq!(x.len(), 1);
let word = x.get(0).unwrap(); 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); 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.0, 8);
assert_eq!(x.coords.1, 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); assert_eq!(x.calculate_score(), 2 + 2 + 2);
} }
@ -799,11 +861,11 @@ mod tests {
Ok(x) => { Ok(x) => {
assert_eq!(x.len(), 2); assert_eq!(x.len(), 2);
let word = x.get(0).unwrap(); 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); assert_eq!(word.calculate_score(), 2 + 2 + 2);
let word = x.get(1).unwrap(); 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); assert_eq!(word.calculate_score(), 8 + 1 + 2 + 1);
} }
Err(e) => { panic!("Expected to find a word to play; found error {}", e) } Err(e) => { panic!("Expected to find a word to play; found error {}", e) }
@ -847,29 +909,28 @@ mod tests {
#[test] #[test]
fn test_dictionary() { 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.len(), 279429);
assert_eq!(dictionary.words.len(), 279429);
assert_eq!(dictionary.words.get(0).unwrap(), "AA"); assert!(dictionary.contains_key("AA"));
assert_eq!(dictionary.words.get(9).unwrap(), "AARDVARK"); 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] #[test]
fn test_dictionary_sets() { fn test_dictionary_sets() {
let dictionary = Dictionary { let mut dictionary = HashMap::new();
words: vec!["JOEL".to_string(), "JOHN".to_string(), "XYZ".to_string()], dictionary.insert("JOEL".to_string(), 0.7);
scores: vec![0.7, 0.5, 0.1], dictionary.insert("JOHN".to_string(), 0.5);
}; dictionary.insert("XYZ".to_string(), 0.1);
let dictionary = dictionary.filter_to_sub_dictionary(0.3); let dictionary = dictionary.filter_to_sub_dictionary(0.3);
assert_eq!(dictionary.words.len(), 2); assert_eq!(dictionary.len(), 2);
assert_eq!(dictionary.words.get(0).unwrap(), "JOEL"); assert!(dictionary.contains_key("JOEL"));
assert_eq!(dictionary.words.get(1).unwrap(), "JOHN"); assert!(dictionary.contains_key("JOHN"));
let set = dictionary.substring_set(); let set = dictionary.substring_set();