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
|
// do some latency compensation
|
||||||
game_info.calculation_time.set(
|
game_info.calculation_time.set(
|
||||||
game_info.calculation_time.get()
|
game_info.calculation_time.get()
|
||||||
@ -109,23 +125,16 @@ pub fn get_move(game: &Game, turn: i32, board: &Board, you: &Battlesnake) -> Opt
|
|||||||
) / 3,
|
) / 3,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
let deadline = start + game_info.calculation_time.get();
|
||||||
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 mut tree = Node::default();
|
let mut tree = Node::default();
|
||||||
|
|
||||||
while start.elapsed() < game_info.calculation_time.get() {
|
while Instant::now() < deadline {
|
||||||
let mut board = board.clone();
|
let mut board = board.clone();
|
||||||
if game.ruleset.name == "solo" {
|
if game.ruleset.name == "solo" {
|
||||||
tree.monte_carlo_step_solo(&mut board);
|
let _ = tree.monte_carlo_step_solo(&mut board, &deadline);
|
||||||
} else {
|
} else {
|
||||||
tree.monte_carlo_step(&mut board);
|
let _ = tree.monte_carlo_step(&mut board, &deadline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +173,8 @@ struct ActionStatistic {
|
|||||||
won: usize,
|
won: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DeadlineError;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Default)]
|
#[derive(Debug, PartialEq, Eq, Clone, Default)]
|
||||||
struct Node {
|
struct Node {
|
||||||
statistic: Statistics,
|
statistic: Statistics,
|
||||||
@ -175,10 +186,17 @@ impl Node {
|
|||||||
/// Performs one monte carlo simulation step
|
/// Performs one monte carlo simulation step
|
||||||
///
|
///
|
||||||
/// Returns the snake that has won the simulation
|
/// 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 {
|
let winner = if self.statistic.played == 0 {
|
||||||
// We didn't simulate a game for this node yet. Do that
|
// 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()
|
board.snakes().next()
|
||||||
} else {
|
} else {
|
||||||
// select a node to simulate
|
// select a node to simulate
|
||||||
@ -206,12 +224,15 @@ impl Node {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
if Instant::now() >= *deadline {
|
||||||
|
return Err(DeadlineError);
|
||||||
|
}
|
||||||
board.simulate_actions(&actions);
|
board.simulate_actions(&actions);
|
||||||
let winner = self
|
let winner = self
|
||||||
.childs
|
.childs
|
||||||
.entry(actions.clone())
|
.entry(actions.clone())
|
||||||
.or_default()
|
.or_default()
|
||||||
.monte_carlo_step(board);
|
.monte_carlo_step(board, deadline)?;
|
||||||
|
|
||||||
// update child statistics
|
// update child statistics
|
||||||
for (token, action) in &actions {
|
for (token, action) in &actions {
|
||||||
@ -237,7 +258,7 @@ impl Node {
|
|||||||
.and_modify(|won| *won += 1)
|
.and_modify(|won| *won += 1)
|
||||||
.or_insert(1);
|
.or_insert(1);
|
||||||
}
|
}
|
||||||
winner
|
Ok(winner)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs one monte carlo simulation step for a solo game
|
/// Performs one monte carlo simulation step for a solo game
|
||||||
@ -246,7 +267,8 @@ impl Node {
|
|||||||
fn monte_carlo_step_solo(
|
fn monte_carlo_step_solo(
|
||||||
&mut self,
|
&mut self,
|
||||||
board: &mut simulation::Board,
|
board: &mut simulation::Board,
|
||||||
) -> BTreeMap<SnakeToken, usize> {
|
deadline: &Instant,
|
||||||
|
) -> Result<BTreeMap<SnakeToken, usize>, DeadlineError> {
|
||||||
let lengths = if self.statistic.played == 0 {
|
let lengths = if self.statistic.played == 0 {
|
||||||
// We didn't simulate a game for this node yet. Do that
|
// We didn't simulate a game for this node yet. Do that
|
||||||
let mut lengths: BTreeMap<_, _> = board
|
let mut lengths: BTreeMap<_, _> = board
|
||||||
@ -254,6 +276,9 @@ impl Node {
|
|||||||
.filter_map(|snake| Some((snake, board.snake_length(snake)?)))
|
.filter_map(|snake| Some((snake, board.snake_length(snake)?)))
|
||||||
.collect();
|
.collect();
|
||||||
board.simulate_until(|board| {
|
board.simulate_until(|board| {
|
||||||
|
if Instant::now() >= *deadline {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
for snake in board.snakes() {
|
for snake in board.snakes() {
|
||||||
if let Some(length) = board.snake_length(snake) {
|
if let Some(length) = board.snake_length(snake) {
|
||||||
lengths.insert(snake, length);
|
lengths.insert(snake, length);
|
||||||
@ -261,6 +286,9 @@ impl Node {
|
|||||||
}
|
}
|
||||||
board.alive_snakes() == 0
|
board.alive_snakes() == 0
|
||||||
});
|
});
|
||||||
|
if Instant::now() >= *deadline {
|
||||||
|
return Err(DeadlineError);
|
||||||
|
}
|
||||||
lengths
|
lengths
|
||||||
} else {
|
} else {
|
||||||
// select a node to simulate
|
// select a node to simulate
|
||||||
@ -290,12 +318,15 @@ impl Node {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
if Instant::now() >= *deadline {
|
||||||
|
return Err(DeadlineError);
|
||||||
|
}
|
||||||
board.simulate_actions(&actions);
|
board.simulate_actions(&actions);
|
||||||
let lengths = self
|
let lengths = self
|
||||||
.childs
|
.childs
|
||||||
.entry(actions.clone())
|
.entry(actions.clone())
|
||||||
.or_default()
|
.or_default()
|
||||||
.monte_carlo_step_solo(board);
|
.monte_carlo_step_solo(board, deadline)?;
|
||||||
|
|
||||||
// update child statistics
|
// update child statistics
|
||||||
for (token, action) in &actions {
|
for (token, action) in &actions {
|
||||||
@ -321,6 +352,6 @@ impl Node {
|
|||||||
.and_modify(|won| *won += length)
|
.and_modify(|won| *won += length)
|
||||||
.or_insert(*length);
|
.or_insert(*length);
|
||||||
}
|
}
|
||||||
lengths
|
Ok(lengths)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user