Add capability to convert AI plays into PlayedTiles vector
This commit is contained in:
parent
0887cb29aa
commit
e23c1d139b
2 changed files with 56 additions and 16 deletions
16
src/game.rs
16
src/game.rs
|
@ -33,11 +33,11 @@ pub struct PlayerState {
|
||||||
pub tray: Tray
|
pub tray: Tray
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Tsify, Copy, Clone)]
|
#[derive(Deserialize, Tsify, Copy, Clone, Debug)]
|
||||||
#[tsify(from_wasm_abi)]
|
#[tsify(from_wasm_abi)]
|
||||||
pub struct PlayedTile {
|
pub struct PlayedTile {
|
||||||
index: usize,
|
pub index: usize,
|
||||||
character: Option<char>,
|
pub character: char,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Tsify)]
|
#[derive(Debug, Serialize, Deserialize, Tsify)]
|
||||||
|
@ -164,15 +164,7 @@ impl Game {
|
||||||
|
|
||||||
let coord = Coordinates::new_from_index(played_tile.index);
|
let coord = Coordinates::new_from_index(played_tile.index);
|
||||||
if letter.is_blank {
|
if letter.is_blank {
|
||||||
match played_tile.character {
|
letter.text = played_tile.character;
|
||||||
None => {
|
|
||||||
panic!("You can't play a blank character without providing a letter value")
|
|
||||||
}
|
|
||||||
Some(x) => {
|
|
||||||
// TODO - I should check that the character is a valid letter
|
|
||||||
letter.text = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
played_letters.push((letter, coord));
|
played_letters.push((letter, coord));
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ use rand::Rng;
|
||||||
use crate::board::{Board, CellType, Coordinates, Direction, Letter};
|
use crate::board::{Board, CellType, Coordinates, Direction, Letter};
|
||||||
use crate::constants::GRID_LENGTH;
|
use crate::constants::GRID_LENGTH;
|
||||||
use crate::dictionary::DictionaryImpl;
|
use crate::dictionary::DictionaryImpl;
|
||||||
|
use crate::game::PlayedTile;
|
||||||
use crate::player_interaction::Tray;
|
use crate::player_interaction::Tray;
|
||||||
|
|
||||||
const ALPHABET: [char; 26] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
|
const ALPHABET: [char; 26] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
|
||||||
|
@ -51,6 +52,47 @@ pub struct CompleteMove {
|
||||||
score: u32,
|
score: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CompleteMove {
|
||||||
|
|
||||||
|
pub fn convert_to_play(&self, tray: &Tray) -> Vec<Option<PlayedTile>> {
|
||||||
|
let mut played_tiles = Vec::with_capacity(tray.letters.len());
|
||||||
|
let mut moves = self.moves.iter()
|
||||||
|
.map(|m| Some(m.clone()))
|
||||||
|
.collect::<Vec<Option<MoveComponent>>>();
|
||||||
|
|
||||||
|
tray.letters.iter().for_each(|letter| {
|
||||||
|
match letter {
|
||||||
|
None => {
|
||||||
|
played_tiles.push(None);
|
||||||
|
}
|
||||||
|
Some(letter) => {
|
||||||
|
let mut found_match = false;
|
||||||
|
// see if we can find a match in moves
|
||||||
|
for m in moves.iter_mut() {
|
||||||
|
match m {
|
||||||
|
Some(x) => {
|
||||||
|
if letter.partial_match(&x.letter) {
|
||||||
|
played_tiles.push(Some(PlayedTile {
|
||||||
|
index: x.coordinates.map_to_index(),
|
||||||
|
character: x.letter.text,
|
||||||
|
}));
|
||||||
|
*m = None;
|
||||||
|
found_match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(found_match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
played_tiles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct MoveScoring {
|
struct MoveScoring {
|
||||||
main_scoring: u32,
|
main_scoring: u32,
|
||||||
|
@ -827,7 +869,7 @@ mod tests {
|
||||||
ephemeral: false,
|
ephemeral: false,
|
||||||
is_blank: false,
|
is_blank: false,
|
||||||
});
|
});
|
||||||
tray.letters[2] = Some(Letter{
|
tray.letters[6] = Some(Letter{
|
||||||
text: 'A',
|
text: 'A',
|
||||||
points: 1,
|
points: 1,
|
||||||
ephemeral: false,
|
ephemeral: false,
|
||||||
|
@ -848,19 +890,25 @@ mod tests {
|
||||||
assert!(end_of_boat.is_some());
|
assert!(end_of_boat.is_some());
|
||||||
assert_eq!(end_of_boat.as_ref().unwrap().len(), 1);
|
assert_eq!(end_of_boat.as_ref().unwrap().len(), 1);
|
||||||
|
|
||||||
//let rng = SmallRng::seed_from_u64(123);
|
|
||||||
|
|
||||||
let moves = ai.find_all_moves(&tray, &board);
|
let moves = ai.find_all_moves(&tray, &board);
|
||||||
|
|
||||||
println!("Moves are {:?}", moves);
|
println!("Moves are {:?}", moves);
|
||||||
|
|
||||||
|
|
||||||
// 2 possible moves -
|
// 3 possible moves -
|
||||||
// 1. put 'S' at the end of 'BOAT' and form words 'SLAM' and 'BOATS'
|
// 1. put 'S' at the end of 'BOAT' and form words 'SLAM' and 'BOATS'
|
||||||
// 2. Put 'S' at end of 'BOAT'
|
// 2. Put 'S' at end of 'BOAT'
|
||||||
// 3. Put 'SL' to left of 'A' in 'BOAT' and then 'M' to right of it
|
// 3. Put 'SL' to left of 'A' in 'BOAT' and then 'M' to right of it
|
||||||
assert_eq!(moves.len(), 3);
|
assert_eq!(moves.len(), 3);
|
||||||
|
|
||||||
|
let mut rng = SmallRng::seed_from_u64(123);
|
||||||
|
let best_move = ai.find_best_move(&tray, &board, &mut rng).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(best_move.score, 23);
|
||||||
|
|
||||||
|
let play = best_move.convert_to_play(&tray);
|
||||||
|
println!("Play is {:?}", play);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue