2023-08-16 02:35:23 +00:00
|
|
|
use rand::prelude::SliceRandom;
|
2023-08-06 01:59:30 +00:00
|
|
|
use rand::rngs::SmallRng;
|
|
|
|
use rand::SeedableRng;
|
2023-08-10 03:00:14 +00:00
|
|
|
use crate::board::{Board, Letter};
|
2023-08-06 01:59:30 +00:00
|
|
|
use crate::constants::{standard_tile_pool, TRAY_LENGTH};
|
2023-08-13 20:08:37 +00:00
|
|
|
use crate::dictionary::{Dictionary, DictionaryImpl};
|
2023-08-06 01:59:30 +00:00
|
|
|
use crate::player_interaction::ai::Difficulty;
|
|
|
|
use crate::player_interaction::Tray;
|
|
|
|
|
|
|
|
pub enum Player {
|
|
|
|
Human(String),
|
|
|
|
AI{
|
|
|
|
name: String,
|
|
|
|
difficulty: Difficulty,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-16 02:35:23 +00:00
|
|
|
impl Player {
|
|
|
|
|
|
|
|
pub fn get_name(&self) -> &str {
|
|
|
|
match &self {
|
|
|
|
Player::Human(name) => {name}
|
|
|
|
Player::AI { name, .. } => {name}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-06 01:59:30 +00:00
|
|
|
pub struct PlayerState {
|
2023-08-16 02:35:23 +00:00
|
|
|
pub player: Player,
|
|
|
|
pub score: u32,
|
2023-08-17 02:37:32 +00:00
|
|
|
pub tray: Tray
|
2023-08-06 01:59:30 +00:00
|
|
|
}
|
|
|
|
|
2023-08-13 20:08:37 +00:00
|
|
|
pub struct Game{
|
2023-08-17 02:37:32 +00:00
|
|
|
pub tile_pool: Vec<Letter>,
|
2023-08-10 03:00:14 +00:00
|
|
|
board: Board,
|
2023-08-16 02:35:23 +00:00
|
|
|
pub player_states: Vec<PlayerState>,
|
2023-08-13 20:08:37 +00:00
|
|
|
dictionary: DictionaryImpl,
|
2023-08-06 01:59:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Problem - I want to provide a UI to the player
|
|
|
|
// Ideally they would get some kind of 'tray' object with methods to use and run
|
|
|
|
// However I want the main game state to live in Rust, not in JS.
|
|
|
|
// Does this mean I provide Rc<RefCell<Tray>>?
|
|
|
|
|
|
|
|
// Other option - what if I just have one Game object that exposes all methods.
|
|
|
|
// At no point do they get a Tray reference that auto-updates, they need to handle that
|
|
|
|
// I just provide read-only JSON of everything, and they call the methods for updates
|
|
|
|
// This will later work out well when I build it out as an API for multiplayer.
|
|
|
|
|
|
|
|
impl Game {
|
2023-08-16 02:35:23 +00:00
|
|
|
pub fn new(seed: u64, dictionary_text: &str, mut player_names: Vec<String>) -> Self {
|
2023-08-06 01:59:30 +00:00
|
|
|
let mut rng = SmallRng::seed_from_u64(seed);
|
|
|
|
|
|
|
|
let mut letters = standard_tile_pool(Some(&mut rng));
|
|
|
|
|
2023-08-16 02:35:23 +00:00
|
|
|
player_names.shuffle(&mut rng);
|
|
|
|
let player_states: Vec<PlayerState> = player_names.iter()
|
|
|
|
.map(|name| {
|
|
|
|
let mut tray = Tray::new(TRAY_LENGTH);
|
|
|
|
tray.fill(&mut letters);
|
|
|
|
PlayerState {
|
|
|
|
player: Player::Human(name.clone()),
|
|
|
|
score: 0,
|
|
|
|
tray,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
2023-08-06 01:59:30 +00:00
|
|
|
|
|
|
|
Game {
|
2023-08-10 03:00:14 +00:00
|
|
|
tile_pool: letters,
|
|
|
|
board: Board::new(),
|
2023-08-16 02:35:23 +00:00
|
|
|
player_states,
|
2023-08-13 20:08:37 +00:00
|
|
|
dictionary: DictionaryImpl::create_from_str(dictionary_text)
|
2023-08-06 01:59:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-17 02:37:32 +00:00
|
|
|
pub fn get_player_state(&self, name: &str) -> Option<&PlayerState> {
|
|
|
|
self.player_states.iter()
|
2023-08-16 02:35:23 +00:00
|
|
|
.filter(|state| state.player.get_name().eq(name))
|
2023-08-17 02:37:32 +00:00
|
|
|
.nth(0)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_player_state_mut(&mut self, name: &str) -> Option<&mut PlayerState> {
|
|
|
|
self.player_states.iter_mut()
|
|
|
|
.filter(|state| state.player.get_name().eq(name))
|
|
|
|
.nth(0)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_tray(&self, name: &str) -> Option<&Tray> {
|
|
|
|
let player = self.get_player_state(name)?;
|
2023-08-16 02:35:23 +00:00
|
|
|
|
|
|
|
Some(&player.tray)
|
|
|
|
|
2023-08-06 01:59:30 +00:00
|
|
|
}
|
|
|
|
|
2023-08-16 02:35:23 +00:00
|
|
|
pub fn get_tray_mut(&mut self, name: &str) -> Option<&mut Tray> {
|
2023-08-17 02:37:32 +00:00
|
|
|
let player = self.get_player_state_mut(name)?;
|
2023-08-16 02:35:23 +00:00
|
|
|
|
|
|
|
Some(&mut player.tray)
|
|
|
|
|
2023-08-06 01:59:30 +00:00
|
|
|
}
|
2023-08-10 03:00:14 +00:00
|
|
|
|
|
|
|
pub fn get_board(&self) -> &Board {&self.board}
|
|
|
|
|
2023-08-17 02:37:32 +00:00
|
|
|
pub fn set_board(&mut self, new_board: Board) {
|
|
|
|
self.board = new_board;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fill_trays(&mut self){
|
|
|
|
for state in self.player_states.iter_mut() {
|
|
|
|
let tray = &mut state.tray;
|
|
|
|
tray.fill(&mut self.tile_pool);
|
|
|
|
}
|
2023-08-13 20:08:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_dictionary(&self) -> &DictionaryImpl {
|
|
|
|
&self.dictionary
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-08-06 01:59:30 +00:00
|
|
|
}
|