2023-07-30 19:57:36 +00:00
|
|
|
use std::collections::{HashMap, HashSet};
|
2023-07-22 23:43:49 +00:00
|
|
|
use std::fmt;
|
|
|
|
use std::fmt::{Formatter, Write};
|
2023-07-25 02:50:40 +00:00
|
|
|
use std::str::FromStr;
|
2023-07-22 23:43:49 +00:00
|
|
|
|
|
|
|
pub const GRID_LENGTH: u8 = 15;
|
|
|
|
pub const TRAY_LENGTH: u8 = 7;
|
|
|
|
pub const ALL_LETTERS_BONUS: u32 = 50;
|
2023-07-22 03:18:06 +00:00
|
|
|
|
2023-07-28 04:25:50 +00:00
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
enum Direction {
|
|
|
|
Row, Column
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Direction {
|
|
|
|
fn invert(&self) -> Self {
|
|
|
|
match &self {
|
|
|
|
Direction::Row => {Direction::Column}
|
|
|
|
Direction::Column => {Direction::Row}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub struct Coordinates (pub u8, pub u8);
|
|
|
|
|
|
|
|
impl Coordinates {
|
|
|
|
fn add(&self, direction: Direction, i: i8) -> Option<Self> {
|
|
|
|
let proposed = match direction {
|
|
|
|
Direction::Column => {(self.0 as i8, self.1 as i8+i)}
|
|
|
|
Direction::Row => {(self.0 as i8+i, self.1 as i8)}
|
|
|
|
};
|
|
|
|
|
|
|
|
if proposed.0 < 0 || proposed.0 >= GRID_LENGTH as i8 || proposed.1 < 0 || proposed.1 >= GRID_LENGTH as i8 {
|
|
|
|
None
|
|
|
|
} else{
|
|
|
|
Some(Coordinates(proposed.0 as u8, proposed.1 as u8))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn increment(&self, direction: Direction) -> Option<Self>{
|
|
|
|
self.add(direction, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn decrement(&self, direction: Direction) -> Option<Self>{
|
|
|
|
self.add(direction, -1)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn map_to_index(&self) -> usize {
|
|
|
|
(self.0 + GRID_LENGTH*self.1) as usize
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-29 04:53:01 +00:00
|
|
|
#[derive(Debug, Copy, Clone)]
|
2023-07-28 04:25:50 +00:00
|
|
|
pub struct Letter {
|
|
|
|
text: char,
|
|
|
|
points: u32,
|
|
|
|
ephemeral: bool,
|
|
|
|
is_blank: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Letter {
|
|
|
|
pub fn new_fixed(text: char, points: u32) -> Self {
|
|
|
|
Letter {
|
|
|
|
text,
|
|
|
|
points,
|
|
|
|
ephemeral: false,
|
|
|
|
is_blank: false,
|
|
|
|
}
|
|
|
|
}
|
2023-07-22 03:18:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2023-07-22 23:43:49 +00:00
|
|
|
pub enum CellType {
|
2023-07-22 03:18:06 +00:00
|
|
|
Normal,
|
|
|
|
DoubleWord,
|
|
|
|
DoubleLetter,
|
|
|
|
TripleLetter,
|
|
|
|
TripleWord,
|
|
|
|
Start,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2023-07-22 23:43:49 +00:00
|
|
|
pub struct Cell {
|
|
|
|
pub value: Option<Letter>,
|
2023-07-22 03:18:06 +00:00
|
|
|
cell_type: CellType,
|
2023-07-28 04:25:50 +00:00
|
|
|
coordinates: Coordinates,
|
2023-07-22 03:18:06 +00:00
|
|
|
}
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
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;
|
2023-07-25 02:50:40 +00:00
|
|
|
}
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
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();
|
2023-07-25 02:50:40 +00:00
|
|
|
|
|
|
|
for result in reader.records() {
|
|
|
|
let record = result.unwrap();
|
2023-07-30 19:57:36 +00:00
|
|
|
let word = record.get(0).unwrap().to_string();
|
|
|
|
|
2023-07-25 02:50:40 +00:00
|
|
|
let score = record.get(1).unwrap();
|
2023-07-30 19:57:36 +00:00
|
|
|
let score = f64::from_str(score).unwrap();
|
2023-07-25 02:50:40 +00:00
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
map.insert(word, score);
|
2023-07-25 02:50:40 +00:00
|
|
|
|
|
|
|
}
|
2023-07-30 19:57:36 +00:00
|
|
|
|
|
|
|
map
|
2023-07-25 02:50:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn filter_to_sub_dictionary(&self, proportion: f64) -> Self {
|
2023-07-30 19:57:36 +00:00
|
|
|
let mut map = HashMap::new();
|
2023-07-25 02:50:40 +00:00
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
for (word, score) in self.iter() {
|
2023-07-25 02:50:40 +00:00
|
|
|
if *score >= proportion {
|
2023-07-30 19:57:36 +00:00
|
|
|
map.insert(word.clone(), *score);
|
2023-07-25 02:50:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
map
|
|
|
|
|
2023-07-25 02:50:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn substring_set(&self) -> HashSet<&str> {
|
|
|
|
let mut set = HashSet::new();
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
for (word, _score) in self.iter() {
|
2023-07-25 02:50:40 +00:00
|
|
|
for j in 0..word.len() {
|
|
|
|
for k in (j+1)..(word.len()+1) {
|
|
|
|
set.insert(&word[j..k]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
set
|
|
|
|
}
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
fn is_word_valid(&self, word: &Word) -> bool {
|
2023-07-30 20:00:01 +00:00
|
|
|
let text = word.to_string();
|
|
|
|
self.contains_key(&text)
|
2023-07-30 19:57:36 +00:00
|
|
|
}
|
2023-07-25 02:50:40 +00:00
|
|
|
}
|
|
|
|
|
2023-07-22 03:18:06 +00:00
|
|
|
|
2023-07-28 04:25:50 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Board {
|
|
|
|
cells: Vec<Cell>,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Word<'a> {
|
|
|
|
cells: Vec<&'a Cell>,
|
|
|
|
coords: Coordinates,
|
|
|
|
}
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-30 00:31:55 +00:00
|
|
|
impl <'a> Word<'a> {
|
|
|
|
|
|
|
|
fn calculate_score(&self) -> u32{
|
|
|
|
let mut multiplier = 1;
|
|
|
|
let mut unmultiplied_score = 0;
|
|
|
|
|
|
|
|
for cell in self.cells.as_slice() {
|
|
|
|
let cell_value = cell.value.unwrap();
|
|
|
|
if cell_value.ephemeral {
|
|
|
|
let cell_multiplier =
|
|
|
|
match cell.cell_type {
|
|
|
|
CellType::Normal => {1}
|
|
|
|
CellType::DoubleWord => {
|
|
|
|
multiplier *= 2;
|
|
|
|
1
|
|
|
|
}
|
|
|
|
CellType::DoubleLetter => {2}
|
|
|
|
CellType::TripleLetter => {3}
|
|
|
|
CellType::TripleWord => {
|
|
|
|
multiplier *= 3;
|
|
|
|
1
|
|
|
|
}
|
|
|
|
CellType::Start => {
|
|
|
|
multiplier *= 2;
|
|
|
|
1
|
|
|
|
}
|
|
|
|
};
|
|
|
|
unmultiplied_score += cell_value.points * cell_multiplier;
|
|
|
|
} else {
|
|
|
|
// no cell multiplier unfortunately
|
|
|
|
unmultiplied_score += cell_value.points;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unmultiplied_score * multiplier
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-22 03:18:06 +00:00
|
|
|
impl Board {
|
2023-07-22 23:43:49 +00:00
|
|
|
pub fn new() -> Self {
|
2023-07-22 03:18:06 +00:00
|
|
|
let mut cells = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
/// Since the board is symmetrical in both directions for the purposes of our logic we can keep our coordinates in one corner
|
|
|
|
///
|
|
|
|
/// # Arguments
|
|
|
|
///
|
|
|
|
/// * `x`: A coordinate
|
|
|
|
///
|
|
|
|
/// returns: u8 The coordinate mapped onto the lower-half
|
|
|
|
fn map_to_corner(x: u8) -> u8 {
|
|
|
|
return if x > GRID_LENGTH / 2 {
|
|
|
|
GRID_LENGTH - x - 1
|
|
|
|
} else {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-28 04:25:50 +00:00
|
|
|
for i_orig in 0..GRID_LENGTH {
|
|
|
|
let i = map_to_corner(i_orig);
|
|
|
|
for j_orig in 0..GRID_LENGTH {
|
|
|
|
let j = map_to_corner(j_orig);
|
2023-07-22 03:18:06 +00:00
|
|
|
|
|
|
|
let mut typee = CellType::Normal;
|
|
|
|
|
|
|
|
// double word scores are diagonals
|
|
|
|
if i == j {
|
|
|
|
typee = CellType::DoubleWord;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Triple letters
|
|
|
|
if (i % 4 == 1) && j % 4 == 1 && !(i == 1 && j == 1) {
|
|
|
|
typee = CellType::TripleLetter;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Double letters
|
|
|
|
if (i % 4 == 2) && (j % 4 == 2) && !(
|
|
|
|
i == 2 && j == 2
|
|
|
|
) {
|
|
|
|
typee = CellType::DoubleLetter;
|
|
|
|
}
|
|
|
|
if (i.min(j) == 0 && i.max(j) == 3) || (i.min(j)==3 && i.max(j) == 7) {
|
|
|
|
typee = CellType::DoubleLetter;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Triple word scores
|
|
|
|
if (i % 7 == 0) && (j % 7 == 0) {
|
|
|
|
typee = CellType::TripleWord;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start
|
|
|
|
if i == 7 && j == 7 {
|
|
|
|
typee = CellType::Start;
|
|
|
|
}
|
|
|
|
|
|
|
|
cells.push(Cell {
|
|
|
|
cell_type: typee,
|
|
|
|
value: None,
|
2023-07-29 04:53:01 +00:00
|
|
|
coordinates: Coordinates(j_orig, i_orig),
|
2023-07-22 03:18:06 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Board {cells}
|
|
|
|
}
|
|
|
|
|
2023-07-28 04:25:50 +00:00
|
|
|
pub fn get_cell(&self, coordinates: Coordinates) -> Result<&Cell, &str> {
|
|
|
|
if coordinates.0 >= GRID_LENGTH || coordinates.1 >= GRID_LENGTH {
|
2023-07-22 03:18:06 +00:00
|
|
|
Err("x & y must be within the board's coordinates")
|
|
|
|
} else {
|
2023-07-28 04:25:50 +00:00
|
|
|
let index = coordinates.map_to_index();
|
|
|
|
Ok(self.cells.get(index).unwrap())
|
2023-07-22 03:18:06 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-22 23:43:49 +00:00
|
|
|
|
2023-07-28 04:25:50 +00:00
|
|
|
pub fn get_cell_mut(&mut self, coordinates: Coordinates) -> Result<&mut Cell, &str> {
|
|
|
|
if coordinates.0 >= GRID_LENGTH || coordinates.1 >= GRID_LENGTH {
|
2023-07-22 23:43:49 +00:00
|
|
|
Err("x & y must be within the board's coordinates")
|
|
|
|
} else {
|
2023-07-28 04:25:50 +00:00
|
|
|
let index = coordinates.map_to_index();
|
|
|
|
Ok(self.cells.get_mut(index).unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-30 00:31:55 +00:00
|
|
|
/*
|
|
|
|
fn calculate_scores(&self, dictionary: &Dictionary) -> Result<(Vec<(Word, u32)>, u32), &str> {
|
|
|
|
let words = self.find_played_words()?;
|
|
|
|
let mut words_and_scores = Vec::new();
|
|
|
|
let mut total_score = 0;
|
|
|
|
|
|
|
|
for word in words {
|
|
|
|
let mut word_score = 0;
|
|
|
|
let mut word_multiplier = 1;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
todo!()
|
|
|
|
}*/
|
|
|
|
|
2023-07-29 04:53:01 +00:00
|
|
|
fn find_played_words(&self) -> Result<Vec<Word>, &str> {
|
2023-07-28 04:25:50 +00:00
|
|
|
// We don't assume that the move is valid, so let's first establish that
|
|
|
|
|
|
|
|
|
|
|
|
// Let's first establish what rows and columns tiles were played in
|
|
|
|
let mut rows_played = HashSet::with_capacity(15);
|
|
|
|
let mut columns_played = HashSet::with_capacity(15);
|
|
|
|
let mut tiles_played = 0;
|
|
|
|
|
|
|
|
for x in 0..GRID_LENGTH {
|
|
|
|
for y in 0..GRID_LENGTH {
|
|
|
|
let coords = Coordinates(x, y);
|
|
|
|
let cell = self.get_cell(coords).unwrap();
|
|
|
|
match &cell.value {
|
|
|
|
Some(value) => {
|
|
|
|
if value.ephemeral {
|
|
|
|
rows_played.insert(x);
|
|
|
|
columns_played.insert(y);
|
|
|
|
tiles_played += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if rows_played.is_empty() {
|
|
|
|
return Err("Tiles need to be played")
|
|
|
|
} else if rows_played.len() > 1 && columns_played.len() > 1 {
|
|
|
|
return Err("Tiles need to be played on one row or column")
|
|
|
|
}
|
|
|
|
|
|
|
|
let direction = if rows_played.len() > 1 {
|
|
|
|
Direction::Row
|
2023-07-29 04:53:01 +00:00
|
|
|
} else {
|
|
|
|
Direction::Column
|
2023-07-28 04:25:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let starting_row = *rows_played.iter().min().unwrap();
|
|
|
|
let starting_column = *columns_played.iter().min().unwrap();
|
|
|
|
|
|
|
|
let mut starting_coords = Coordinates(starting_row, starting_column);
|
2023-07-29 04:53:01 +00:00
|
|
|
let main_word = self.find_word_at_position(starting_coords, direction).unwrap();
|
2023-07-28 04:25:50 +00:00
|
|
|
|
2023-07-29 04:53:01 +00:00
|
|
|
starting_coords = main_word.coords;
|
2023-07-28 04:25:50 +00:00
|
|
|
|
2023-07-29 04:53:01 +00:00
|
|
|
let mut words = Vec::new();
|
2023-07-30 00:31:55 +00:00
|
|
|
let mut observed_tiles_played = 0;
|
2023-07-28 04:25:50 +00:00
|
|
|
|
|
|
|
// At this point we now know that we're at the start of the word and we have the direction.
|
|
|
|
// Now we'll head forward and look for every word that intersects one of the played tiles
|
2023-07-29 04:53:01 +00:00
|
|
|
for cell in main_word.cells.as_slice() {
|
|
|
|
if cell.value.as_ref().unwrap().ephemeral {
|
2023-07-30 00:31:55 +00:00
|
|
|
observed_tiles_played += 1;
|
2023-07-29 04:53:01 +00:00
|
|
|
let side_word = self.find_word_at_position(cell.coordinates, direction.invert());
|
|
|
|
match side_word {
|
|
|
|
None => {}
|
|
|
|
Some(side_word) => {
|
|
|
|
if side_word.cells.len() > 1 {
|
|
|
|
words.push(side_word);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-07-28 04:25:50 +00:00
|
|
|
|
2023-07-30 00:31:55 +00:00
|
|
|
// there are tiles not part of the main word
|
|
|
|
if observed_tiles_played != tiles_played {
|
|
|
|
return Err("Played tiles cannot have empty gap");
|
|
|
|
}
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
// 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");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-07-28 04:25:50 +00:00
|
|
|
|
|
|
|
|
2023-07-30 00:31:55 +00:00
|
|
|
// need to verify that the play is 'anchored'
|
|
|
|
let mut anchored = false;
|
|
|
|
'outer: for word in words.as_slice() {
|
|
|
|
for cell in word.cells.as_slice() {
|
|
|
|
// either one of the letters
|
|
|
|
if !cell.value.as_ref().unwrap().ephemeral || (cell.coordinates.0 == GRID_LENGTH / 2 && cell.coordinates.1 == GRID_LENGTH / 2){
|
|
|
|
anchored = true;
|
|
|
|
break 'outer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if anchored {
|
|
|
|
Ok(words)
|
|
|
|
} else {
|
|
|
|
return Err("Played tiles must be anchored to something")
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-07-28 04:25:50 +00:00
|
|
|
}
|
|
|
|
|
2023-07-29 04:53:01 +00:00
|
|
|
fn find_word_at_position(&self, mut start_coords: Coordinates, direction: Direction) -> Option<Word> {
|
2023-07-28 04:25:50 +00:00
|
|
|
// let's see how far we can backtrack to the start of the word
|
|
|
|
let mut times_moved = 0;
|
|
|
|
loop {
|
|
|
|
let one_back = start_coords.add(direction, -times_moved);
|
|
|
|
match one_back {
|
|
|
|
None => { break }
|
|
|
|
Some(new_coords) => {
|
|
|
|
let cell = self.get_cell(new_coords).unwrap();
|
|
|
|
if cell.value.is_some(){
|
|
|
|
times_moved += 1;
|
|
|
|
} else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if times_moved == 0 {
|
|
|
|
return None;
|
2023-07-22 23:43:49 +00:00
|
|
|
}
|
2023-07-28 04:25:50 +00:00
|
|
|
|
|
|
|
start_coords = start_coords.add(direction, -times_moved + 1).unwrap();
|
|
|
|
|
|
|
|
// since we moved and we know that start_coords has started on a letter, we know we have a word
|
|
|
|
// we'll now keep track of the cells that form it
|
|
|
|
let mut cells = Vec::with_capacity(GRID_LENGTH as usize);
|
|
|
|
cells.push(self.get_cell(start_coords).unwrap());
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let position = start_coords.add(direction, cells.len() as i8);
|
|
|
|
match position {
|
|
|
|
None => {break}
|
|
|
|
Some(x) => {
|
|
|
|
let cell = self.get_cell(x).unwrap();
|
|
|
|
match cell.value {
|
|
|
|
None => {break}
|
|
|
|
Some(_) => {
|
|
|
|
cells.push(cell);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(Word {
|
|
|
|
cells,
|
|
|
|
coords: start_coords,
|
|
|
|
})
|
2023-07-22 23:43:49 +00:00
|
|
|
}
|
2023-07-28 04:25:50 +00:00
|
|
|
|
|
|
|
|
2023-07-22 23:43:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Board {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
|
|
|
|
|
|
let mut str = String::new();
|
|
|
|
|
|
|
|
let normal = "\x1b[48;5;174m\x1b[38;5;0m";
|
|
|
|
let triple_word = "\x1b[48;5;196m\x1b[38;5;0m";
|
|
|
|
let double_word = "\x1b[48;5;204m\x1b[38;5;0m";
|
|
|
|
let triple_letter = "\x1b[48;5;21m\x1b[38;5;15m";
|
|
|
|
let double_letter = "\x1b[48;5;51m\x1b[38;5;0m";
|
|
|
|
str.write_char('\n').unwrap();
|
|
|
|
|
|
|
|
for x in 0..GRID_LENGTH {
|
|
|
|
for y in 0..GRID_LENGTH {
|
2023-07-28 04:25:50 +00:00
|
|
|
let coords = Coordinates(x, y);
|
|
|
|
|
|
|
|
let cell = self.get_cell(coords).unwrap();
|
2023-07-22 23:43:49 +00:00
|
|
|
|
|
|
|
let color = match cell.cell_type {
|
|
|
|
CellType::Normal => {normal}
|
|
|
|
CellType::DoubleWord => {double_word}
|
|
|
|
CellType::DoubleLetter => {double_letter}
|
|
|
|
CellType::TripleLetter => {triple_letter}
|
|
|
|
CellType::TripleWord => {triple_word}
|
|
|
|
CellType::Start => {double_word}
|
|
|
|
};
|
|
|
|
|
|
|
|
let content = match &cell.value {
|
|
|
|
None => {' '}
|
2023-07-28 04:25:50 +00:00
|
|
|
Some(letter) => {letter.text}
|
2023-07-22 23:43:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
str.write_str(color).unwrap();
|
|
|
|
str.write_char(content).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
str.write_str("\x1b[0m\n").unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
write!(f, "{}", str)
|
|
|
|
|
|
|
|
}
|
2023-07-22 03:18:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_cell_types() {
|
|
|
|
let board = Board::new();
|
|
|
|
|
2023-07-28 04:25:50 +00:00
|
|
|
assert!(matches!(board.get_cell(Coordinates(0, 0)).unwrap().cell_type, CellType::TripleWord));
|
|
|
|
assert!(matches!(board.get_cell(Coordinates(1, 0)).unwrap().cell_type, CellType::Normal));
|
|
|
|
assert!(matches!(board.get_cell(Coordinates(0, 1)).unwrap().cell_type, CellType::Normal));
|
|
|
|
assert!(matches!(board.get_cell(Coordinates(1, 1)).unwrap().cell_type, CellType::DoubleWord));
|
|
|
|
|
|
|
|
assert!(matches!(board.get_cell(Coordinates(13, 13)).unwrap().cell_type, CellType::DoubleWord));
|
|
|
|
assert!(matches!(board.get_cell(Coordinates(14, 14)).unwrap().cell_type, CellType::TripleWord));
|
|
|
|
assert!(matches!(board.get_cell(Coordinates(11, 14)).unwrap().cell_type, CellType::DoubleLetter));
|
|
|
|
|
|
|
|
assert!(matches!(board.get_cell(Coordinates(7, 7)).unwrap().cell_type, CellType::Start));
|
|
|
|
assert!(matches!(board.get_cell(Coordinates(8, 6)).unwrap().cell_type, CellType::DoubleLetter));
|
|
|
|
assert!(matches!(board.get_cell(Coordinates(5, 9)).unwrap().cell_type, CellType::TripleLetter));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2023-07-29 04:53:01 +00:00
|
|
|
fn test_cell_coordinates() {
|
|
|
|
let board = Board::new();
|
|
|
|
|
|
|
|
for x in 0..GRID_LENGTH {
|
|
|
|
for y in 0..GRID_LENGTH {
|
|
|
|
let cell = board.get_cell(Coordinates(x, y)).unwrap();
|
|
|
|
let coords = cell.coordinates;
|
|
|
|
|
|
|
|
assert_eq!(x, coords.0);
|
|
|
|
assert_eq!(y, coords.1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_word_finding_at_position() {
|
2023-07-28 04:25:50 +00:00
|
|
|
let mut board = Board::new();
|
|
|
|
|
|
|
|
board.get_cell_mut(Coordinates(8, 6)).unwrap().value = Some(Letter::new_fixed('J', 0));
|
|
|
|
board.get_cell_mut(Coordinates(8, 7)).unwrap().value = Some(Letter::new_fixed('O', 0));
|
|
|
|
board.get_cell_mut(Coordinates(8, 8)).unwrap().value = Some(Letter::new_fixed( 'E', 0));
|
|
|
|
board.get_cell_mut(Coordinates(8, 9)).unwrap().value = Some(Letter::new_fixed( 'L', 0));
|
|
|
|
|
|
|
|
board.get_cell_mut(Coordinates(0, 0)).unwrap().value = Some(Letter::new_fixed('I', 0));
|
|
|
|
board.get_cell_mut(Coordinates(1, 0)).unwrap().value = Some(Letter::new_fixed('S', 0));
|
|
|
|
|
|
|
|
board.get_cell_mut(Coordinates(3, 0)).unwrap().value = Some(Letter::new_fixed('C', 0));
|
|
|
|
board.get_cell_mut(Coordinates(4, 0)).unwrap().value = Some(Letter::new_fixed('O', 0));
|
|
|
|
board.get_cell_mut(Coordinates(5, 0)).unwrap().value = Some(Letter::new_fixed('O', 0));
|
|
|
|
board.get_cell_mut(Coordinates(6, 0)).unwrap().value = Some(Letter::new_fixed('L', 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));
|
|
|
|
|
|
|
|
for x in vec![6, 7, 8, 9] {
|
|
|
|
println!("x is {}", x);
|
2023-07-29 04:53:01 +00:00
|
|
|
let first_word = board.find_word_at_position(Coordinates(8, x), Direction::Column);
|
2023-07-28 04:25:50 +00:00
|
|
|
match first_word {
|
|
|
|
None => {panic!("Expected to find word JOEL")}
|
|
|
|
Some(x) => {
|
|
|
|
assert_eq!(x.coords.0, 8);
|
|
|
|
assert_eq!(x.coords.1, 6);
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
assert_eq!(x.to_string(), "JOEL");
|
2023-07-28 04:25:50 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-29 04:53:01 +00:00
|
|
|
let single_letter_word = board.find_word_at_position(Coordinates(8, 9), Direction::Row);
|
2023-07-28 04:25:50 +00:00
|
|
|
match single_letter_word {
|
|
|
|
None => {panic!("Expected to find letter L")}
|
|
|
|
Some(x) => {
|
|
|
|
assert_eq!(x.coords.0, 8);
|
|
|
|
assert_eq!(x.coords.1, 9);
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
assert_eq!(x.to_string(), "L");
|
2023-07-28 04:25:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for x in vec![0, 1] {
|
|
|
|
println!("x is {}", x);
|
2023-07-29 04:53:01 +00:00
|
|
|
let word = board.find_word_at_position(Coordinates(x, 0), Direction::Row);
|
2023-07-28 04:25:50 +00:00
|
|
|
match word {
|
|
|
|
None => {panic!("Expected to find word IS")}
|
|
|
|
Some(x) => {
|
|
|
|
assert_eq!(x.coords.0, 0);
|
|
|
|
assert_eq!(x.coords.1, 0);
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
assert_eq!(x.to_string(), "IS");
|
2023-07-28 04:25:50 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for x in vec![3, 4, 5, 6] {
|
|
|
|
println!("x is {}", x);
|
2023-07-29 04:53:01 +00:00
|
|
|
let word = board.find_word_at_position(Coordinates(x, 0), Direction::Row);
|
2023-07-28 04:25:50 +00:00
|
|
|
match word {
|
|
|
|
None => {panic!("Expected to find word COOL")}
|
|
|
|
Some(x) => {
|
|
|
|
assert_eq!(x.coords.0, 3);
|
|
|
|
assert_eq!(x.coords.1, 0);
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
assert_eq!(x.to_string(), "COOL");
|
2023-07-28 04:25:50 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-29 04:53:01 +00:00
|
|
|
let no_word = board.find_word_at_position(Coordinates(2, 0), Direction::Row);
|
2023-07-28 04:25:50 +00:00
|
|
|
assert!(no_word.is_none());
|
|
|
|
|
2023-07-29 04:53:01 +00:00
|
|
|
let word = board.find_word_at_position(Coordinates(10, 8), Direction::Row);
|
2023-07-28 04:25:50 +00:00
|
|
|
match word {
|
|
|
|
None => {panic!("Expected to find word EGG")}
|
|
|
|
Some(x) => {
|
|
|
|
assert_eq!(x.coords.0, 8);
|
|
|
|
assert_eq!(x.coords.1, 8);
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
assert_eq!(x.to_string(), "EGG");
|
2023-07-28 04:25:50 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-22 03:18:06 +00:00
|
|
|
|
|
|
|
|
2023-07-29 04:53:01 +00:00
|
|
|
}
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
#[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);
|
|
|
|
}
|
|
|
|
|
2023-07-30 00:31:55 +00:00
|
|
|
#[test]
|
|
|
|
fn test_word_finding_anchor() {
|
|
|
|
let mut board = Board::new();
|
|
|
|
|
|
|
|
fn make_letter(x: char, ephemeral: bool) -> Letter {
|
|
|
|
Letter {
|
|
|
|
text: x,
|
|
|
|
points: 0,
|
|
|
|
ephemeral,
|
|
|
|
is_blank: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
board.get_cell_mut(Coordinates(8, 6)).unwrap().value = Some(make_letter('J', true));
|
|
|
|
board.get_cell_mut(Coordinates(8, 7)).unwrap().value = Some(make_letter('O', true));
|
|
|
|
board.get_cell_mut(Coordinates(8, 8)).unwrap().value = Some(make_letter('E', true));
|
|
|
|
board.get_cell_mut(Coordinates(8, 9)).unwrap().value = Some(make_letter('L', true));
|
|
|
|
|
|
|
|
let words = board.find_played_words();
|
|
|
|
match words {
|
|
|
|
Ok(_) => {panic!("Expected the not-anchored error")}
|
|
|
|
Err(x) => {assert_eq!(x, "Played tiles must be anchored to something")}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adding anchor
|
|
|
|
board.get_cell_mut(Coordinates(7, 6)).unwrap().value = Some(make_letter('I', false));
|
|
|
|
assert!(board.find_played_words().is_ok());
|
|
|
|
|
|
|
|
board = Board::new();
|
|
|
|
|
|
|
|
// we go through center so this is anchored
|
|
|
|
board.get_cell_mut(Coordinates(7, 7)).unwrap().value = Some(make_letter('J', true));
|
|
|
|
board.get_cell_mut(Coordinates(8, 7)).unwrap().value = Some(make_letter('O', true));
|
|
|
|
board.get_cell_mut(Coordinates(9, 7)).unwrap().value = Some(make_letter('E', true));
|
|
|
|
board.get_cell_mut(Coordinates(10, 7)).unwrap().value = Some(make_letter('L', true));
|
|
|
|
|
|
|
|
assert!(board.find_played_words().is_ok());
|
|
|
|
}
|
2023-07-29 04:53:01 +00:00
|
|
|
|
|
|
|
#[test]
|
2023-07-30 00:31:55 +00:00
|
|
|
fn test_word_finding_with_break() {
|
|
|
|
// Verify that if I play my tiles on one row or column but with a break in-between I get an error
|
|
|
|
|
2023-07-29 04:53:01 +00:00
|
|
|
let mut board = Board::new();
|
|
|
|
|
|
|
|
fn make_letter(x: char, ephemeral: bool) -> Letter {
|
2023-07-30 00:31:55 +00:00
|
|
|
Letter {
|
|
|
|
text: x,
|
|
|
|
points: 0,
|
|
|
|
ephemeral,
|
|
|
|
is_blank: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
board.get_cell_mut(Coordinates(8, 6)).unwrap().value = Some(Letter::new_fixed('J', 0));
|
|
|
|
board.get_cell_mut(Coordinates(8, 7)).unwrap().value = Some(make_letter('O', true));
|
|
|
|
board.get_cell_mut(Coordinates(8, 8)).unwrap().value = Some(make_letter('E', true));
|
|
|
|
board.get_cell_mut(Coordinates(8, 9)).unwrap().value = Some(Letter::new_fixed( 'L', 0));
|
|
|
|
|
|
|
|
board.get_cell_mut(Coordinates(8, 11)).unwrap().value = Some(make_letter('I', true));
|
|
|
|
board.get_cell_mut(Coordinates(8, 12)).unwrap().value = Some(Letter::new_fixed('S', 0));
|
|
|
|
|
|
|
|
let words = board.find_played_words();
|
|
|
|
match words {
|
|
|
|
Ok(_) => {panic!("Expected to find an error!")}
|
|
|
|
Err(x) => {
|
|
|
|
assert_eq!(x, "Played tiles cannot have empty gap")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_word_finding_whole_board() {
|
|
|
|
let mut board = Board::new();
|
|
|
|
|
|
|
|
fn make_letter(x: char, ephemeral: bool, points: u32) -> Letter {
|
2023-07-29 04:53:01 +00:00
|
|
|
Letter {
|
|
|
|
text: x,
|
2023-07-30 00:31:55 +00:00
|
|
|
points,
|
2023-07-29 04:53:01 +00:00
|
|
|
ephemeral,
|
|
|
|
is_blank: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let words = board.find_played_words();
|
|
|
|
match words {
|
|
|
|
Ok(_) => {panic!("Expected to find no words")}
|
|
|
|
Err(x) => {assert_eq!(x, "Tiles need to be played")}
|
|
|
|
}
|
|
|
|
|
2023-07-30 00:31:55 +00:00
|
|
|
board.get_cell_mut(Coordinates(8, 6)).unwrap().value = Some(Letter::new_fixed('J', 8));
|
|
|
|
board.get_cell_mut(Coordinates(8, 7)).unwrap().value = Some(make_letter('O', true, 1));
|
|
|
|
board.get_cell_mut(Coordinates(8, 8)).unwrap().value = Some(make_letter('E', true, 1));
|
|
|
|
board.get_cell_mut(Coordinates(8, 9)).unwrap().value = Some(Letter::new_fixed( 'L', 1));
|
2023-07-29 04:53:01 +00:00
|
|
|
|
2023-07-30 00:31:55 +00:00
|
|
|
board.get_cell_mut(Coordinates(0, 0)).unwrap().value = Some(Letter::new_fixed('I', 1));
|
|
|
|
board.get_cell_mut(Coordinates(1, 0)).unwrap().value = Some(Letter::new_fixed('S', 1));
|
2023-07-29 04:53:01 +00:00
|
|
|
|
2023-07-30 00:31:55 +00:00
|
|
|
board.get_cell_mut(Coordinates(3, 0)).unwrap().value = Some(Letter::new_fixed('C', 3));
|
|
|
|
board.get_cell_mut(Coordinates(4, 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));
|
2023-07-29 04:53:01 +00:00
|
|
|
|
|
|
|
fn check_board(board: &mut Board, inverted: bool) {
|
2023-07-30 20:00:01 +00:00
|
|
|
let dictionary = HashMap::create("resources/dictionary.csv");
|
2023-07-30 00:31:55 +00:00
|
|
|
println!("{}", board);
|
2023-07-29 04:53:01 +00:00
|
|
|
let words = board.find_played_words();
|
|
|
|
match words {
|
|
|
|
Ok(x) => {
|
|
|
|
assert_eq!(x.len(), 1);
|
|
|
|
let word = x.get(0).unwrap();
|
2023-07-30 19:57:36 +00:00
|
|
|
assert_eq!(word.to_string(), "JOEL");
|
2023-07-30 20:00:01 +00:00
|
|
|
assert!(!dictionary.is_word_valid(word));
|
2023-07-30 00:31:55 +00:00
|
|
|
|
|
|
|
assert_eq!(word.calculate_score(), 8 + 1 + 2 + 1);
|
2023-07-29 04:53:01 +00:00
|
|
|
}
|
|
|
|
Err(e) => { panic!("Expected to find a word to play; found error {}", e) }
|
|
|
|
}
|
|
|
|
|
|
|
|
let maybe_invert = |coords: Coordinates| {
|
|
|
|
if inverted {
|
|
|
|
return Coordinates(coords.1, coords.0);
|
|
|
|
}
|
|
|
|
return coords;
|
|
|
|
};
|
|
|
|
|
|
|
|
let maybe_invert_direction = |direction: Direction| {
|
|
|
|
if inverted {
|
|
|
|
return direction.invert();
|
|
|
|
}
|
|
|
|
return direction;
|
|
|
|
};
|
|
|
|
|
2023-07-30 00:31:55 +00:00
|
|
|
board.get_cell_mut(maybe_invert(Coordinates(9, 8))).unwrap().value = Some(Letter::new_fixed('G', 2));
|
|
|
|
board.get_cell_mut(maybe_invert(Coordinates(10, 8))).unwrap().value = Some(Letter::new_fixed('G', 2));
|
2023-07-29 04:53:01 +00:00
|
|
|
|
|
|
|
let word = board.find_word_at_position(Coordinates(8, 8), maybe_invert_direction(Direction::Row));
|
|
|
|
match word {
|
|
|
|
None => {panic!("Expected to find word EGG")}
|
|
|
|
Some(x) => {
|
|
|
|
assert_eq!(x.coords.0, 8);
|
|
|
|
assert_eq!(x.coords.1, 8);
|
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
assert_eq!(x.to_string(), "EGG");
|
2023-07-30 00:31:55 +00:00
|
|
|
assert_eq!(x.calculate_score(), 2 + 2 + 2);
|
2023-07-30 20:00:01 +00:00
|
|
|
assert!(dictionary.is_word_valid(&x));
|
2023-07-29 04:53:01 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let words = board.find_played_words();
|
|
|
|
match words {
|
|
|
|
Ok(x) => {
|
|
|
|
assert_eq!(x.len(), 2);
|
|
|
|
let word = x.get(0).unwrap();
|
2023-07-30 19:57:36 +00:00
|
|
|
assert_eq!(word.to_string(), "EGG");
|
2023-07-30 00:31:55 +00:00
|
|
|
assert_eq!(word.calculate_score(), 2 + 2 + 2);
|
2023-07-30 20:00:01 +00:00
|
|
|
assert!(dictionary.is_word_valid(word));
|
2023-07-29 04:53:01 +00:00
|
|
|
|
|
|
|
let word = x.get(1).unwrap();
|
2023-07-30 19:57:36 +00:00
|
|
|
assert_eq!(word.to_string(), "JOEL");
|
2023-07-30 00:31:55 +00:00
|
|
|
assert_eq!(word.calculate_score(), 8 + 1 + 2 + 1);
|
2023-07-30 20:00:01 +00:00
|
|
|
assert!(!dictionary.is_word_valid(word));
|
2023-07-29 04:53:01 +00:00
|
|
|
}
|
|
|
|
Err(e) => { panic!("Expected to find a word to play; found error {}", e) }
|
|
|
|
}
|
2023-07-30 00:31:55 +00:00
|
|
|
// replace one of the 'G' in EGG with an ephemeral to trigger an error
|
|
|
|
board.get_cell_mut(maybe_invert(Coordinates(9, 8))).unwrap().value = Some(make_letter('G', true, 2));
|
2023-07-29 04:53:01 +00:00
|
|
|
|
|
|
|
let words = board.find_played_words();
|
|
|
|
match words {
|
|
|
|
Ok(_) => { panic!("Expected error as we played tiles in multiple rows and columns") }
|
|
|
|
Err(e) => { assert_eq!(e, "Tiles need to be played on one row or column") }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// make a copy of the board now with x and y swapped
|
|
|
|
let mut inverted_board = Board::new();
|
|
|
|
|
|
|
|
for x in 0..GRID_LENGTH {
|
|
|
|
for y in 0..GRID_LENGTH {
|
|
|
|
let cell_original = board.get_cell(Coordinates(x, y)).unwrap();
|
|
|
|
let cell_new = inverted_board.get_cell_mut(Coordinates(y, x)).unwrap();
|
|
|
|
|
|
|
|
match &cell_original.value {
|
|
|
|
None => {}
|
|
|
|
Some(x) => {
|
|
|
|
cell_new.value = Some(*x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
println!("Checking original board");
|
|
|
|
check_board(&mut board, false);
|
|
|
|
|
|
|
|
println!("Checking inverted board");
|
|
|
|
check_board(&mut inverted_board, true);
|
|
|
|
|
|
|
|
|
2023-07-22 03:18:06 +00:00
|
|
|
}
|
2023-07-25 02:50:40 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_dictionary() {
|
2023-07-30 19:57:36 +00:00
|
|
|
let dictionary = HashMap::create("resources/dictionary.csv");
|
2023-07-25 02:50:40 +00:00
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
assert_eq!(dictionary.len(), 279429);
|
2023-07-25 02:50:40 +00:00
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
assert!(dictionary.contains_key("AA"));
|
|
|
|
assert!(dictionary.contains_key("AARDVARK"));
|
2023-07-25 02:50:40 +00:00
|
|
|
|
2023-07-30 19:57:36 +00:00
|
|
|
assert!((dictionary.get("AARDVARK").unwrap() - 0.5798372).abs() < 0.0001)
|
2023-07-25 02:50:40 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_dictionary_sets() {
|
2023-07-30 19:57:36 +00:00
|
|
|
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);
|
2023-07-25 02:50:40 +00:00
|
|
|
|
|
|
|
let dictionary = dictionary.filter_to_sub_dictionary(0.3);
|
2023-07-30 19:57:36 +00:00
|
|
|
assert_eq!(dictionary.len(), 2);
|
|
|
|
assert!(dictionary.contains_key("JOEL"));
|
|
|
|
assert!(dictionary.contains_key("JOHN"));
|
2023-07-25 02:50:40 +00:00
|
|
|
|
|
|
|
let set = dictionary.substring_set();
|
|
|
|
|
|
|
|
assert!(set.contains("J"));
|
|
|
|
assert!(set.contains("O"));
|
|
|
|
assert!(set.contains("E"));
|
|
|
|
assert!(set.contains("L"));
|
|
|
|
assert!(set.contains("H"));
|
|
|
|
assert!(set.contains("N"));
|
|
|
|
|
|
|
|
assert!(set.contains("JO"));
|
|
|
|
assert!(set.contains("OE"));
|
|
|
|
assert!(set.contains("EL"));
|
|
|
|
assert!(set.contains("OH"));
|
|
|
|
assert!(set.contains("HN"));
|
|
|
|
|
|
|
|
assert!(set.contains("JOE"));
|
|
|
|
assert!(set.contains("OEL"));
|
|
|
|
assert!(set.contains("JOH"));
|
|
|
|
assert!(set.contains("OHN"));
|
|
|
|
|
|
|
|
|
|
|
|
assert!(!set.contains("XY"));
|
|
|
|
assert!(!set.contains("JH"));
|
|
|
|
assert!(!set.contains("JE"));
|
|
|
|
|
|
|
|
}
|
2023-07-22 03:18:06 +00:00
|
|
|
}
|