From 12066e223eeafb2d0495908da43d7b63b3adff8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20CORTIER?= Date: Sun, 31 May 2020 15:02:04 -0400 Subject: [PATCH] examples/rust: complete test level --- examples/rust-bot/src/bot.rs | 34 ++++++++++++++++++++++++++-------- examples/rust-bot/src/path.rs | 30 +++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/examples/rust-bot/src/bot.rs b/examples/rust-bot/src/bot.rs index ceb73a4..c3dec7e 100644 --- a/examples/rust-bot/src/bot.rs +++ b/examples/rust-bot/src/bot.rs @@ -11,11 +11,13 @@ use std::vec; #[derive(Debug)] pub struct UserData { ninja_handle: usize, + enemy_handle: usize, target: CellPos, button: CellPos, path: vec::IntoIter, current_target: Option, activated: bool, + is_going_to_button: bool, } pub fn init() {} @@ -25,9 +27,12 @@ pub fn start_level(api: &mut Api) -> UserData { api.log_trace(api.map.to_string()); let mut ninja_handle_opt = None; + let mut enemy_handle_opt = None; for entity in &api.entities { - if let EntityKind::Dll = entity.kind() { - ninja_handle_opt = Some(entity.handle()); + match entity.kind() { + EntityKind::Harmless | EntityKind::Patrol | EntityKind::Aggressive => enemy_handle_opt = Some(entity.handle()), + EntityKind::Dll => ninja_handle_opt = Some(entity.handle()), + _ => {} } } @@ -40,26 +45,39 @@ pub fn start_level(api: &mut Api) -> UserData { UserData { ninja_handle: ninja_handle_opt.expect("ninja clown not found"), + enemy_handle: enemy_handle_opt.unwrap_or(usize::MAX), target: CellPos::new(2, 1), button: button_bos.expect("button not found"), path: Vec::new().into_iter(), current_target: None, activated: false, + is_going_to_button: false, } } pub fn think(api: &mut Api, data: &mut UserData) { let ninja_clown = api.entities.get(data.ninja_handle).expect("ninja clown not found"); + if let Some(enemy) = api.entities.get(data.enemy_handle) { + let dist = absdiff(enemy.x(), ninja_clown.x()) + absdiff(enemy.y(), ninja_clown.y()); + if dist < ninja_clown.properties().attack_range() { + api.commit_decisions(&[Decision::attack(data.enemy_handle).commit(data.ninja_handle)]); + api.log_info("Attack!"); + return; + } + } + // compute path graph if data.current_target.is_none() || api.map.changed() { let start = CellPos::new(ninja_clown.x() as usize, ninja_clown.y() as usize); let graph = PathGraph::build(&api.map); let path = if let Some(path) = graph.path_to(&start, &data.target) { + data.is_going_to_button = false; api.log_info("Moving to the target!"); path } else if let Some(path) = graph.path_to(&start, &data.button) { + data.is_going_to_button = true; api.log_info("Moving to the button!"); path } else { @@ -78,12 +96,12 @@ pub fn think(api: &mut Api, data: &mut UserData) { }; let dist = absdiff(target.center_x(), ninja_clown.x()) + absdiff(target.center_y(), ninja_clown.y()); - if dist < 0.6 { - let interaction = api.map.cell_at_pos(target).unwrap().interaction(); - if !data.activated && interaction != InteractionKind::NoInteraction { - api.commit_decisions(&[Decision::activate(target.column(), target.line()).commit(data.ninja_handle)]); - data.activated = true; - } else if let Some(next_target) = data.path.next() { + let interaction = api.map.cell_at_pos(target).unwrap().interaction(); + if dist < ninja_clown.properties().activate_range() && !data.activated && interaction != InteractionKind::NoInteraction && data.is_going_to_button { + api.commit_decisions(&[Decision::activate(target.column(), target.line()).commit(data.ninja_handle)]); + data.activated = true; + } else if dist < 0.5 { + if let Some(next_target) = data.path.next() { let decision = move_towards(ninja_clown, &next_target); api.commit_decisions(&[decision]); data.current_target = Some(next_target); diff --git a/examples/rust-bot/src/path.rs b/examples/rust-bot/src/path.rs index 9a0b7aa..3f747dd 100644 --- a/examples/rust-bot/src/path.rs +++ b/examples/rust-bot/src/path.rs @@ -5,13 +5,13 @@ use ninja_clown_bot::{ use pathfinding::prelude::{absdiff, astar}; use std::collections::HashMap; -fn pos_dist(a: &CellPos, b: &CellPos) -> usize { - absdiff(a.column(), b.column()) + absdiff(a.line(), b.line()) +fn pos_dist(a: &CellPos, b: &CellPos) -> u64 { + (absdiff(a.center_x(), b.center_x()) + absdiff(a.center_y(), b.center_y()) * 10.0) as u64 } #[derive(Clone, Debug)] pub struct PathGraph { - successors: HashMap>, + successors: HashMap>, } impl PathGraph { @@ -39,7 +39,27 @@ impl PathGraph { .iter() { if let Some(CellKind::Ground) = map.cell_at(*x, *y).map(|c| c.kind()) { - successors.push(CellPos::new(*x, *y)); + successors.push((CellPos::new(*x, *y), 10)); + } + } + + for (x, y) in [ + (cell.column().saturating_sub(1), cell.line() + 1), + (cell.column() + 1, cell.line() + 1), + (cell.column().saturating_sub(1), cell.line().saturating_sub(1)), + (cell.column() + 1, cell.line().saturating_sub(1)), + ] + .iter() + { + match ( + map.cell_at(*x, *y).map(|c| c.kind()), + map.cell_at(*x, cell.line()).map(|c| c.kind()), + map.cell_at(cell.column(), *y).map(|c| c.kind()), + ) { + (Some(CellKind::Ground), Some(CellKind::Ground), Some(CellKind::Ground)) => { + successors.push((CellPos::new(*x, *y), 15)); + } + _ => {} } } @@ -54,7 +74,7 @@ impl PathGraph { |p| { self.successors .get(p) - .map(|v| v.iter().cloned().map(|p| (p, 1)).collect()) + .map(|v| v.iter().cloned().map(|(p, cost)| (p, cost)).collect()) .unwrap_or_else(Vec::new) }, |p| pos_dist(p, goal) / 3,