1
Fork 0

async fn pathing works

This commit is contained in:
Andy Killorin 2023-12-19 17:16:50 -06:00
parent c4e1096588
commit 7bfed6d8af
Signed by: ank
GPG key ID: B6241CA3B552BCA4
4 changed files with 140 additions and 54 deletions

View file

@ -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):")

View file

@ -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),
)
}

View file

@ -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>> {

View file

@ -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)]