async fn pathing works
This commit is contained in:
parent
c4e1096588
commit
7bfed6d8af
4 changed files with 140 additions and 54 deletions
|
@ -70,6 +70,8 @@ if not idfile then
|
|||
local fuel = turtle.getFuelLevel()
|
||||
if fs.exists("/disk/pos") then
|
||||
io.input("/disk/pos")
|
||||
else
|
||||
io.input(io.stdin)
|
||||
end
|
||||
local startpos = io.input()
|
||||
print("Direction (North, South, East, West):")
|
||||
|
|
|
@ -23,7 +23,7 @@ use tokio::sync::{
|
|||
Mutex, RwLock, mpsc
|
||||
};
|
||||
use tower::Service;
|
||||
use turtle::{TurtleTask, Iota, Receiver, Sender, Turtle, TurtleUpdate, TurtleInfo, goto, TurtleCommand};
|
||||
use turtle::{TurtleTask, Iota, Receiver, Sender, Turtle, TurtleUpdate, TurtleInfo, TurtleCommand, TurtleCommander};
|
||||
|
||||
use crate::{blocks::Block, paths::route};
|
||||
|
||||
|
@ -42,23 +42,26 @@ struct SavedState {
|
|||
}
|
||||
|
||||
struct LiveState {
|
||||
turtles: Vec<turtle::Turtle>,
|
||||
turtles: Vec<Arc<RwLock<turtle::Turtle>>>,
|
||||
tasks: Vec<VecDeque<TurtleMineJob>>,
|
||||
world: blocks::World,
|
||||
}
|
||||
|
||||
impl LiveState {
|
||||
async fn to_save(self) -> SavedState {
|
||||
SavedState { turtles: self.turtles, world: self.world.to_tree().await }
|
||||
}
|
||||
|
||||
async fn save(&self) -> SavedState {
|
||||
let turtles = self.turtles.iter().map(|t| t.info());
|
||||
SavedState { turtles: turtles.collect(), world: self.world.tree().await }
|
||||
let mut turtles = Vec::new();
|
||||
for turtle in self.turtles.iter() {
|
||||
turtles.push(turtle.read().await.info());
|
||||
};
|
||||
SavedState { turtles, world: self.world.tree().await }
|
||||
}
|
||||
|
||||
fn from_save(save: SavedState) -> Self {
|
||||
Self { turtles: save.turtles, tasks: Vec::new(), world: World::from_tree(save.world) }
|
||||
Self { turtles: save.turtles.into_iter().map(|t| Arc::new(RwLock::new(t))).collect(), tasks: Vec::new(), world: World::from_tree(save.world) }
|
||||
}
|
||||
|
||||
async fn get_turtle(&self, name: u32) -> Option<TurtleCommander> {
|
||||
TurtleCommander::new(Name::from_num(name), self).await
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -128,7 +131,10 @@ async fn create_turtle(
|
|||
let state = &mut state.write().await;
|
||||
let id = state.turtles.len() as u32;
|
||||
let (send, receive) = mpsc::channel(1);
|
||||
state.turtles.push(turtle::Turtle::with_channel(id, Position::new(req.position, req.facing), req.fuel, send,receive));
|
||||
state.turtles.push(
|
||||
Arc::new(RwLock::new(
|
||||
turtle::Turtle::with_channel(id, Position::new(req.position, req.facing), req.fuel, send,receive)
|
||||
)));
|
||||
state.tasks.push(VecDeque::new());
|
||||
|
||||
|
||||
|
@ -145,23 +151,35 @@ async fn place_up(
|
|||
Path(id): Path<u32>,
|
||||
State(state): State<SharedControl>,
|
||||
) -> Json<TurtleInfo> {
|
||||
let turtle = state.read().await.turtles.get(id as usize).unwrap()
|
||||
.cmd();
|
||||
let turtle = state.read().await.get_turtle(id).await.unwrap();
|
||||
let response = turtle.execute(turtle::TurtleCommand::PlaceUp).await;
|
||||
|
||||
Json(response)
|
||||
}
|
||||
|
||||
async fn dig(
|
||||
Path(id): Path<u32>,
|
||||
State(state): State<SharedControl>,
|
||||
Json(req): Json<Position>,
|
||||
) -> &'static str {
|
||||
let turtle = state.read().await.get_turtle(id).await.unwrap();
|
||||
tokio::spawn(
|
||||
async move {
|
||||
turtle.goto_adjacent(req.pos).await;
|
||||
turtle.execute(TurtleCommand::Dig).await
|
||||
}
|
||||
);
|
||||
|
||||
"ACK"
|
||||
}
|
||||
|
||||
async fn set_goal(
|
||||
Path(id): Path<u32>,
|
||||
State(state): State<SharedControl>,
|
||||
Json(req): Json<Position>,
|
||||
) -> &'static str {
|
||||
let state = state.read().await;
|
||||
let turtle = state.turtles[id as usize].cmd();
|
||||
let info = turtle.execute(TurtleCommand::Wait(0)).await;
|
||||
|
||||
tokio::spawn(goto(turtle.clone(), info, req, state.world.clone()));
|
||||
let turtle = state.read().await.get_turtle(id).await.unwrap();
|
||||
tokio::spawn(async move {turtle.goto(req).await});
|
||||
|
||||
"ACK"
|
||||
}
|
||||
|
@ -176,12 +194,10 @@ async fn cancel(
|
|||
}
|
||||
|
||||
async fn update_turtles(State(state): State<SharedControl>) -> &'static str {
|
||||
state
|
||||
.write()
|
||||
.await
|
||||
.turtles
|
||||
.iter_mut()
|
||||
.for_each(|t| t.pending_update = true);
|
||||
for turtle in state .write().await.turtles.iter_mut() {
|
||||
turtle.write().await.pending_update = true;
|
||||
}
|
||||
|
||||
"ACK"
|
||||
}
|
||||
|
||||
|
@ -190,7 +206,7 @@ async fn turtle_info(
|
|||
State(state): State<SharedControl>,
|
||||
) -> Json<turtle::Turtle> {
|
||||
let state = &mut state.read().await;
|
||||
let turtle = &state.turtles[id as usize];
|
||||
let turtle = &state.turtles[id as usize].read().await;
|
||||
|
||||
let cloned = Turtle::new(
|
||||
turtle.name.to_num(),
|
||||
|
@ -215,7 +231,8 @@ async fn command(
|
|||
}
|
||||
|
||||
Json(
|
||||
turtle::process_turtle_update(id, &mut state, req).await.unwrap_or(turtle::TurtleCommand::Update),
|
||||
turtle::process_turtle_update(id, &mut state, req).await
|
||||
.unwrap_or(turtle::TurtleCommand::Update),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,12 @@ use crate::{
|
|||
};
|
||||
use pathfinding::prelude::astar;
|
||||
|
||||
pub async fn route_facing(from: Position, to: Position, world: &World) -> Option<Vec<Position>> {
|
||||
pub async fn route_facing(from: Position, to: Vec3, world: &World) -> Option<Vec<Position>> {
|
||||
let facing = |p: &Position| {
|
||||
let ahead = p.dir.unit() + p.pos;
|
||||
to.pos == ahead
|
||||
to == ahead
|
||||
};
|
||||
route_to(from, to.pos, facing, world).await
|
||||
route_to(from, to, facing, world).await
|
||||
}
|
||||
|
||||
pub async fn route(from: Position, to: Position, world: &World) -> Option<Vec<Position>> {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
use crate::SharedControl;
|
||||
use crate::blocks::Block;
|
||||
use crate::blocks::Direction;
|
||||
use crate::blocks::Position;
|
||||
|
@ -6,6 +7,7 @@ use crate::blocks::Vec3;
|
|||
use crate::blocks::World;
|
||||
use crate::blocks::nearest;
|
||||
use crate::mine::TurtleMineJob;
|
||||
use crate::paths::route_facing;
|
||||
|
||||
use anyhow::Ok;
|
||||
|
||||
|
@ -124,19 +126,25 @@ impl Turtle {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cmd(&self) -> TurtleCommander {
|
||||
TurtleCommander { sender: self.sender.as_ref().unwrap().clone() }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TurtleCommander {
|
||||
sender: Arc<Sender>,
|
||||
world: World,
|
||||
turtle: Arc<RwLock<Turtle>>,
|
||||
}
|
||||
|
||||
impl TurtleCommander {
|
||||
pub async fn new(turtle: Name, state: &LiveState) -> Option<TurtleCommander> {
|
||||
let turtle = state.turtles.get(turtle.to_num() as usize)?.clone();
|
||||
Some(TurtleCommander {
|
||||
sender:turtle.clone().read().await.sender.as_ref().unwrap().clone(),
|
||||
world: state.world.clone(),
|
||||
turtle,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn execute(&self, command: TurtleCommand) -> TurtleInfo {
|
||||
let (send, recv) = oneshot::channel::<TurtleInfo>();
|
||||
|
||||
|
@ -144,10 +152,22 @@ impl TurtleCommander {
|
|||
|
||||
recv.await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn goto(cmd: TurtleCommander, recent: TurtleInfo, pos: Position, world: World) -> Option<()> {
|
||||
let mut recent = recent.pos;
|
||||
pub async fn pos(&self) -> Position {
|
||||
self.turtle.read().await.position
|
||||
}
|
||||
|
||||
pub async fn fuel(&self) -> usize {
|
||||
self.turtle.read().await.fuel
|
||||
}
|
||||
|
||||
pub async fn world(&self) -> World {
|
||||
self.world.clone()
|
||||
}
|
||||
|
||||
pub async fn goto(&self, pos: Position) -> Option<()> {
|
||||
let mut recent = self.pos().await;
|
||||
let world = self.world.clone();
|
||||
loop {
|
||||
if recent == pos {
|
||||
break;
|
||||
|
@ -165,22 +185,52 @@ pub async fn goto(cmd: TurtleCommander, recent: TurtleInfo, pos: Position, world
|
|||
break 'route;
|
||||
}
|
||||
|
||||
let state = cmd.execute(command).await;
|
||||
let state = self.execute(command).await;
|
||||
recent = state.pos;
|
||||
}
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub async fn goto_adjacent(&self, pos: Vec3) -> Option<Position> {
|
||||
let mut recent = self.pos().await;
|
||||
let world = self.world.clone();
|
||||
loop {
|
||||
|
||||
if pos == recent.dir.unit() + recent.pos {
|
||||
break;
|
||||
}
|
||||
|
||||
let route = route_facing(recent, pos, &world).await?;
|
||||
|
||||
let steps: Vec<TurtleCommand> = route.iter().map_windows(|[from,to]| from.difference(**to).unwrap()).collect();
|
||||
|
||||
'route: for (next_position, command) in route.into_iter().skip(1).zip(steps) {
|
||||
// reroute if the goal point is not empty before moving
|
||||
// valid routes will explicitly tell you to break ground
|
||||
|
||||
if world.occupied(next_position.pos).await {
|
||||
break 'route;
|
||||
}
|
||||
|
||||
let state = self.execute(command).await;
|
||||
recent = state.pos;
|
||||
}
|
||||
}
|
||||
Some(recent)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub(crate) async fn process_turtle_update(
|
||||
id: u32,
|
||||
state: &mut LiveState,
|
||||
update: TurtleUpdate,
|
||||
) -> anyhow::Result<TurtleCommand> {
|
||||
let turtle = state
|
||||
let mut turtle = state
|
||||
.turtles
|
||||
.get_mut(id as usize)
|
||||
.context("nonexisting turtle")?;
|
||||
.context("nonexisting turtle")?.write().await;
|
||||
let tasks = state
|
||||
.tasks
|
||||
.get_mut(id as usize)
|
||||
|
@ -193,9 +243,14 @@ pub(crate) async fn process_turtle_update(
|
|||
}
|
||||
|
||||
if turtle.fuel != update.fuel {
|
||||
let diff = turtle.fuel - update.fuel;
|
||||
turtle.fuel = update.fuel;
|
||||
|
||||
turtle.position.pos += turtle.queued_movement;
|
||||
if diff > 0 {
|
||||
let delta = turtle.queued_movement * diff as i32;
|
||||
|
||||
turtle.position.pos += delta;
|
||||
}
|
||||
turtle.queued_movement = Vec3::zeros();
|
||||
}
|
||||
|
||||
|
@ -232,6 +287,7 @@ pub(crate) async fn process_turtle_update(
|
|||
TurtleCommand::Right => turtle.position.dir = turtle.position.dir.right(),
|
||||
_ => {}
|
||||
}
|
||||
turtle.queued_movement = cmd.unit(turtle.position.dir);
|
||||
return Ok(cmd);
|
||||
}
|
||||
}
|
||||
|
@ -293,6 +349,17 @@ impl TurtleCommand {
|
|||
_ => Vec3::zeros(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unit(&self, direction: Direction) -> Vec3 {
|
||||
let dir = direction.unit();
|
||||
match self {
|
||||
TurtleCommand::Forward(_) => dir,
|
||||
TurtleCommand::Backward(_) => -dir,
|
||||
TurtleCommand::Up(_) => Vec3::y(),
|
||||
TurtleCommand::Down(_) => -Vec3::y(),
|
||||
_ => Vec3::zeros(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
|
Loading…
Reference in a new issue