diff --git a/Cargo.lock b/Cargo.lock index b31323a..03595b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -234,26 +234,16 @@ dependencies = [ [[package]] name = "rs48" -version = "1.1.0" +version = "1.2.0" dependencies = [ "clap", "rand", - "rs48_lib 1.1.0", + "rs48_lib", ] [[package]] name = "rs48_lib" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da34dd2475597325c46db60df6c4f27cdf773f2acba50d96668471ead6bd61c" -dependencies = [ - "rand", - "termion", -] - -[[package]] -name = "rs48_lib" -version = "1.1.1" +version = "1.2.0" dependencies = [ "rand", "termion", diff --git a/rs48/Cargo.toml b/rs48/Cargo.toml index 34b5e09..687e57e 100644 --- a/rs48/Cargo.toml +++ b/rs48/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rs48" -version = "1.1.0" +version = "1.2.0" edition = "2021" description = "A game of 2048 that plays in the terminal as a TUI with a lot of configurability." license = "GPL-3.0" @@ -9,6 +9,6 @@ repository = "https://github.com/MajorBarnulf/rs48" homepage = "https://github.com/MajorBarnulf/rs48" [dependencies] -clap = { version = "3.1", features = ["derive"] } -rs48_lib = "1.1" -rand = "*" +clap = { version = "3.2", features = ["derive"] } +rs48_lib = { path = "../rs48_lib" } +rand = "0.8" diff --git a/rs48/src/main.rs b/rs48/src/main.rs index e4a6388..0b2879d 100644 --- a/rs48/src/main.rs +++ b/rs48/src/main.rs @@ -83,11 +83,10 @@ fn main() -> Result<(), GameError> { let controller = match arguments.controller { ControllerParam::Player => PlayerController::new().into_box(), ControllerParam::Random => RandomController::new().into_box(), - ControllerParam::Simulated => todo!(), + ControllerParam::Simulated => SimulatedController::new(80, 50).into_box(), }; let mut managed = GameManager::new(game_rules, manager_rules, controller); let err = managed.play_all(); - println!("color seed: {color_seed}"); err } diff --git a/rs48_lib/Cargo.toml b/rs48_lib/Cargo.toml index 2b732b0..45b16d6 100644 --- a/rs48_lib/Cargo.toml +++ b/rs48_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rs48_lib" -version = "1.1.1" +version = "1.2.0" edition = "2021" description = "components of rs48" license = "MIT" diff --git a/rs48_lib/src/controller.rs b/rs48_lib/src/controller.rs index f2c3698..4f2c19a 100644 --- a/rs48_lib/src/controller.rs +++ b/rs48_lib/src/controller.rs @@ -1,9 +1,9 @@ use rand::{distributions::Standard, prelude::Distribution}; -use super::grid::Grid; +use crate::game::Game; use std::{error::Error, fmt::Display}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Move { LEFT, RIGHT, @@ -11,6 +11,12 @@ pub enum Move { DOWN, } +impl Move { + pub fn all() -> [Self; 4] { + [Self::LEFT, Self::RIGHT, Self::UP, Self::DOWN] + } +} + impl Distribution for Standard { fn sample(&self, rng: &mut R) -> Move { match rng.gen_range(0..4) { @@ -39,7 +45,7 @@ impl Display for ControllerError { impl Error for ControllerError {} pub trait Controller { - fn next_move(&mut self, grid: &Grid) -> Result; + fn next_move(&mut self, game: &Game) -> Result; fn into_box(self) -> Box where diff --git a/rs48_lib/src/controller/player.rs b/rs48_lib/src/controller/player.rs index 835e49d..27839c1 100644 --- a/rs48_lib/src/controller/player.rs +++ b/rs48_lib/src/controller/player.rs @@ -2,7 +2,7 @@ use std::io::{stdin, stdout}; use termion::{event::Key, input::TermRead, raw::IntoRawMode}; use super::{Controller, ControllerError, Move}; -use crate::grid::Grid; +use crate::game::Game; pub struct PlayerController; @@ -13,7 +13,7 @@ impl PlayerController { } impl Controller for PlayerController { - fn next_move(&mut self, _grid: &Grid) -> Result { + fn next_move(&mut self, _game: &Game) -> Result { let stdin = stdin(); let mut _stdout = stdout() .into_raw_mode() diff --git a/rs48_lib/src/controller/random.rs b/rs48_lib/src/controller/random.rs index 8f2e90c..bb21104 100644 --- a/rs48_lib/src/controller/random.rs +++ b/rs48_lib/src/controller/random.rs @@ -1,7 +1,7 @@ use rand::random; use super::{Controller, ControllerError, Move}; -use crate::grid::Grid; +use crate::game::Game; pub struct RandomController; @@ -12,7 +12,7 @@ impl RandomController { } impl Controller for RandomController { - fn next_move(&mut self, _grid: &Grid) -> Result { + fn next_move(&mut self, _game: &Game) -> Result { let movement = random(); Ok(movement) } diff --git a/rs48_lib/src/controller/simulated.rs b/rs48_lib/src/controller/simulated.rs index beed693..73aa53e 100644 --- a/rs48_lib/src/controller/simulated.rs +++ b/rs48_lib/src/controller/simulated.rs @@ -1,4 +1,4 @@ -use crate::grid::Grid; +use crate::{game::Game, prelude::RandomController}; use super::{Controller, ControllerError, Move}; @@ -8,27 +8,53 @@ pub enum Objective { } pub struct SimulatedController { - _simulations_per_move: usize, - _length_of_simulation: usize, - _objective: Objective, + simulations_per_move: usize, + length_of_simulation: usize, } impl SimulatedController { - pub fn new( - _simulations_per_move: usize, - _length_of_simulation: usize, - _objective: Objective, - ) -> Self { + pub fn new(simulations_per_move: usize, length_of_simulation: usize) -> Self { Self { - _simulations_per_move, - _length_of_simulation, - _objective, + simulations_per_move, + length_of_simulation, } } } impl Controller for SimulatedController { - fn next_move(&mut self, _grid: &Grid) -> Result { - todo!() + fn next_move(&mut self, game: &Game) -> Result { + let initial_score = game.get_score(); + + let mut scores: Vec<_> = Move::all() + .into_iter() + .map(|initial_move| { + let sim_scores = (0..self.simulations_per_move).map(|_| { + let mut game = game.clone(); + game.turn(initial_move.clone()).ok(); + let mut controller = RandomController::new(); + for _ in 1..self.length_of_simulation { + let movement = controller.next_move(&game).ok(); + let result = movement.and_then(|movement| game.turn(movement).ok()); + if result.is_none() { + continue; + } + } + game.get_score() - initial_score + }); + + let mut res = 0; + let mut it = 0; + for score in sim_scores { + it += 1; + res += score; + } + + (initial_move, res / it) + }) + .collect(); + scores.sort_by(|(_, a), (_, b)| a.cmp(b)); + + let (m, _) = scores.last().unwrap(); + Ok(m.clone()) } } diff --git a/rs48_lib/src/game.rs b/rs48_lib/src/game.rs index 15221ba..d3275f5 100644 --- a/rs48_lib/src/game.rs +++ b/rs48_lib/src/game.rs @@ -5,6 +5,7 @@ use super::{ grid::Grid, }; +#[derive(Debug, Clone)] pub struct Rules { size: usize, spawn_per_turn: usize, @@ -60,6 +61,7 @@ pub struct Game { score: usize, turn_index: usize, spawn_per_turn: usize, + rules: Rules, } impl Game { @@ -67,13 +69,14 @@ impl Game { let Rules { size, spawn_per_turn, - } = rules; + } = rules.clone(); Self { board: Grid::new(size), score: 0, turn_index: 0, spawn_per_turn, + rules, } } @@ -85,13 +88,16 @@ impl Game { self.score } + pub fn get_rules(&self) -> &Rules { + &self.rules + } + pub fn get_turn_index(&self) -> usize { self.turn_index } pub fn turn(&mut self, movement: Move) -> Result<(), GameError> { - let move_score = self.perform_move(movement); - self.score += move_score; + self.perform_move(movement); for _ in 0..self.spawn_per_turn { self.spawn_random()?; } @@ -156,6 +162,7 @@ impl Game { } } }; + self.score += move_score; move_score } diff --git a/rs48_lib/src/game_manager.rs b/rs48_lib/src/game_manager.rs index 18be4dd..9f6f03e 100644 --- a/rs48_lib/src/game_manager.rs +++ b/rs48_lib/src/game_manager.rs @@ -119,8 +119,7 @@ impl GameManager { } fn game_turn(&mut self) -> Result<(), GameError> { - let board = self.game.get_board(); - let movement = self.controller.next_move(board)?; + let movement = self.controller.next_move(&self.game)?; self.game.turn(movement)?; Ok(()) }