planetwars.dev/planetwars-matchrunner/src/lib.rs

119 lines
2.9 KiB
Rust
Raw Normal View History

2022-01-18 20:17:13 +01:00
pub mod bot_runner;
2022-01-22 14:32:43 +01:00
pub mod docker_runner;
2022-01-18 20:17:13 +01:00
pub mod match_context;
2022-02-23 21:08:56 +01:00
pub mod match_log;
2022-01-18 20:17:13 +01:00
pub mod pw_match;
2021-12-25 14:45:05 +01:00
use std::{
path::PathBuf,
sync::{Arc, Mutex},
};
2022-01-22 14:32:43 +01:00
use async_trait::async_trait;
2022-02-23 21:08:56 +01:00
use futures::{stream::FuturesOrdered, StreamExt};
2021-12-25 14:45:05 +01:00
use match_context::MatchCtx;
2022-02-23 21:08:56 +01:00
use match_log::{create_log_sink, MatchLogger};
2021-12-25 14:45:05 +01:00
use planetwars_rules::PwConfig;
2022-09-22 19:38:09 +02:00
pub use self::match_context::{EventBus, PlayerHandle};
2021-12-25 14:45:05 +01:00
pub struct MatchConfig {
2021-12-25 21:49:16 +01:00
pub map_name: String,
2021-12-25 14:45:05 +01:00
pub map_path: PathBuf,
pub log_path: PathBuf,
2021-12-28 14:57:41 +01:00
pub players: Vec<MatchPlayer>,
2021-12-25 14:45:05 +01:00
}
2021-12-28 14:57:41 +01:00
pub struct MatchPlayer {
2022-01-22 14:32:43 +01:00
pub bot_spec: Box<dyn BotSpec>,
}
#[async_trait]
2022-02-03 20:46:40 +01:00
pub trait BotSpec: Send + Sync {
2022-01-22 14:32:43 +01:00
async fn run_bot(
&self,
player_id: u32,
event_bus: Arc<Mutex<EventBus>>,
2022-02-23 21:08:56 +01:00
match_logger: MatchLogger,
2022-01-22 14:32:43 +01:00
) -> Box<dyn PlayerHandle>;
2021-12-25 14:45:05 +01:00
}
2022-04-27 20:08:48 +02:00
pub struct MatchOutcome {
pub winner: Option<usize>,
pub player_outcomes: Vec<PlayerOutcome>,
}
pub struct PlayerOutcome {
pub had_errors: bool,
pub crashed: bool,
2022-04-27 20:08:48 +02:00
}
pub async fn run_match(config: MatchConfig) -> MatchOutcome {
2021-12-25 14:45:05 +01:00
let pw_config = PwConfig {
map_file: config.map_path,
2022-08-28 15:47:31 +02:00
max_turns: 500,
2021-12-25 14:45:05 +01:00
};
let event_bus = Arc::new(Mutex::new(EventBus::new()));
2022-02-23 21:08:56 +01:00
let match_logger = create_log_sink(&config.log_path).await;
2021-12-25 14:45:05 +01:00
// start bots
2022-01-22 14:32:43 +01:00
// TODO: what happens when a bot fails?
2021-12-25 14:45:05 +01:00
let players = config
.players
.iter()
.enumerate()
2021-12-28 14:57:41 +01:00
.map(|(player_id, player)| {
2021-12-25 14:45:05 +01:00
let player_id = (player_id + 1) as u32;
2022-02-23 21:08:56 +01:00
start_bot(
player_id,
event_bus.clone(),
2022-03-13 15:20:03 +01:00
player.bot_spec.as_ref(),
2022-02-23 21:08:56 +01:00
match_logger.clone(),
)
2021-12-25 14:45:05 +01:00
})
2022-01-22 14:32:43 +01:00
.collect::<FuturesOrdered<_>>()
// await all results
.collect()
.await;
2021-12-25 21:49:16 +01:00
2022-02-23 21:08:56 +01:00
let match_ctx = MatchCtx::new(event_bus, players, match_logger);
2021-12-25 21:49:16 +01:00
let mut match_instance = pw_match::PwMatch::create(match_ctx, pw_config);
match_instance.run().await;
match_instance.match_ctx.shutdown().await;
let survivors = match_instance.match_state.state().living_players();
2022-04-27 20:08:48 +02:00
let winner = if survivors.len() == 1 {
Some(survivors[0])
} else {
None
};
let player_outcomes = (1..=config.players.len())
.map(|player_id| {
let player_status = &match_instance.player_status[&player_id];
PlayerOutcome {
had_errors: player_status.had_command_errors,
crashed: player_status.terminated,
}
})
.collect();
MatchOutcome {
winner,
player_outcomes,
}
2021-12-25 14:45:05 +01:00
}
2022-01-23 13:23:23 +01:00
// writing this as a closure causes lifetime inference errors
async fn start_bot(
player_id: u32,
event_bus: Arc<Mutex<EventBus>>,
2022-03-13 15:20:03 +01:00
bot_spec: &dyn BotSpec,
2022-02-23 21:08:56 +01:00
match_logger: MatchLogger,
2022-01-23 13:23:23 +01:00
) -> (u32, Box<dyn PlayerHandle>) {
2022-02-23 21:08:56 +01:00
let player_handle = bot_spec.run_bot(player_id, event_bus, match_logger).await;
2022-01-23 13:23:23 +01:00
(player_id, player_handle)
}