reuse old simulation states
This commit is contained in:
parent
4e44ac548c
commit
f3d7c3160d
@ -48,6 +48,7 @@ struct GameInfo {
|
|||||||
calculation_time: Arc<Mutex<Duration>>,
|
calculation_time: Arc<Mutex<Duration>>,
|
||||||
token_mapping: Arc<BTreeMap<String, SnakeToken>>,
|
token_mapping: Arc<BTreeMap<String, SnakeToken>>,
|
||||||
my_token: SnakeToken,
|
my_token: SnakeToken,
|
||||||
|
tree: Arc<Mutex<Option<Node>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
static GAME_INFOS: LazyLock<Mutex<HashMap<(String, String), GameInfo>>> =
|
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,
|
token_mapping,
|
||||||
my_token,
|
my_token,
|
||||||
|
tree: Arc::new(Mutex::new(None)),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -114,6 +116,7 @@ pub fn get_move(
|
|||||||
))),
|
))),
|
||||||
token_mapping,
|
token_mapping,
|
||||||
my_token,
|
my_token,
|
||||||
|
tree: Arc::new(Mutex::new(None)),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -126,12 +129,9 @@ pub fn get_move(
|
|||||||
game.ruleset.name == "constrictor",
|
game.ruleset.name == "constrictor",
|
||||||
);
|
);
|
||||||
let possible_actions = board.possible_actions().get(&game_info.my_token).cloned()?;
|
let possible_actions = board.possible_actions().get(&game_info.my_token).cloned()?;
|
||||||
if possible_actions.len() <= 1 {
|
if possible_actions.is_empty() {
|
||||||
info!("Only one movement option exists in turn {turn}. Skipping Tree evaluation");
|
info!("No movement options in turn {turn}");
|
||||||
return possible_actions.first().map(|direction| Action {
|
return None;
|
||||||
r#move: *direction,
|
|
||||||
shout: None,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// do some latency compensation
|
// 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 {
|
while Instant::now() < deadline {
|
||||||
let mut board = board.clone();
|
let mut board = board.clone();
|
||||||
@ -175,6 +213,11 @@ pub fn get_move(
|
|||||||
.map(|(direction, _)| *direction)
|
.map(|(direction, _)| *direction)
|
||||||
.or_else(|| possible_actions.iter().choose(&mut thread_rng()).copied())?;
|
.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!(
|
info!(
|
||||||
"DIRECTION {turn}: {chosen:?} after {}ms ({})",
|
"DIRECTION {turn}: {chosen:?} after {}ms ({})",
|
||||||
start.elapsed().as_millis(),
|
start.elapsed().as_millis(),
|
||||||
|
@ -118,6 +118,14 @@ impl Board {
|
|||||||
self.snakes.get(&token).map(|snake| snake.body.len())
|
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(
|
pub fn simulate_actions(
|
||||||
&mut self,
|
&mut self,
|
||||||
actions: &BTreeMap<SnakeToken, Direction>,
|
actions: &BTreeMap<SnakeToken, Direction>,
|
||||||
@ -313,7 +321,6 @@ impl Battlesnake {
|
|||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn head(&self) -> &Coord {
|
pub fn head(&self) -> &Coord {
|
||||||
debug_assert!(!self.body.is_empty());
|
&self.body[0]
|
||||||
self.body.front().unwrap_or_else(|| unreachable!())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user