Re-do dictionary, fix bug in word-finding
This commit is contained in:
parent
6f14579f3a
commit
37fe5bac56
1 changed files with 125 additions and 64 deletions
189
src/lib.rs
189
src/lib.rs
|
@ -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);
|
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'
|
// 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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue