bot
This commit is contained in:
parent
80d4c256c0
commit
24ddcce233
9
Cargo.lock
generated
9
Cargo.lock
generated
|
|
@ -1109,6 +1109,14 @@ dependencies = [
|
||||||
"objc2-encode",
|
"objc2-encode",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bot"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"pretty_assertions",
|
||||||
|
"store",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.14.0"
|
version = "3.14.0"
|
||||||
|
|
@ -1242,6 +1250,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bincode",
|
"bincode",
|
||||||
|
"bot",
|
||||||
"pico-args",
|
"pico-args",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"renet",
|
"renet",
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ members = [
|
||||||
"client",
|
"client",
|
||||||
"client_tui",
|
"client_tui",
|
||||||
"client_cli",
|
"client_cli",
|
||||||
|
"bot",
|
||||||
"server",
|
"server",
|
||||||
"store"
|
"store"
|
||||||
]
|
]
|
||||||
|
|
|
||||||
10
bot/Cargo.toml
Normal file
10
bot/Cargo.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "bot"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
pretty_assertions = "1.4.0"
|
||||||
|
store = { path = "../store" }
|
||||||
0
bot/src/bot.rs
Normal file
0
bot/src/bot.rs
Normal file
108
bot/src/lib.rs
Normal file
108
bot/src/lib.rs
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
mod bot;
|
||||||
|
|
||||||
|
use store::{CheckerMove, Color, Dice, GameEvent, GameState, Player, PlayerId, Stage, TurnStage};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Bot {
|
||||||
|
pub game: GameState,
|
||||||
|
player_id: PlayerId,
|
||||||
|
color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Bot {
|
||||||
|
fn default() -> Bot {
|
||||||
|
Bot {
|
||||||
|
game: GameState::default(),
|
||||||
|
player_id: 1,
|
||||||
|
color: Color::Black,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl PlayerEngine for Bot {}
|
||||||
|
|
||||||
|
impl Bot {
|
||||||
|
/// new initialize a bot
|
||||||
|
/// # Examples
|
||||||
|
/// ```let mut bot = Bot::new(Color::Black);
|
||||||
|
/// assert_eq!(bot.game.stage, Stage::PreGame);
|
||||||
|
/// ```
|
||||||
|
pub fn new(color: Color) -> Self {
|
||||||
|
let mut game = GameState::default();
|
||||||
|
game.init_player("p1");
|
||||||
|
game.init_player("p2");
|
||||||
|
|
||||||
|
let player_id = match color {
|
||||||
|
Color::White => 1,
|
||||||
|
Color::Black => 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
game,
|
||||||
|
player_id,
|
||||||
|
color,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consume(&mut self, event: &GameEvent) -> Option<GameEvent> {
|
||||||
|
self.game.consume(event);
|
||||||
|
// println!("{:?}", self.game);
|
||||||
|
if self.game.active_player_id == self.player_id {
|
||||||
|
return match self.game.turn_stage {
|
||||||
|
TurnStage::RollDice => Some(GameEvent::Roll {
|
||||||
|
player_id: self.player_id,
|
||||||
|
}),
|
||||||
|
TurnStage::MarkPoints => Some(GameEvent::Mark {
|
||||||
|
player_id: self.player_id,
|
||||||
|
points: 0,
|
||||||
|
}),
|
||||||
|
TurnStage::Move => Some(GameEvent::Move {
|
||||||
|
player_id: self.player_id,
|
||||||
|
moves: self.choose_move(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose_move(&self) -> (CheckerMove, CheckerMove) {
|
||||||
|
let (dice1, dice2) = match self.color {
|
||||||
|
Color::White => self.game.dice.values,
|
||||||
|
Color::Black => (0 - self.game.dice.values.0, 0 - self.game.dice.values.1),
|
||||||
|
};
|
||||||
|
|
||||||
|
let fields = self.game.board.get_color_fields(self.color);
|
||||||
|
let first_field = fields.first().unwrap();
|
||||||
|
(
|
||||||
|
CheckerMove::new(first_field.0, first_field.0 + dice1 as usize).unwrap(),
|
||||||
|
CheckerMove::new(first_field.0, first_field.0 + dice2 as usize).unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new() {
|
||||||
|
let bot = Bot::new(Color::Black);
|
||||||
|
assert_eq!(bot.game.stage, Stage::PreGame);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_consume() {
|
||||||
|
let mut bot = Bot::new(Color::Black);
|
||||||
|
let mut event = bot.consume(&GameEvent::BeginGame { goes_first: 2 });
|
||||||
|
assert_eq!(event, Some(GameEvent::Roll { player_id: 2 }));
|
||||||
|
|
||||||
|
event = bot.consume(&GameEvent::BeginGame { goes_first: 1 });
|
||||||
|
assert_eq!(event, None);
|
||||||
|
|
||||||
|
event = bot.consume(&GameEvent::RollResult {
|
||||||
|
player_id: 2,
|
||||||
|
dice: Dice { values: (2, 3) },
|
||||||
|
});
|
||||||
|
assert_eq!(bot.game.turn_stage, TurnStage::MarkPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,3 +12,4 @@ pico-args = "0.5.0"
|
||||||
pretty_assertions = "1.4.0"
|
pretty_assertions = "1.4.0"
|
||||||
renet = "0.0.13"
|
renet = "0.0.13"
|
||||||
store = { path = "../store" }
|
store = { path = "../store" }
|
||||||
|
bot = { path = "../bot" }
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
use bot::Bot;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use store::{CheckerMove, Dice, DiceRoller, GameEvent, GameState, PlayerId};
|
use store::{CheckerMove, Color, Dice, DiceRoller, GameEvent, GameState, PlayerId};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct AppArgs {
|
pub struct AppArgs {
|
||||||
|
|
@ -13,6 +14,7 @@ pub struct Game {
|
||||||
pub dice_roller: DiceRoller,
|
pub dice_roller: DiceRoller,
|
||||||
first_move: Option<CheckerMove>,
|
first_move: Option<CheckerMove>,
|
||||||
player_id: Option<PlayerId>,
|
player_id: Option<PlayerId>,
|
||||||
|
bot: Bot,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
|
|
@ -21,16 +23,27 @@ impl Game {
|
||||||
let mut state = GameState::default();
|
let mut state = GameState::default();
|
||||||
// local : player
|
// local : player
|
||||||
let player_id: Option<PlayerId> = state.init_player("myself");
|
let player_id: Option<PlayerId> = state.init_player("myself");
|
||||||
state.init_player("adversary");
|
// bot
|
||||||
state.consume(&GameEvent::BeginGame {
|
let bot_id: PlayerId = state.init_player("bot").unwrap();
|
||||||
goes_first: player_id.unwrap(),
|
let bot_color = state.player_color_by_id(&bot_id).unwrap();
|
||||||
});
|
let bot: Bot = Bot::new(bot_color);
|
||||||
Self {
|
|
||||||
|
let mut game = Self {
|
||||||
state,
|
state,
|
||||||
dice_roller: DiceRoller::new(seed),
|
dice_roller: DiceRoller::new(seed),
|
||||||
first_move: None,
|
first_move: None,
|
||||||
player_id,
|
player_id,
|
||||||
|
bot,
|
||||||
|
};
|
||||||
|
game.consume(&GameEvent::BeginGame {
|
||||||
|
goes_first: player_id.unwrap(),
|
||||||
|
});
|
||||||
|
game
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn consume(&mut self, event: &GameEvent) -> Option<GameEvent> {
|
||||||
|
self.state.consume(&event);
|
||||||
|
self.bot.consume(&event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,7 +91,7 @@ impl App {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let dice = self.game.dice_roller.roll();
|
let dice = self.game.dice_roller.roll();
|
||||||
self.game.state.consume(&GameEvent::RollResult {
|
self.game.consume(&GameEvent::RollResult {
|
||||||
player_id: self.game.player_id.unwrap(),
|
player_id: self.game.player_id.unwrap(),
|
||||||
dice,
|
dice,
|
||||||
});
|
});
|
||||||
|
|
@ -106,7 +119,7 @@ impl App {
|
||||||
self.game.first_move = None;
|
self.game.first_move = None;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.game.state.consume(&move_event);
|
self.game.consume(&move_event);
|
||||||
self.game.first_move = None;
|
self.game.first_move = None;
|
||||||
} else {
|
} else {
|
||||||
self.game.first_move = Some(checker_move.unwrap());
|
self.game.first_move = Some(checker_move.unwrap());
|
||||||
|
|
|
||||||
|
|
@ -296,6 +296,27 @@ impl Board {
|
||||||
self.get_field_checkers(field).map(|(count, color)| color)
|
self.get_field_checkers(field).map(|(count, color)| color)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns the list of Fields containing Checkers of the Color
|
||||||
|
pub fn get_color_fields(&self, color: Color) -> Vec<(usize, i8)> {
|
||||||
|
match color {
|
||||||
|
Color::White => self
|
||||||
|
.positions
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|&(_, count)| *count > 0)
|
||||||
|
.map(|(i, count)| (i + 1, *count))
|
||||||
|
.collect(),
|
||||||
|
Color::Black => self
|
||||||
|
.positions
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|&(_, count)| *count < 0)
|
||||||
|
.rev()
|
||||||
|
.map(|(i, count)| (i + 1, (0 - count)))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the corner field for the color
|
// Get the corner field for the color
|
||||||
pub fn get_color_corner(&self, color: &Color) -> Field {
|
pub fn get_color_corner(&self, color: &Color) -> Field {
|
||||||
if color == &Color::White {
|
if color == &Color::White {
|
||||||
|
|
@ -407,4 +428,11 @@ mod tests {
|
||||||
let player = Player::new("".into(), Color::White);
|
let player = Player::new("".into(), Color::White);
|
||||||
assert!(board.set(&Color::White, 23, -3).is_err());
|
assert!(board.set(&Color::White, 23, -3).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_color_fields() {
|
||||||
|
let board = Board::new();
|
||||||
|
assert_eq!(board.get_color_fields(Color::White), vec![(1, 15)]);
|
||||||
|
assert_eq!(board.get_color_fields(Color::Black), vec![(24, 15)]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,14 @@ impl GameState {
|
||||||
.next()
|
.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn player_color_by_id(&self, player_id: &PlayerId) -> Option<Color> {
|
||||||
|
self.players
|
||||||
|
.iter()
|
||||||
|
.filter(|(id, _)| *id == player_id)
|
||||||
|
.map(|(_, player)| player.color)
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
// Rules checks
|
// Rules checks
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
mod game;
|
mod game;
|
||||||
pub use game::{EndGameReason, GameEvent, GameState, Stage};
|
pub use game::{EndGameReason, GameEvent, GameState, Stage, TurnStage};
|
||||||
|
|
||||||
mod player;
|
mod player;
|
||||||
pub use player::{Color, Player, PlayerId};
|
pub use player::{Color, Player, PlayerId};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue