reuse old simulation states
This commit is contained in:
parent
4e44ac548c
commit
f3d7c3160d
@ -48,6 +48,7 @@ struct GameInfo {
|
||||
calculation_time: Arc<Mutex<Duration>>,
|
||||
token_mapping: Arc<BTreeMap<String, SnakeToken>>,
|
||||
my_token: SnakeToken,
|
||||
tree: Arc<Mutex<Option<Node>>>,
|
||||
}
|
||||
|
||||
static GAME_INFOS: LazyLock<Mutex<HashMap<(String, String), GameInfo>>> =
|
||||
@ -70,6 +71,7 @@ pub fn start(game: &Game, _turn: i32, board: &Board, you: &Battlesnake) {
|
||||
))),
|
||||
token_mapping,
|
||||
my_token,
|
||||
tree: Arc::new(Mutex::new(None)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -114,6 +116,7 @@ pub fn get_move(
|
||||
))),
|
||||
token_mapping,
|
||||
my_token,
|
||||
tree: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
});
|
||||
|
||||
@ -126,12 +129,9 @@ pub fn get_move(
|
||||
game.ruleset.name == "constrictor",
|
||||
);
|
||||
let possible_actions = board.possible_actions().get(&game_info.my_token).cloned()?;
|
||||
if possible_actions.len() <= 1 {
|
||||
info!("Only one movement option exists in turn {turn}. Skipping Tree evaluation");
|
||||
return possible_actions.first().map(|direction| Action {
|
||||
r#move: *direction,
|
||||
shout: None,
|
||||
});
|
||||
if possible_actions.is_empty() {
|
||||
info!("No movement options in turn {turn}");
|
||||
return None;
|
||||
}
|
||||
|
||||
// do some latency compensation
|
||||
@ -153,7 +153,45 @@ pub fn get_move(
|
||||
},
|
||||
);
|
||||
|
||||
let mut tree = Node::default();
|
||||
let mut tree_guard = game_info.tree.lock();
|
||||
let tree = match tree_guard {
|
||||
Err(ref e) => {
|
||||
error!("unable to lock tree: {e}");
|
||||
None
|
||||
}
|
||||
Ok(ref mut guard) => guard.as_mut(),
|
||||
};
|
||||
let mut tree = tree
|
||||
.and_then(|node| {
|
||||
let snake_length_direction: BTreeMap<_, _> = board
|
||||
.snakes()
|
||||
.map(|snake| {
|
||||
let length = board.snake_length(snake).unwrap_or_default();
|
||||
let action = board.last_action(snake).unwrap_or(Direction::Up);
|
||||
(snake, (action, length))
|
||||
})
|
||||
.collect();
|
||||
let node_key = node
|
||||
.childs
|
||||
.keys()
|
||||
.find(|child| {
|
||||
child.iter().all(|(snake, (direction, length))| {
|
||||
snake_length_direction
|
||||
.get(snake)
|
||||
.copied()
|
||||
.unwrap_or((*direction, 0))
|
||||
== (*direction, *length)
|
||||
})
|
||||
})?
|
||||
.clone();
|
||||
let node = node.childs.remove(&node_key)?;
|
||||
info!(
|
||||
"using previous node with {} simulations",
|
||||
node.statistic.played
|
||||
);
|
||||
Some(node)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
while Instant::now() < deadline {
|
||||
let mut board = board.clone();
|
||||
@ -175,6 +213,11 @@ pub fn get_move(
|
||||
.map(|(direction, _)| *direction)
|
||||
.or_else(|| possible_actions.iter().choose(&mut thread_rng()).copied())?;
|
||||
|
||||
if let Ok(ref mut guard) = tree_guard {
|
||||
**guard = Some(tree);
|
||||
}
|
||||
std::mem::drop(tree_guard);
|
||||
|
||||
info!(
|
||||
"DIRECTION {turn}: {chosen:?} after {}ms ({})",
|
||||
start.elapsed().as_millis(),
|
||||
|
@ -118,6 +118,14 @@ impl Board {
|
||||
self.snakes.get(&token).map(|snake| snake.body.len())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn last_action(&self, token: SnakeToken) -> Option<Direction> {
|
||||
self.snakes.get(&token).and_then(|snake| {
|
||||
enum_iterator::all::<Direction>()
|
||||
.find(|direction| snake.body[1].move_to(*direction) == *snake.head())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn simulate_actions(
|
||||
&mut self,
|
||||
actions: &BTreeMap<SnakeToken, Direction>,
|
||||
@ -313,7 +321,6 @@ impl Battlesnake {
|
||||
|
||||
#[must_use]
|
||||
pub fn head(&self) -> &Coord {
|
||||
debug_assert!(!self.body.is_empty());
|
||||
self.body.front().unwrap_or_else(|| unreachable!())
|
||||
&self.body[0]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user