Catch errors in word-finding; add start of scoring
This commit is contained in:
parent
5184c5b520
commit
6f14579f3a
1 changed files with 174 additions and 17 deletions
183
src/lib.rs
183
src/lib.rs
|
@ -156,6 +156,44 @@ struct Word<'a> {
|
||||||
coords: Coordinates,
|
coords: Coordinates,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Board {
|
impl Board {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut cells = Vec::new();
|
let mut cells = Vec::new();
|
||||||
|
@ -243,6 +281,22 @@ impl Board {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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!()
|
||||||
|
}*/
|
||||||
|
|
||||||
fn find_played_words(&self) -> Result<Vec<Word>, &str> {
|
fn find_played_words(&self) -> Result<Vec<Word>, &str> {
|
||||||
// We don't assume that the move is valid, so let's first establish that
|
// We don't assume that the move is valid, so let's first establish that
|
||||||
|
|
||||||
|
@ -290,11 +344,13 @@ impl Board {
|
||||||
starting_coords = main_word.coords;
|
starting_coords = main_word.coords;
|
||||||
|
|
||||||
let mut words = Vec::new();
|
let mut words = Vec::new();
|
||||||
|
let mut observed_tiles_played = 0;
|
||||||
|
|
||||||
// At this point we now know that we're at the start of the word and we have the direction.
|
// 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
|
// Now we'll head forward and look for every word that intersects one of the played tiles
|
||||||
for cell in main_word.cells.as_slice() {
|
for cell in main_word.cells.as_slice() {
|
||||||
if cell.value.as_ref().unwrap().ephemeral {
|
if cell.value.as_ref().unwrap().ephemeral {
|
||||||
|
observed_tiles_played += 1;
|
||||||
let side_word = self.find_word_at_position(cell.coordinates, direction.invert());
|
let side_word = self.find_word_at_position(cell.coordinates, direction.invert());
|
||||||
match side_word {
|
match side_word {
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -307,10 +363,33 @@ impl Board {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// there are tiles not part of the main word
|
||||||
|
if observed_tiles_played != tiles_played {
|
||||||
|
return Err("Played tiles cannot have empty gap");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
words.push(main_word);
|
words.push(main_word);
|
||||||
|
|
||||||
|
// 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)
|
Ok(words)
|
||||||
|
} else {
|
||||||
|
return Err("Played tiles must be anchored to something")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_word_at_position(&self, mut start_coords: Coordinates, direction: Direction) -> Option<Word> {
|
fn find_word_at_position(&self, mut start_coords: Coordinates, direction: Direction) -> Option<Word> {
|
||||||
|
@ -557,9 +636,8 @@ mod tests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_word_finding_whole_board() {
|
fn test_word_finding_anchor() {
|
||||||
let mut board = Board::new();
|
let mut board = Board::new();
|
||||||
|
|
||||||
fn make_letter(x: char, ephemeral: bool) -> Letter {
|
fn make_letter(x: char, ephemeral: bool) -> Letter {
|
||||||
|
@ -571,10 +649,45 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
let words = board.find_played_words();
|
||||||
match words {
|
match words {
|
||||||
Ok(_) => {panic!("Expected to find no words")}
|
Ok(_) => {panic!("Expected the not-anchored error")}
|
||||||
Err(x) => {assert_eq!(x, "Tiles need to be played")}
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
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
|
||||||
|
|
||||||
|
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(Letter::new_fixed('J', 0));
|
board.get_cell_mut(Coordinates(8, 6)).unwrap().value = Some(Letter::new_fixed('J', 0));
|
||||||
|
@ -582,14 +695,51 @@ mod tests {
|
||||||
board.get_cell_mut(Coordinates(8, 8)).unwrap().value = Some(make_letter('E', 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, 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));
|
||||||
|
|
||||||
board.get_cell_mut(Coordinates(0, 0)).unwrap().value = Some(Letter::new_fixed('I', 0));
|
let words = board.find_played_words();
|
||||||
board.get_cell_mut(Coordinates(1, 0)).unwrap().value = Some(Letter::new_fixed('S', 0));
|
match words {
|
||||||
|
Ok(_) => {panic!("Expected to find an error!")}
|
||||||
|
Err(x) => {
|
||||||
|
assert_eq!(x, "Played tiles cannot have empty gap")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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));
|
#[test]
|
||||||
|
fn test_word_finding_whole_board() {
|
||||||
|
let mut board = Board::new();
|
||||||
|
|
||||||
|
fn make_letter(x: char, ephemeral: bool, points: u32) -> Letter {
|
||||||
|
Letter {
|
||||||
|
text: x,
|
||||||
|
points,
|
||||||
|
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")}
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
fn word_to_text(word: &Word) -> String {
|
fn word_to_text(word: &Word) -> String {
|
||||||
let mut text = String::with_capacity(word.cells.len());
|
let mut text = String::with_capacity(word.cells.len());
|
||||||
|
@ -601,12 +751,15 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_board(board: &mut Board, inverted: bool) {
|
fn check_board(board: &mut Board, inverted: bool) {
|
||||||
|
println!("{}", board);
|
||||||
let words = board.find_played_words();
|
let words = board.find_played_words();
|
||||||
match words {
|
match words {
|
||||||
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_text(word), "JOEL");
|
||||||
|
|
||||||
|
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) }
|
||||||
}
|
}
|
||||||
|
@ -625,8 +778,8 @@ mod tests {
|
||||||
return direction;
|
return direction;
|
||||||
};
|
};
|
||||||
|
|
||||||
board.get_cell_mut(maybe_invert(Coordinates(9, 8))).unwrap().value = Some(Letter::new_fixed('G', 0));
|
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', 0));
|
board.get_cell_mut(maybe_invert(Coordinates(10, 8))).unwrap().value = Some(Letter::new_fixed('G', 2));
|
||||||
|
|
||||||
let word = board.find_word_at_position(Coordinates(8, 8), maybe_invert_direction(Direction::Row));
|
let word = board.find_word_at_position(Coordinates(8, 8), maybe_invert_direction(Direction::Row));
|
||||||
match word {
|
match word {
|
||||||
|
@ -636,6 +789,7 @@ mod tests {
|
||||||
assert_eq!(x.coords.1, 8);
|
assert_eq!(x.coords.1, 8);
|
||||||
|
|
||||||
assert_eq!(word_to_text(&x), "EGG");
|
assert_eq!(word_to_text(&x), "EGG");
|
||||||
|
assert_eq!(x.calculate_score(), 2 + 2 + 2);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -646,13 +800,16 @@ mod tests {
|
||||||
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_text(word), "EGG");
|
||||||
|
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_text(word), "JOEL");
|
||||||
|
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) }
|
||||||
}
|
}
|
||||||
board.get_cell_mut(maybe_invert(Coordinates(9, 8))).unwrap().value = Some(make_letter('G', true));
|
// 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));
|
||||||
|
|
||||||
let words = board.find_played_words();
|
let words = board.find_played_words();
|
||||||
match words {
|
match words {
|
||||||
|
|
Loading…
Reference in a new issue