finished simulated controller

This commit is contained in:
matthieu.jolimaitre 2022-09-29 10:25:20 +02:00
parent aaf717bd8d
commit 5d723ae9f8
10 changed files with 73 additions and 46 deletions

16
Cargo.lock generated
View file

@ -234,26 +234,16 @@ dependencies = [
[[package]] [[package]]
name = "rs48" name = "rs48"
version = "1.1.0" version = "1.2.0"
dependencies = [ dependencies = [
"clap", "clap",
"rand", "rand",
"rs48_lib 1.1.0", "rs48_lib",
] ]
[[package]] [[package]]
name = "rs48_lib" name = "rs48_lib"
version = "1.1.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da34dd2475597325c46db60df6c4f27cdf773f2acba50d96668471ead6bd61c"
dependencies = [
"rand",
"termion",
]
[[package]]
name = "rs48_lib"
version = "1.1.1"
dependencies = [ dependencies = [
"rand", "rand",
"termion", "termion",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "rs48" name = "rs48"
version = "1.1.0" version = "1.2.0"
edition = "2021" edition = "2021"
description = "A game of 2048 that plays in the terminal as a TUI with a lot of configurability." description = "A game of 2048 that plays in the terminal as a TUI with a lot of configurability."
license = "GPL-3.0" license = "GPL-3.0"
@ -9,6 +9,6 @@ repository = "https://github.com/MajorBarnulf/rs48"
homepage = "https://github.com/MajorBarnulf/rs48" homepage = "https://github.com/MajorBarnulf/rs48"
[dependencies] [dependencies]
clap = { version = "3.1", features = ["derive"] } clap = { version = "3.2", features = ["derive"] }
rs48_lib = "1.1" rs48_lib = { path = "../rs48_lib" }
rand = "*" rand = "0.8"

View file

@ -83,11 +83,10 @@ fn main() -> Result<(), GameError> {
let controller = match arguments.controller { let controller = match arguments.controller {
ControllerParam::Player => PlayerController::new().into_box(), ControllerParam::Player => PlayerController::new().into_box(),
ControllerParam::Random => RandomController::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 mut managed = GameManager::new(game_rules, manager_rules, controller);
let err = managed.play_all(); let err = managed.play_all();
println!("color seed: {color_seed}");
err err
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "rs48_lib" name = "rs48_lib"
version = "1.1.1" version = "1.2.0"
edition = "2021" edition = "2021"
description = "components of rs48" description = "components of rs48"
license = "MIT" license = "MIT"

View file

@ -1,9 +1,9 @@
use rand::{distributions::Standard, prelude::Distribution}; use rand::{distributions::Standard, prelude::Distribution};
use super::grid::Grid; use crate::game::Game;
use std::{error::Error, fmt::Display}; use std::{error::Error, fmt::Display};
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum Move { pub enum Move {
LEFT, LEFT,
RIGHT, RIGHT,
@ -11,6 +11,12 @@ pub enum Move {
DOWN, DOWN,
} }
impl Move {
pub fn all() -> [Self; 4] {
[Self::LEFT, Self::RIGHT, Self::UP, Self::DOWN]
}
}
impl Distribution<Move> for Standard { impl Distribution<Move> for Standard {
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Move { fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Move {
match rng.gen_range(0..4) { match rng.gen_range(0..4) {
@ -39,7 +45,7 @@ impl Display for ControllerError {
impl Error for ControllerError {} impl Error for ControllerError {}
pub trait Controller { pub trait Controller {
fn next_move(&mut self, grid: &Grid) -> Result<Move, ControllerError>; fn next_move(&mut self, game: &Game) -> Result<Move, ControllerError>;
fn into_box(self) -> Box<dyn Controller> fn into_box(self) -> Box<dyn Controller>
where where

View file

@ -2,7 +2,7 @@ use std::io::{stdin, stdout};
use termion::{event::Key, input::TermRead, raw::IntoRawMode}; use termion::{event::Key, input::TermRead, raw::IntoRawMode};
use super::{Controller, ControllerError, Move}; use super::{Controller, ControllerError, Move};
use crate::grid::Grid; use crate::game::Game;
pub struct PlayerController; pub struct PlayerController;
@ -13,7 +13,7 @@ impl PlayerController {
} }
impl Controller for PlayerController { impl Controller for PlayerController {
fn next_move(&mut self, _grid: &Grid) -> Result<Move, ControllerError> { fn next_move(&mut self, _game: &Game) -> Result<Move, ControllerError> {
let stdin = stdin(); let stdin = stdin();
let mut _stdout = stdout() let mut _stdout = stdout()
.into_raw_mode() .into_raw_mode()

View file

@ -1,7 +1,7 @@
use rand::random; use rand::random;
use super::{Controller, ControllerError, Move}; use super::{Controller, ControllerError, Move};
use crate::grid::Grid; use crate::game::Game;
pub struct RandomController; pub struct RandomController;
@ -12,7 +12,7 @@ impl RandomController {
} }
impl Controller for RandomController { impl Controller for RandomController {
fn next_move(&mut self, _grid: &Grid) -> Result<Move, ControllerError> { fn next_move(&mut self, _game: &Game) -> Result<Move, ControllerError> {
let movement = random(); let movement = random();
Ok(movement) Ok(movement)
} }

View file

@ -1,4 +1,4 @@
use crate::grid::Grid; use crate::{game::Game, prelude::RandomController};
use super::{Controller, ControllerError, Move}; use super::{Controller, ControllerError, Move};
@ -8,27 +8,53 @@ pub enum Objective {
} }
pub struct SimulatedController { pub struct SimulatedController {
_simulations_per_move: usize, simulations_per_move: usize,
_length_of_simulation: usize, length_of_simulation: usize,
_objective: Objective,
} }
impl SimulatedController { impl SimulatedController {
pub fn new( pub fn new(simulations_per_move: usize, length_of_simulation: usize) -> Self {
_simulations_per_move: usize,
_length_of_simulation: usize,
_objective: Objective,
) -> Self {
Self { Self {
_simulations_per_move, simulations_per_move,
_length_of_simulation, length_of_simulation,
_objective,
} }
} }
} }
impl Controller for SimulatedController { impl Controller for SimulatedController {
fn next_move(&mut self, _grid: &Grid) -> Result<Move, ControllerError> { fn next_move(&mut self, game: &Game) -> Result<Move, ControllerError> {
todo!() 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())
} }
} }

View file

@ -5,6 +5,7 @@ use super::{
grid::Grid, grid::Grid,
}; };
#[derive(Debug, Clone)]
pub struct Rules { pub struct Rules {
size: usize, size: usize,
spawn_per_turn: usize, spawn_per_turn: usize,
@ -60,6 +61,7 @@ pub struct Game {
score: usize, score: usize,
turn_index: usize, turn_index: usize,
spawn_per_turn: usize, spawn_per_turn: usize,
rules: Rules,
} }
impl Game { impl Game {
@ -67,13 +69,14 @@ impl Game {
let Rules { let Rules {
size, size,
spawn_per_turn, spawn_per_turn,
} = rules; } = rules.clone();
Self { Self {
board: Grid::new(size), board: Grid::new(size),
score: 0, score: 0,
turn_index: 0, turn_index: 0,
spawn_per_turn, spawn_per_turn,
rules,
} }
} }
@ -85,13 +88,16 @@ impl Game {
self.score self.score
} }
pub fn get_rules(&self) -> &Rules {
&self.rules
}
pub fn get_turn_index(&self) -> usize { pub fn get_turn_index(&self) -> usize {
self.turn_index self.turn_index
} }
pub fn turn(&mut self, movement: Move) -> Result<(), GameError> { pub fn turn(&mut self, movement: Move) -> Result<(), GameError> {
let move_score = self.perform_move(movement); self.perform_move(movement);
self.score += move_score;
for _ in 0..self.spawn_per_turn { for _ in 0..self.spawn_per_turn {
self.spawn_random()?; self.spawn_random()?;
} }
@ -156,6 +162,7 @@ impl Game {
} }
} }
}; };
self.score += move_score;
move_score move_score
} }

View file

@ -119,8 +119,7 @@ impl GameManager {
} }
fn game_turn(&mut self) -> Result<(), GameError> { fn game_turn(&mut self) -> Result<(), GameError> {
let board = self.game.get_board(); let movement = self.controller.next_move(&self.game)?;
let movement = self.controller.next_move(board)?;
self.game.turn(movement)?; self.game.turn(movement)?;
Ok(()) Ok(())
} }