Add full word finding
This commit is contained in:
parent
4f5de6e52e
commit
5184c5b520
1 changed files with 177 additions and 14 deletions
191
src/lib.rs
191
src/lib.rs
|
@ -51,7 +51,7 @@ impl Coordinates {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Letter {
|
pub struct Letter {
|
||||||
text: char,
|
text: char,
|
||||||
points: u32,
|
points: u32,
|
||||||
|
@ -216,7 +216,7 @@ impl Board {
|
||||||
cells.push(Cell {
|
cells.push(Cell {
|
||||||
cell_type: typee,
|
cell_type: typee,
|
||||||
value: None,
|
value: None,
|
||||||
coordinates: Coordinates(i, j),
|
coordinates: Coordinates(j_orig, i_orig),
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,7 @@ impl Board {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn score_move(&self) -> Result<u32, &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
|
||||||
|
|
||||||
|
|
||||||
|
@ -276,27 +276,44 @@ impl Board {
|
||||||
}
|
}
|
||||||
|
|
||||||
let direction = if rows_played.len() > 1 {
|
let direction = if rows_played.len() > 1 {
|
||||||
Direction::Column
|
|
||||||
} else {
|
|
||||||
Direction::Row
|
Direction::Row
|
||||||
|
} else {
|
||||||
|
Direction::Column
|
||||||
};
|
};
|
||||||
|
|
||||||
let starting_row = *rows_played.iter().min().unwrap();
|
let starting_row = *rows_played.iter().min().unwrap();
|
||||||
let starting_column = *columns_played.iter().min().unwrap();
|
let starting_column = *columns_played.iter().min().unwrap();
|
||||||
|
|
||||||
let mut starting_coords = Coordinates(starting_row, starting_column);
|
let mut starting_coords = Coordinates(starting_row, starting_column);
|
||||||
|
let main_word = self.find_word_at_position(starting_coords, direction).unwrap();
|
||||||
|
|
||||||
|
starting_coords = main_word.coords;
|
||||||
|
|
||||||
|
let mut words = Vec::new();
|
||||||
|
|
||||||
// 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() {
|
||||||
|
if cell.value.as_ref().unwrap().ephemeral {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
words.push(main_word);
|
||||||
|
|
||||||
todo!()
|
Ok(words)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_word(&self, mut start_coords: Coordinates, direction: Direction) -> Option<Word> {
|
fn find_word_at_position(&self, mut start_coords: Coordinates, direction: Direction) -> Option<Word> {
|
||||||
// let's see how far we can backtrack to the start of the word
|
// let's see how far we can backtrack to the start of the word
|
||||||
let mut times_moved = 0;
|
let mut times_moved = 0;
|
||||||
loop {
|
loop {
|
||||||
|
@ -421,7 +438,22 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_word_finding() {
|
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() {
|
||||||
let mut board = Board::new();
|
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, 6)).unwrap().value = Some(Letter::new_fixed('J', 0));
|
||||||
|
@ -452,7 +484,7 @@ mod tests {
|
||||||
|
|
||||||
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(Coordinates(8, x), Direction::Column);
|
let first_word = board.find_word_at_position(Coordinates(8, x), Direction::Column);
|
||||||
match first_word {
|
match first_word {
|
||||||
None => {panic!("Expected to find word JOEL")}
|
None => {panic!("Expected to find word JOEL")}
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
|
@ -465,7 +497,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let single_letter_word = board.find_word(Coordinates(8, 9), Direction::Row);
|
let single_letter_word = board.find_word_at_position(Coordinates(8, 9), Direction::Row);
|
||||||
match single_letter_word {
|
match single_letter_word {
|
||||||
None => {panic!("Expected to find letter L")}
|
None => {panic!("Expected to find letter L")}
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
|
@ -478,7 +510,7 @@ mod tests {
|
||||||
|
|
||||||
for x in vec![0, 1] {
|
for x in vec![0, 1] {
|
||||||
println!("x is {}", x);
|
println!("x is {}", x);
|
||||||
let word = board.find_word(Coordinates(x, 0), Direction::Row);
|
let word = board.find_word_at_position(Coordinates(x, 0), Direction::Row);
|
||||||
match word {
|
match word {
|
||||||
None => {panic!("Expected to find word IS")}
|
None => {panic!("Expected to find word IS")}
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
|
@ -493,7 +525,7 @@ mod tests {
|
||||||
|
|
||||||
for x in vec![3, 4, 5, 6] {
|
for x in vec![3, 4, 5, 6] {
|
||||||
println!("x is {}", x);
|
println!("x is {}", x);
|
||||||
let word = board.find_word(Coordinates(x, 0), Direction::Row);
|
let word = board.find_word_at_position(Coordinates(x, 0), Direction::Row);
|
||||||
match word {
|
match word {
|
||||||
None => {panic!("Expected to find word COOL")}
|
None => {panic!("Expected to find word COOL")}
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
|
@ -506,10 +538,10 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let no_word = board.find_word(Coordinates(2, 0), Direction::Row);
|
let no_word = board.find_word_at_position(Coordinates(2, 0), Direction::Row);
|
||||||
assert!(no_word.is_none());
|
assert!(no_word.is_none());
|
||||||
|
|
||||||
let word = board.find_word(Coordinates(10, 8), Direction::Row);
|
let word = board.find_word_at_position(Coordinates(10, 8), Direction::Row);
|
||||||
match word {
|
match word {
|
||||||
None => {panic!("Expected to find word EGG")}
|
None => {panic!("Expected to find word EGG")}
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
|
@ -523,6 +555,137 @@ mod tests {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_word_finding_whole_board() {
|
||||||
|
let mut board = Board::new();
|
||||||
|
|
||||||
|
fn make_letter(x: char, ephemeral: bool) -> Letter {
|
||||||
|
Letter {
|
||||||
|
text: x,
|
||||||
|
points: 0,
|
||||||
|
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', 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(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));
|
||||||
|
|
||||||
|
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) {
|
||||||
|
let words = board.find_played_words();
|
||||||
|
match words {
|
||||||
|
Ok(x) => {
|
||||||
|
assert_eq!(x.len(), 1);
|
||||||
|
let word = x.get(0).unwrap();
|
||||||
|
assert_eq!(word_to_text(word), "JOEL");
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
board.get_cell_mut(maybe_invert(Coordinates(9, 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', 0));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
assert_eq!(word_to_text(&x), "EGG");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let words = board.find_played_words();
|
||||||
|
match words {
|
||||||
|
Ok(x) => {
|
||||||
|
assert_eq!(x.len(), 2);
|
||||||
|
let word = x.get(0).unwrap();
|
||||||
|
assert_eq!(word_to_text(word), "EGG");
|
||||||
|
|
||||||
|
let word = x.get(1).unwrap();
|
||||||
|
assert_eq!(word_to_text(word), "JOEL");
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue