first implementation of turtle plans

This commit is contained in:
Niklas Kapelle 2024-08-11 20:17:37 +02:00
parent 249a48807a
commit 8546659ae0
Signed by: niklas
GPG Key ID: 4EB651B36D841D16
3 changed files with 198 additions and 0 deletions

View File

@ -0,0 +1,15 @@
package lib.turtle.planner;
import kernel.turtle.Types.InteractDirections;
enum Action {
Forward;
Back;
Up;
Down;
TurnLeft;
TurnRight;
Clear(dir:InteractDirections); // Digs in the direction. Does not fail if nothing to dig. Trys again if still blocked.
FullTunnel; // Digs front, move forward, dig down. Like a tunnel for a player.
HalfTunnel; // Just clears s 1x2 tunnel infront of it. Like FullTunnel but without moving.
}

View File

@ -0,0 +1,41 @@
package lib.turtle.planner;
import kernel.turtle.Turtle;
using tink.CoreApi;
class Executer {
public function new() {}
public function execute(action:Action) {
var r = translate(action);
switch r {
case Failure(failure):
throw new Error(failure); // I think that this a valid place to use exeptions.
default:
}
}
private function translate(action:Action):Outcome<Noise, String> {
switch (action) {
case Forward:
return Turtle.forward();
case Back:
return Turtle.back();
case Up:
return Turtle.up();
case Down:
return Turtle.down();
case TurnLeft:
return Turtle.turnLeft();
case TurnRight:
return Turtle.turnRight();
case Clear(dir):
return Turtle.digEmpty(dir);
case FullTunnel:
return Helper.combine([Turtle.digEmpty.bind(Front), Turtle.forward, Turtle.digEmpty.bind(Down)]);
case HalfTunnel:
return Helper.combine([Turtle.digEmpty.bind(Front), Turtle.down, Turtle.digEmpty.bind(Front), Turtle.up]);
}
}
}

View File

@ -0,0 +1,142 @@
package lib.turtle.planner;
import kernel.turtle.TurtleMutex;
import kernel.ps.ProcessHandle;
using tink.CoreApi;
/**
A plan repesents a pice of a squence of turtle commands.
It acts like node in a linked list.
It also has no interal state and can be reused.
Once a plan has been setup it (should be) is immutable.
**/
class Plan {
private var prev:Null<Plan>;
private var delegate:(Executer) -> Void;
public static function newPlan():Plan {
return new Plan();
}
private function new() {}
/**
Do a sequence of actions
**/
public function act(actions:Array<Action>):Plan {
#if debug
if (this.delegate != null) {
throw new Error("Can't reuse plans");
}
#end
this.delegate = (ex) -> {
trace('Act: $actions');
for (a in actions) {
ex.execute(a);
}
};
var next = new Plan();
next.prev = this;
return next;
}
/**
Do a sequence of actions multiple times.
**/
public function repeat(actions:Array<Action>, times:Int):Plan {
#if debug
if (this.delegate != null) {
throw new Error("Can't reuse plans");
}
#end
this.delegate = (ex) -> {
trace('Rep: $actions');
for (i in 0...times) {
for (a in actions) {
ex.execute(a);
}
}
};
var next = new Plan();
next.prev = this;
return next;
}
/**
Append a plan to the current chain.
**/
public function subplan(plan:Plan):Plan {
#if debug
if (this.delegate != null) {
throw new Error("Can't reuse plans");
}
#end
this.delegate = (ex) -> {
trace('Subplan');
plan.execute(ex);
};
var next = new Plan();
next.prev = this;
return next;
}
/**
Execute a plan mutiple times.
**/
public function repateSubplan(plan:Plan, times:Int):Plan {
#if debug
if (this.delegate != null) {
throw new Error("Can't reuse plans");
}
#end
this.delegate = (ex) -> {
trace('Subplan repeat');
for (_ in 0...times) {
plan.execute(ex);
}
};
var next = new Plan();
next.prev = this;
return next;
}
private function execute(ex:Executer) {
if (this.prev == null) {
this.delegate(ex);
return;
}
this.prev.execute(ex);
if (this.delegate != null) { // The last plan in a line does not have a delegate
this.delegate(ex);
}
return;
}
public function begin(handle:ProcessHandle) {
trace("begin plan");
if (!handle.claimTurtleMutex()) {
handle.writeLine("Failed to claim turtle mutex");
handle.close();
return;
}
var ex = new Executer();
TurtleMutex.runInTThread(() -> {
try {
this.execute(ex);
} catch (e) {
handle.writeLine(e.message);
}
handle.close(true);
});
}
}