Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Prototype path finding in Rust bot #48

Merged
merged 1 commit into from
Mar 24, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prototype path finding in Rust bot
The proof-of-concept Rust bot has been rewritten to use path finding to
route airplanes to the airport. The bot also supports multiple airports
and tags now. Path finding is done with an external crate and the A*
algorithm.
jdno committed Mar 24, 2022
commit 9c1934371717d3fb6d09d7c4b5f9130ae5fbb0b5
25 changes: 25 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/starter-rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ publish = false
[dependencies]
atc = { path = "../../sdk/rust", version = "0.1.0", features = ["server"] }

pathfinding = "3.0.11"
tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] }
tokio-stream = { version = "0.1.8" }
tonic = "0.6.2"
87 changes: 79 additions & 8 deletions examples/starter-rust/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::ops::Deref;
use std::rc::Rc;
use std::thread::sleep;
use std::time::Duration;

use pathfinding::prelude::astar;
use tokio_stream::StreamExt;
use tonic::transport::Channel;

use crate::route::route_between;
use atc::v1::airplane_service_client::AirplaneServiceClient;
use atc::v1::event_service_client::EventServiceClient;
use atc::v1::game_service_client::GameServiceClient;
@@ -14,7 +17,11 @@ use atc::v1::{
UpdateFlightPlanRequest,
};

mod route;
use crate::map::{Airport, Map};
use crate::point::{Coord, Point};

mod map;
mod point;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -39,12 +46,43 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
start_game(&mut game_service).await;
}

let mut map = Rc::new(None);

while let Some(message) = stream.next().await {
let event = message.unwrap().event.unwrap();

match event {
Event::AirplaneDetected(airplane_detected) => {
create_flight_plan(&mut airplane_service, airplane_detected).await;
create_flight_plan(&mut airplane_service, airplane_detected, &map).await;
}
Event::GameStarted(game_started) => {
let game_map = game_started.map.unwrap();

let airports = game_map
.airports
.iter()
.map(|airport| {
let node = airport.node.as_ref().unwrap();

Airport {
coord: Coord(node.longitude, node.latitude, false),
tag: airport.tag(),
}
})
.collect();

let routing_grid = game_map
.routing_grid
.iter()
.map(|node| Coord(node.longitude, node.latitude, node.restricted))
.collect();

map = Rc::new(Some(Map {
airports,
routing_grid,
width: game_map.width,
height: game_map.height,
}));
}
Event::GameStopped(game_stopped) => {
let points = game_stopped.score;
@@ -68,19 +106,52 @@ async fn start_game(game_service: &mut GameServiceClient<Channel>) {
async fn create_flight_plan(
airplane_service: &mut AirplaneServiceClient<Channel>,
airplane_detected: AirplaneDetected,
map: &Rc<Option<Map>>,
) {
let airplane = airplane_detected.airplane.unwrap();
let first_hop = airplane
.flight_plan
.get(0)
.expect("expected flight plan to have at least one hop");

let destination = Node {
longitude: 0,
latitude: 0,
restricted: false,
let starting_point = Point {
x: first_hop.longitude,
y: first_hop.latitude,
map: map.clone(),
};

let airport = &map
.deref()
.as_ref()
.unwrap()
.airports
.iter()
.find(|airport| airport.tag == airplane.tag())
.unwrap();

let destination_point = Point {
x: airport.coord.0,
y: airport.coord.1,
map: map.clone(),
};
let route = route_between(first_hop, &destination, true);

let route = astar(
&starting_point,
|p| p.neighbors(),
|p| p.distance(&destination_point) / 3,
|p| p == &destination_point,
)
.unwrap()
.0;

let route = route
.iter()
.map(|point| Node {
longitude: point.x,
latitude: point.y,
restricted: false,
})
.collect();

let request = UpdateFlightPlanRequest {
id: airplane.id,
31 changes: 31 additions & 0 deletions examples/starter-rust/src/map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::{Coord, Point};
use atc::v1::Tag;

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct Airport {
pub coord: Coord,
pub tag: Tag,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct Map {
pub airports: Vec<Airport>,
pub routing_grid: Vec<Coord>,
pub width: u32,
pub height: u32,
}

impl Map {
pub fn coord_at(&self, x: i32, y: i32) -> Coord {
let x = x + self.width as i32 / 2;
let y = y + self.height as i32 / 2;

let index = (y * self.width as i32) + x;

*self.routing_grid.get(index as usize).unwrap()
}

pub fn is_within_bounds(&self, point: &Point) -> bool {
point.x.abs() <= self.width as i32 / 2 && point.y.abs() <= self.height as i32 / 2
}
}
99 changes: 99 additions & 0 deletions examples/starter-rust/src/point.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use std::ops::Deref;
use std::rc::Rc;

use pathfinding::prelude::*;

use crate::map::Map;

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct Coord(pub i32, pub i32, pub bool);

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct Point {
pub x: i32,
pub y: i32,
pub map: Rc<Option<Map>>,
}

impl Point {
pub fn distance(&self, other: &Point) -> u32 {
(absdiff(self.x, other.x) + absdiff(self.y, other.y)) as u32
}

pub fn neighbors(&self) -> Vec<(Point, u32)> {
let potential_neighbors = vec![
(
Point {
x: self.x,
y: self.y + 1,
map: self.map.clone(),
},
1,
),
(
Point {
x: self.x + 1,
y: self.y + 1,
map: self.map.clone(),
},
2,
),
(
Point {
x: self.x + 1,
y: self.y,
map: self.map.clone(),
},
1,
),
(
Point {
x: self.x + 1,
y: self.y - 1,
map: self.map.clone(),
},
2,
),
(
Point {
x: self.x,
y: self.y - 1,
map: self.map.clone(),
},
1,
),
(
Point {
x: self.x - 1,
y: self.y - 1,
map: self.map.clone(),
},
2,
),
(
Point {
x: self.x - 1,
y: self.y,
map: self.map.clone(),
},
1,
),
(
Point {
x: self.x - 1,
y: self.y + 1,
map: self.map.clone(),
},
2,
),
];

let map: &Map = self.map.deref().as_ref().unwrap();

potential_neighbors
.into_iter()
.filter(|(point, _)| map.is_within_bounds(point))
.filter(|(point, _)| !map.coord_at(point.x, point.y).2)
.collect()
}
}
161 changes: 0 additions & 161 deletions examples/starter-rust/src/route.rs

This file was deleted.