2025-01-15 17:46:39 +01:00
|
|
|
use bot::{Bot, BotStrategy};
|
2025-08-08 16:24:12 +02:00
|
|
|
use log::{debug, error};
|
2024-10-16 17:37:38 +02:00
|
|
|
use store::{CheckerMove, DiceRoller, GameEvent, GameState, PlayerId, TurnStage};
|
|
|
|
|
|
|
|
|
|
// Application Game
|
2024-11-04 17:37:36 +01:00
|
|
|
#[derive(Debug, Default)]
|
2024-11-19 17:28:18 +01:00
|
|
|
pub struct GameRunner {
|
2024-10-16 17:37:38 +02:00
|
|
|
pub state: GameState,
|
|
|
|
|
pub dice_roller: DiceRoller,
|
|
|
|
|
pub first_move: Option<CheckerMove>,
|
|
|
|
|
pub player_id: Option<PlayerId>,
|
2024-11-19 17:28:18 +01:00
|
|
|
bots: Vec<Bot>,
|
2024-10-16 17:37:38 +02:00
|
|
|
}
|
|
|
|
|
|
2024-11-19 17:28:18 +01:00
|
|
|
impl GameRunner {
|
2024-10-16 17:37:38 +02:00
|
|
|
// Constructs a new instance of [`App`].
|
2024-11-19 17:28:18 +01:00
|
|
|
pub fn new(
|
|
|
|
|
schools_enabled: bool,
|
|
|
|
|
bot_strategies: Vec<Box<dyn BotStrategy>>,
|
|
|
|
|
seed: Option<u64>,
|
|
|
|
|
) -> Self {
|
2024-10-16 17:37:38 +02:00
|
|
|
let mut state = GameState::new(schools_enabled);
|
|
|
|
|
// local : player
|
2025-01-06 20:27:16 +01:00
|
|
|
let player_id: Option<PlayerId> = if bot_strategies.len() > 1 {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
state.init_player("myself")
|
|
|
|
|
};
|
2024-11-19 17:28:18 +01:00
|
|
|
|
|
|
|
|
// bots
|
2025-01-03 17:40:08 +01:00
|
|
|
let bots: Vec<Bot> = bot_strategies
|
2024-11-19 17:28:18 +01:00
|
|
|
.into_iter()
|
|
|
|
|
.map(|strategy| {
|
|
|
|
|
let bot_id: PlayerId = state.init_player("bot").unwrap();
|
|
|
|
|
let bot_color = state.player_color_by_id(&bot_id).unwrap();
|
|
|
|
|
Bot::new(strategy, bot_color)
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
// let bot_strategy = Box::new(DefaultStrategy::default());
|
2024-11-04 17:37:36 +01:00
|
|
|
// let bot: Bot = Bot::new(bot_strategy, bot_color, schools_enabled);
|
2024-11-19 17:28:18 +01:00
|
|
|
// let bot: Bot = Bot::new(bot_strategy, bot_color);
|
2024-10-16 17:37:38 +02:00
|
|
|
|
2025-01-03 17:40:08 +01:00
|
|
|
let first_player_id = if bots.len() > 1 {
|
|
|
|
|
bots[0].player_id
|
|
|
|
|
} else {
|
|
|
|
|
player_id.unwrap()
|
|
|
|
|
};
|
2024-10-16 17:37:38 +02:00
|
|
|
let mut game = Self {
|
|
|
|
|
state,
|
|
|
|
|
dice_roller: DiceRoller::new(seed),
|
|
|
|
|
first_move: None,
|
|
|
|
|
player_id,
|
2024-11-19 17:28:18 +01:00
|
|
|
bots,
|
2024-10-16 17:37:38 +02:00
|
|
|
};
|
|
|
|
|
game.handle_event(&GameEvent::BeginGame {
|
2025-01-03 17:40:08 +01:00
|
|
|
goes_first: first_player_id,
|
2024-10-16 17:37:38 +02:00
|
|
|
});
|
|
|
|
|
game
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn handle_event(&mut self, event: &GameEvent) -> Option<GameEvent> {
|
2025-05-13 17:46:06 +02:00
|
|
|
if event == &GameEvent::PlayError {
|
2024-10-16 17:37:38 +02:00
|
|
|
return None;
|
|
|
|
|
}
|
2025-05-13 17:46:06 +02:00
|
|
|
let valid_event = if self.state.validate(event) {
|
2025-08-08 16:24:12 +02:00
|
|
|
debug!(
|
2025-08-04 18:04:40 +02:00
|
|
|
"--------------- new valid event {event:?} (stage {:?}) -----------",
|
|
|
|
|
self.state.turn_stage
|
|
|
|
|
);
|
2025-05-13 17:46:06 +02:00
|
|
|
self.state.consume(event);
|
2025-08-08 16:24:12 +02:00
|
|
|
debug!(
|
2025-08-04 18:04:40 +02:00
|
|
|
" --> stage {:?} ; active player points {:?}",
|
|
|
|
|
self.state.turn_stage,
|
|
|
|
|
self.state.who_plays().map(|p| p.points)
|
|
|
|
|
);
|
2025-05-13 17:46:06 +02:00
|
|
|
event
|
|
|
|
|
} else {
|
2025-08-08 16:24:12 +02:00
|
|
|
debug!("{}", self.state);
|
2025-08-04 18:04:40 +02:00
|
|
|
error!("event not valid : {event:?}");
|
|
|
|
|
panic!("crash and burn");
|
2025-05-13 17:46:06 +02:00
|
|
|
&GameEvent::PlayError
|
|
|
|
|
};
|
2025-01-03 17:40:08 +01:00
|
|
|
|
2024-10-16 17:37:38 +02:00
|
|
|
// chain all successive bot actions
|
2025-01-03 17:40:08 +01:00
|
|
|
if self.bots.is_empty() {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Collect bot actions to avoid borrow conflicts
|
|
|
|
|
let bot_events: Vec<GameEvent> = self
|
|
|
|
|
.bots
|
|
|
|
|
.iter_mut()
|
2025-05-13 17:46:06 +02:00
|
|
|
.filter_map(|bot| bot.handle_event(valid_event))
|
2025-01-03 17:40:08 +01:00
|
|
|
.collect();
|
|
|
|
|
|
2025-01-06 20:27:16 +01:00
|
|
|
// if bot_events.len() > 1 {
|
|
|
|
|
// println!(
|
|
|
|
|
// "There might be a problem : 2 bots events : {:?}",
|
|
|
|
|
// bot_events
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
|
2025-01-03 17:40:08 +01:00
|
|
|
let mut next_event = None;
|
|
|
|
|
for bot_event in bot_events {
|
|
|
|
|
let bot_result_event = self.handle_event(&bot_event);
|
|
|
|
|
if let Some(bot_id) = bot_event.player_id() {
|
|
|
|
|
next_event = if self.bot_needs_dice_roll(bot_id) {
|
|
|
|
|
let dice = self.dice_roller.roll();
|
|
|
|
|
self.handle_event(&GameEvent::RollResult {
|
|
|
|
|
player_id: bot_id,
|
|
|
|
|
dice,
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
bot_result_event
|
2025-01-06 20:27:16 +01:00
|
|
|
};
|
2025-01-03 17:40:08 +01:00
|
|
|
}
|
2024-10-16 17:37:38 +02:00
|
|
|
}
|
2025-01-26 17:52:57 +01:00
|
|
|
|
|
|
|
|
if let Some(winner) = self.state.determine_winner() {
|
|
|
|
|
next_event = Some(store::GameEvent::EndGame {
|
|
|
|
|
reason: store::EndGameReason::PlayerWon { winner },
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-03 17:40:08 +01:00
|
|
|
next_event
|
2024-10-16 17:37:38 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-03 17:40:08 +01:00
|
|
|
fn bot_needs_dice_roll(&self, bot_id: PlayerId) -> bool {
|
|
|
|
|
self.state.active_player_id == bot_id && self.state.turn_stage == TurnStage::RollWaiting
|
2024-10-16 17:37:38 +02:00
|
|
|
}
|
|
|
|
|
}
|