add maps to matches api
This commit is contained in:
parent
624fa99fad
commit
e26f13c8bb
6 changed files with 45 additions and 13 deletions
|
@ -1,4 +1,4 @@
|
||||||
use diesel::{PgConnection, QueryDsl, QueryResult, RunQueryDsl};
|
use diesel::prelude::*;
|
||||||
|
|
||||||
use crate::schema::maps;
|
use crate::schema::maps;
|
||||||
|
|
||||||
|
@ -26,6 +26,10 @@ pub fn find_map(id: i32, conn: &PgConnection) -> QueryResult<Map> {
|
||||||
maps::table.find(id).get_result(conn)
|
maps::table.find(id).get_result(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_map_by_name(name: &str, conn: &PgConnection) -> QueryResult<Map> {
|
||||||
|
maps::table.filter(maps::name.eq(name)).first(conn)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn list_maps(conn: &PgConnection) -> QueryResult<Vec<Map>> {
|
pub fn list_maps(conn: &PgConnection) -> QueryResult<Vec<Map>> {
|
||||||
maps::table.get_results(conn)
|
maps::table.get_results(conn)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ pub struct NewMatch<'a> {
|
||||||
pub state: MatchState,
|
pub state: MatchState,
|
||||||
pub log_path: &'a str,
|
pub log_path: &'a str,
|
||||||
pub is_public: bool,
|
pub is_public: bool,
|
||||||
|
pub map_id: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Insertable)]
|
#[derive(Insertable)]
|
||||||
|
|
|
@ -111,15 +111,20 @@ impl pb::client_api_service_server::ClientApiService for ClientApiServer {
|
||||||
db::bots::find_bot_with_version_by_name(&match_request.opponent_name, &conn)
|
db::bots::find_bot_with_version_by_name(&match_request.opponent_name, &conn)
|
||||||
.map_err(|_| Status::not_found("opponent not found"))?;
|
.map_err(|_| Status::not_found("opponent not found"))?;
|
||||||
|
|
||||||
|
// TODO: allow map as parameter here
|
||||||
|
let map = db::maps::find_map_by_name(&"hex", &conn)
|
||||||
|
.map_err(|_| Status::not_found("map not found"))?;
|
||||||
|
|
||||||
let player_key = gen_alphanumeric(32);
|
let player_key = gen_alphanumeric(32);
|
||||||
|
|
||||||
let remote_bot_spec = Box::new(RemoteBotSpec {
|
let remote_bot_spec = Box::new(RemoteBotSpec {
|
||||||
player_key: player_key.clone(),
|
player_key: player_key.clone(),
|
||||||
router: self.router.clone(),
|
router: self.router.clone(),
|
||||||
});
|
});
|
||||||
let run_match = RunMatch::from_players(
|
let run_match = RunMatch::new(
|
||||||
self.runner_config.clone(),
|
self.runner_config.clone(),
|
||||||
false,
|
false,
|
||||||
|
map,
|
||||||
vec![
|
vec![
|
||||||
MatchPlayer::BotSpec {
|
MatchPlayer::BotSpec {
|
||||||
spec: remote_bot_spec,
|
spec: remote_bot_spec,
|
||||||
|
|
|
@ -7,6 +7,7 @@ use tokio::task::JoinHandle;
|
||||||
use crate::{
|
use crate::{
|
||||||
db::{
|
db::{
|
||||||
self,
|
self,
|
||||||
|
maps::Map,
|
||||||
matches::{MatchData, MatchResult},
|
matches::{MatchData, MatchResult},
|
||||||
},
|
},
|
||||||
util::gen_alphanumeric,
|
util::gen_alphanumeric,
|
||||||
|
@ -18,6 +19,10 @@ pub struct RunMatch {
|
||||||
players: Vec<MatchPlayer>,
|
players: Vec<MatchPlayer>,
|
||||||
config: Arc<GlobalConfig>,
|
config: Arc<GlobalConfig>,
|
||||||
is_public: bool,
|
is_public: bool,
|
||||||
|
// Map is mandatory for now.
|
||||||
|
// It would be nice to allow "anonymous" (eg. randomly generated) maps
|
||||||
|
// in the future, too.
|
||||||
|
map: Map,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum MatchPlayer {
|
pub enum MatchPlayer {
|
||||||
|
@ -32,9 +37,10 @@ pub enum MatchPlayer {
|
||||||
|
|
||||||
impl RunMatch {
|
impl RunMatch {
|
||||||
// TODO: create a MatchParams struct
|
// TODO: create a MatchParams struct
|
||||||
pub fn from_players(
|
pub fn new(
|
||||||
config: Arc<GlobalConfig>,
|
config: Arc<GlobalConfig>,
|
||||||
is_public: bool,
|
is_public: bool,
|
||||||
|
map: Map,
|
||||||
players: Vec<MatchPlayer>,
|
players: Vec<MatchPlayer>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let log_file_name = format!("{}.log", gen_alphanumeric(16));
|
let log_file_name = format!("{}.log", gen_alphanumeric(16));
|
||||||
|
@ -43,13 +49,14 @@ impl RunMatch {
|
||||||
log_file_name,
|
log_file_name,
|
||||||
players,
|
players,
|
||||||
is_public,
|
is_public,
|
||||||
|
map,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_runner_config(self) -> runner::MatchConfig {
|
fn into_runner_config(self) -> runner::MatchConfig {
|
||||||
runner::MatchConfig {
|
runner::MatchConfig {
|
||||||
map_path: PathBuf::from(&self.config.maps_directory).join("hex.json"),
|
map_path: PathBuf::from(&self.config.maps_directory).join(self.map.file_path),
|
||||||
map_name: "hex".to_string(),
|
map_name: self.map.name,
|
||||||
log_path: PathBuf::from(&self.config.match_logs_directory).join(&self.log_file_name),
|
log_path: PathBuf::from(&self.config.match_logs_directory).join(&self.log_file_name),
|
||||||
players: self
|
players: self
|
||||||
.players
|
.players
|
||||||
|
@ -88,6 +95,7 @@ impl RunMatch {
|
||||||
state: db::matches::MatchState::Playing,
|
state: db::matches::MatchState::Playing,
|
||||||
log_path: &self.log_file_name,
|
log_path: &self.log_file_name,
|
||||||
is_public: self.is_public,
|
is_public: self.is_public,
|
||||||
|
map_id: Some(self.map.id),
|
||||||
};
|
};
|
||||||
let new_match_players = self
|
let new_match_players = self
|
||||||
.players
|
.players
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::db::bots::BotVersion;
|
use crate::db::bots::BotVersion;
|
||||||
|
use crate::db::maps::Map;
|
||||||
use crate::{db::bots::Bot, DbPool, GlobalConfig};
|
use crate::{db::bots::Bot, DbPool, GlobalConfig};
|
||||||
|
|
||||||
use crate::db;
|
use crate::db;
|
||||||
|
@ -15,6 +16,8 @@ use tokio;
|
||||||
const RANKER_INTERVAL: u64 = 60;
|
const RANKER_INTERVAL: u64 = 60;
|
||||||
const RANKER_NUM_MATCHES: i64 = 10_000;
|
const RANKER_NUM_MATCHES: i64 = 10_000;
|
||||||
|
|
||||||
|
const RANKER_MAP_NAME: &str = "hex";
|
||||||
|
|
||||||
pub async fn run_ranker(config: Arc<GlobalConfig>, db_pool: DbPool) {
|
pub async fn run_ranker(config: Arc<GlobalConfig>, db_pool: DbPool) {
|
||||||
// TODO: make this configurable
|
// TODO: make this configurable
|
||||||
// play at most one match every n seconds
|
// play at most one match every n seconds
|
||||||
|
@ -25,7 +28,7 @@ pub async fn run_ranker(config: Arc<GlobalConfig>, db_pool: DbPool) {
|
||||||
.expect("could not get database connection");
|
.expect("could not get database connection");
|
||||||
loop {
|
loop {
|
||||||
interval.tick().await;
|
interval.tick().await;
|
||||||
let bots = db::bots::all_active_bots_with_version(&db_conn).unwrap();
|
let bots = db::bots::all_active_bots_with_version(&db_conn).expect("could not load bots");
|
||||||
if bots.len() < 2 {
|
if bots.len() < 2 {
|
||||||
// not enough bots to play a match
|
// not enough bots to play a match
|
||||||
continue;
|
continue;
|
||||||
|
@ -34,13 +37,17 @@ pub async fn run_ranker(config: Arc<GlobalConfig>, db_pool: DbPool) {
|
||||||
let mut rng = &mut rand::thread_rng();
|
let mut rng = &mut rand::thread_rng();
|
||||||
bots.choose_multiple(&mut rng, 2).cloned().collect()
|
bots.choose_multiple(&mut rng, 2).cloned().collect()
|
||||||
};
|
};
|
||||||
play_ranking_match(config.clone(), selected_bots, db_pool.clone()).await;
|
|
||||||
|
let map =
|
||||||
|
db::maps::find_map_by_name(RANKER_MAP_NAME, &db_conn).expect("could not load map");
|
||||||
|
play_ranking_match(config.clone(), map, selected_bots, db_pool.clone()).await;
|
||||||
recalculate_ratings(&db_conn).expect("could not recalculate ratings");
|
recalculate_ratings(&db_conn).expect("could not recalculate ratings");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn play_ranking_match(
|
async fn play_ranking_match(
|
||||||
config: Arc<GlobalConfig>,
|
config: Arc<GlobalConfig>,
|
||||||
|
map: Map,
|
||||||
selected_bots: Vec<(Bot, BotVersion)>,
|
selected_bots: Vec<(Bot, BotVersion)>,
|
||||||
db_pool: DbPool,
|
db_pool: DbPool,
|
||||||
) {
|
) {
|
||||||
|
@ -53,7 +60,7 @@ async fn play_ranking_match(
|
||||||
players.push(player);
|
players.push(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (_, handle) = RunMatch::from_players(config, true, players)
|
let (_, handle) = RunMatch::new(config, true, map, players)
|
||||||
.run(db_pool.clone())
|
.run(db_pool.clone())
|
||||||
.await
|
.await
|
||||||
.expect("failed to run match");
|
.expect("failed to run match");
|
||||||
|
|
|
@ -14,12 +14,13 @@ use serde::{Deserialize, Serialize};
|
||||||
use super::matches::ApiMatch;
|
use super::matches::ApiMatch;
|
||||||
|
|
||||||
const DEFAULT_OPPONENT_NAME: &str = "simplebot";
|
const DEFAULT_OPPONENT_NAME: &str = "simplebot";
|
||||||
|
const DEFAULT_MAP_NAME: &str = "hex";
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct SubmitBotParams {
|
pub struct SubmitBotParams {
|
||||||
pub code: String,
|
pub code: String,
|
||||||
// TODO: would it be better to pass an ID here?
|
|
||||||
pub opponent_name: Option<String>,
|
pub opponent_name: Option<String>,
|
||||||
|
pub map_name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
@ -40,17 +41,24 @@ pub async fn submit_bot(
|
||||||
.opponent_name
|
.opponent_name
|
||||||
.unwrap_or_else(|| DEFAULT_OPPONENT_NAME.to_string());
|
.unwrap_or_else(|| DEFAULT_OPPONENT_NAME.to_string());
|
||||||
|
|
||||||
|
let map_name = params
|
||||||
|
.map_name
|
||||||
|
.unwrap_or_else(|| DEFAULT_MAP_NAME.to_string());
|
||||||
|
|
||||||
let (opponent_bot, opponent_bot_version) =
|
let (opponent_bot, opponent_bot_version) =
|
||||||
db::bots::find_bot_with_version_by_name(&opponent_name, &conn)
|
db::bots::find_bot_with_version_by_name(&opponent_name, &conn)
|
||||||
.map_err(|_| StatusCode::BAD_REQUEST)?;
|
.map_err(|_| StatusCode::BAD_REQUEST)?;
|
||||||
|
|
||||||
|
let map = db::maps::find_map_by_name(&map_name, &conn).map_err(|_| StatusCode::BAD_REQUEST)?;
|
||||||
|
|
||||||
let player_bot_version = save_code_string(¶ms.code, None, &conn, &config)
|
let player_bot_version = save_code_string(¶ms.code, None, &conn, &config)
|
||||||
// TODO: can we recover from this?
|
// TODO: can we recover from this?
|
||||||
.expect("could not save bot code");
|
.expect("could not save bot code");
|
||||||
|
|
||||||
let run_match = RunMatch::from_players(
|
let run_match = RunMatch::new(
|
||||||
config,
|
config,
|
||||||
false,
|
false,
|
||||||
|
map.clone(),
|
||||||
vec![
|
vec![
|
||||||
MatchPlayer::BotVersion {
|
MatchPlayer::BotVersion {
|
||||||
bot: None,
|
bot: None,
|
||||||
|
@ -82,8 +90,7 @@ pub async fn submit_bot(
|
||||||
bot: Some(opponent_bot),
|
bot: Some(opponent_bot),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
// TODO!
|
map: Some(map),
|
||||||
map: None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let api_match = super::matches::match_data_to_api(full_match_data);
|
let api_match = super::matches::match_data_to_api(full_match_data);
|
||||||
|
|
Loading…
Reference in a new issue