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::{Formatter, Write};
use std::str::FromStr;
@ -87,50 +87,50 @@ pub struct Cell {
coordinates: Coordinates,
}
pub struct Dictionary {
words: Vec<String>,
scores: Vec<f64>,
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<String> = Vec::new();
let mut scores: Vec<f64> = Vec::new();
impl Dictionary for HashMap<String, f64> {
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<String> = Vec::new();
let mut scores: Vec<f64> = 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");
}
// 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();