diff --git a/battlesnake/src/main.rs b/battlesnake/src/main.rs index d23df08..6a1eb53 100644 --- a/battlesnake/src/main.rs +++ b/battlesnake/src/main.rs @@ -69,6 +69,7 @@ async fn start(request: Json) { async fn get_move(request: Json) -> response::Json { let start = Instant::now(); let board = Board::from(&*request); + let timeout = Duration::from_millis(u64::from(request.game.timeout)); let id = board.get_id(&request.you.id).unwrap_or_else(|| { error!("My id is not in the simulation board"); 0 @@ -88,33 +89,36 @@ async fn get_move(request: Json) -> response::Json { info!("valid actions: {actions:?}"); tokio::task::spawn_blocking(move || { + if start.elapsed() > Duration::from_millis(10) { + error!( + "The calculation started late ({}ms)", + start.elapsed().as_millis() + ); + } let base_turns = board.turn(); + let rolling_horizon = (u32::from(request.you.length) * 3).max(32); + let last_turn = base_turns + rolling_horizon; let end_condition: &dyn Fn(&Board) -> Option<_> = match &*request.game.ruleset.name { "solo" => &|board| { - if board.num_snakes() == 0 - || board.turn() > base_turns + (u32::from(request.you.length) * 3).min(32) - { + if board.valid_actions(0).count() == 0 || board.turn() > last_turn { Some(()) } else { None } }, _ => &|board| { - if board.num_snakes() <= 1 - || board.turn() > base_turns + (u32::from(request.you.length) * 3).min(32) - { + if board.num_snakes() <= 1 || board.turn() > last_turn { Some(()) } else { None } }, }; - let start_snakes = u32::try_from(board.num_snakes()).unwrap_or(0); let score_fn: &dyn Fn(&Board, u8) -> u32 = match &*request.game.ruleset.name { - "solo" => &|board, _| board.turn(), + "solo" => &|board, id| u32::try_from(board.length(id)).unwrap_or(0), _ => &|board, id| { if board.alive(id) { - 1 + start_snakes - u32::try_from(board.num_snakes()).unwrap_or(start_snakes) + 1 + u32::from(board.max_length() == board.length(id)) } else { 0 } @@ -125,7 +129,7 @@ async fn get_move(request: Json) -> response::Json { .map(|id| MctsManager::new(u8::try_from(id).unwrap())) .collect(); let c = f32::sqrt(2.0); - while start.elapsed() < Duration::from_millis(250) { + while start.elapsed() < timeout * 4 / 5 { let mut board = board.clone(); while end_condition(&board).is_none() { let actions: Vec<_> = mcts_managers diff --git a/battlesnake/src/types/simulation.rs b/battlesnake/src/types/simulation.rs index 63dd247..3cb11c4 100644 --- a/battlesnake/src/types/simulation.rs +++ b/battlesnake/src/types/simulation.rs @@ -210,6 +210,23 @@ impl Board { self.id_to_index(id).is_some() } + #[must_use] + pub fn length(&self, id: u8) -> usize { + let Some(index) = self.id_to_index(id) else { + return 0; + }; + self.snakes[index].body.len() + } + + #[must_use] + pub fn max_length(&self) -> usize { + self.snakes + .iter() + .map(|snake| snake.body.len()) + .max() + .unwrap_or(0) + } + #[must_use] pub fn is_food(&self, tile: Coord) -> bool { let index = self.coord_to_linear(tile);