allow terminating in progress simulations
This commit is contained in:
parent
d28eec7ef2
commit
12276bc354
@ -100,6 +100,22 @@ pub fn get_move(game: &Game, turn: i32, board: &Board, you: &Battlesnake) -> Opt
|
||||
}
|
||||
});
|
||||
|
||||
let board = simulation::Board::from_game_board(
|
||||
board,
|
||||
&game_info.token_mapping,
|
||||
turn,
|
||||
game.ruleset.settings.food_spawn_chance,
|
||||
game.ruleset.settings.minimum_food,
|
||||
);
|
||||
let possible_actions = board.possible_actions().get(&game_info.my_token).cloned()?;
|
||||
if possible_actions.len() == 1 {
|
||||
info!("Only one movement option exists. Skipping Tree evaluation");
|
||||
return possible_actions.first().map(|direction| Action {
|
||||
r#move: *direction,
|
||||
shout: None,
|
||||
});
|
||||
}
|
||||
|
||||
// do some latency compensation
|
||||
game_info.calculation_time.set(
|
||||
game_info.calculation_time.get()
|
||||
@ -109,23 +125,16 @@ pub fn get_move(game: &Game, turn: i32, board: &Board, you: &Battlesnake) -> Opt
|
||||
) / 3,
|
||||
),
|
||||
);
|
||||
|
||||
let board = simulation::Board::from_game_board(
|
||||
board,
|
||||
&game_info.token_mapping,
|
||||
turn,
|
||||
game.ruleset.settings.food_spawn_chance,
|
||||
game.ruleset.settings.minimum_food,
|
||||
);
|
||||
let deadline = start + game_info.calculation_time.get();
|
||||
|
||||
let mut tree = Node::default();
|
||||
|
||||
while start.elapsed() < game_info.calculation_time.get() {
|
||||
while Instant::now() < deadline {
|
||||
let mut board = board.clone();
|
||||
if game.ruleset.name == "solo" {
|
||||
tree.monte_carlo_step_solo(&mut board);
|
||||
let _ = tree.monte_carlo_step_solo(&mut board, &deadline);
|
||||
} else {
|
||||
tree.monte_carlo_step(&mut board);
|
||||
let _ = tree.monte_carlo_step(&mut board, &deadline);
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,6 +173,8 @@ struct ActionStatistic {
|
||||
won: usize,
|
||||
}
|
||||
|
||||
struct DeadlineError;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Default)]
|
||||
struct Node {
|
||||
statistic: Statistics,
|
||||
@ -175,10 +186,17 @@ impl Node {
|
||||
/// Performs one monte carlo simulation step
|
||||
///
|
||||
/// Returns the snake that has won the simulation
|
||||
fn monte_carlo_step(&mut self, board: &mut simulation::Board) -> Option<SnakeToken> {
|
||||
fn monte_carlo_step(
|
||||
&mut self,
|
||||
board: &mut simulation::Board,
|
||||
deadline: &Instant,
|
||||
) -> Result<Option<SnakeToken>, DeadlineError> {
|
||||
let winner = if self.statistic.played == 0 {
|
||||
// We didn't simulate a game for this node yet. Do that
|
||||
board.simulate_until(|board| board.alive_snakes() <= 1);
|
||||
board.simulate_until(|board| board.alive_snakes() <= 1 || Instant::now() >= *deadline);
|
||||
if Instant::now() >= *deadline {
|
||||
return Err(DeadlineError);
|
||||
}
|
||||
board.snakes().next()
|
||||
} else {
|
||||
// select a node to simulate
|
||||
@ -206,12 +224,15 @@ impl Node {
|
||||
})
|
||||
.collect();
|
||||
|
||||
if Instant::now() >= *deadline {
|
||||
return Err(DeadlineError);
|
||||
}
|
||||
board.simulate_actions(&actions);
|
||||
let winner = self
|
||||
.childs
|
||||
.entry(actions.clone())
|
||||
.or_default()
|
||||
.monte_carlo_step(board);
|
||||
.monte_carlo_step(board, deadline)?;
|
||||
|
||||
// update child statistics
|
||||
for (token, action) in &actions {
|
||||
@ -237,7 +258,7 @@ impl Node {
|
||||
.and_modify(|won| *won += 1)
|
||||
.or_insert(1);
|
||||
}
|
||||
winner
|
||||
Ok(winner)
|
||||
}
|
||||
|
||||
/// Performs one monte carlo simulation step for a solo game
|
||||
@ -246,7 +267,8 @@ impl Node {
|
||||
fn monte_carlo_step_solo(
|
||||
&mut self,
|
||||
board: &mut simulation::Board,
|
||||
) -> BTreeMap<SnakeToken, usize> {
|
||||
deadline: &Instant,
|
||||
) -> Result<BTreeMap<SnakeToken, usize>, DeadlineError> {
|
||||
let lengths = if self.statistic.played == 0 {
|
||||
// We didn't simulate a game for this node yet. Do that
|
||||
let mut lengths: BTreeMap<_, _> = board
|
||||
@ -254,6 +276,9 @@ impl Node {
|
||||
.filter_map(|snake| Some((snake, board.snake_length(snake)?)))
|
||||
.collect();
|
||||
board.simulate_until(|board| {
|
||||
if Instant::now() >= *deadline {
|
||||
return true;
|
||||
}
|
||||
for snake in board.snakes() {
|
||||
if let Some(length) = board.snake_length(snake) {
|
||||
lengths.insert(snake, length);
|
||||
@ -261,6 +286,9 @@ impl Node {
|
||||
}
|
||||
board.alive_snakes() == 0
|
||||
});
|
||||
if Instant::now() >= *deadline {
|
||||
return Err(DeadlineError);
|
||||
}
|
||||
lengths
|
||||
} else {
|
||||
// select a node to simulate
|
||||
@ -290,12 +318,15 @@ impl Node {
|
||||
})
|
||||
.collect();
|
||||
|
||||
if Instant::now() >= *deadline {
|
||||
return Err(DeadlineError);
|
||||
}
|
||||
board.simulate_actions(&actions);
|
||||
let lengths = self
|
||||
.childs
|
||||
.entry(actions.clone())
|
||||
.or_default()
|
||||
.monte_carlo_step_solo(board);
|
||||
.monte_carlo_step_solo(board, deadline)?;
|
||||
|
||||
// update child statistics
|
||||
for (token, action) in &actions {
|
||||
@ -321,6 +352,6 @@ impl Node {
|
||||
.and_modify(|won| *won += length)
|
||||
.or_insert(*length);
|
||||
}
|
||||
lengths
|
||||
Ok(lengths)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user