views:

82

answers:

4

I have a bunch of procedures that need to be executed successively until either they are all executed, or a certain condition is met. Here's the basic code that needs to be executed until a condition is met:

public boolean search()
{
    robot.go();

    robot.spin();

    //etc - around 8 more similar commands (each takes around 2 seconds)
    return false; //didn't find what it was looking for
}

So far, the only way that I've thought of doing what I wanted is this:

public boolean search()
{
    robot.go(false);
    while(robot.isMoving())
    {
        if(thingFound())
        {
            robot.stop()
            return true;
        }
        Thread.yield();
    }

    robot.spin(false);
    while(robot.isMoving())
    {
        if(thingFound())
        {
            robot.stop()
            return true;
        }
        Thread.yield();
    }


    //etc - around 8 more similar commands
    return false; //didn't find what it was looking for
}

The false parameter to go() and spin() indicates that they should return immediately, allowing the condition to be checked. However, this approach strikes me as rather inefficient, as the same block of code must be repeated 10 times. Could this be achieved more efficiently with exceptions or concurrent Threads?

+3  A: 

Not sure why you are using Thread.yield() - are there other threads executing that you didn't mention? Or maybe I misread the problem.

I think maybe the Command pattern could work here. You would have a RobotCommand interface with an execute method, and an implementation of RobotCommand per command type (go, spin, etc). Then you could construct a RobotAlgorithm as a List of RobotCommand, and have a method executeRobotAlgorithm that iterated over the list, calling execute on each RobotCommand and checking the result of thingFound() after each one.

Edit - oh, I think I get it. Do go and spin kick off threads that change the state of the robot, or something like that?

Edit 2 - in response to your comment, it sounds like the problem here is that you need to be able to return immediately if the robot finds what it's looking for, but the go, spin, etc commands won't do this right now, and you need the ability to keep executing new commands in the meantime. So what I might do here is have two threads - one would be an "executor" thread that would execute your List of RobotCommands one by one, and a "watcher" thread that will repeatedly sleep and poll (check thingFound()). If thingFound() is ever true then you can stop your robot as well as the executor thread, or if the executor gets to the end before thingFound() is true then it can signal as such (if necessary).

danben
If the robot commands are methods like go(), spin() etc, you can use reflection to write the commands, such that the code will be shorter.
binil
That is correct. When called with no parameters, the `while(robot.isMoving()) Thread.yield();` is included within the functions. When called with `true`, the thread starts, but the procedure does not wait for its completion. I hadn't thought of using a List.
Eric
How do I go about stopping the thread?
Eric
Have a local boolean variable `interrupted` that it checks between executions - if `interrupted` is true, exit the main loop. Override the `interrupt()` method to set `interrupted`. Call `interrupt()` on the executor thread when you want to stop it.
danben
A: 

robot can use a Condition object to signal to the controller that it's completed some sub-task or entered a new state:

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/Condition.html

interesting, for the environment that's in you could probably use and notify() and wait() instead of the more flexible Condition. controller could wait() until the robot decides to release him with notify().

jspcal
Regrettably, the Condition class is not availiable in the limited subset of Java I have to play with. The language I am using (LeJOS-NXJ) is a rather limited subset of Java for a LEGO robotics controller.
Eric
+2  A: 

Clearly, the while loop can be packaged into its own function:

private boolean isFound()
{
    while (robot.isMoving())
    {
        if (thingFound())
        {
            robot.stop()
            return true;
        }
        Thread.yield();
    }
    return false;
}

public boolean search()
{
    robot.go(false);
    if (isFound()) return true;

    robot.spin(false);
    if (isFound()) return true;   

    //etc - around 8 more similar commands
    return false; //didn't find what it was looking for
}

(I don't mind if the conditional is split over two lines; I'd probably do that in production code.)

A better Java programmer than I can tell you whether you can pass 'procedures' around (pointers to functions, in terms of C programming). I suspect you can, but I don't know the syntax and rules. The evidence seems to be that you can't (circa 2004, anyway).

Jonathan Leffler
@danben: thanks for the additional confirmation; as you can see, I had found the same thing via a trusty Google search. (One day, I'll experiment again with Bing and see whether it would produce a better answer - but so far, it hasn't done anything much for me. Wolfram Alpha has never deigned to recognize any of my questions as valid. Clearly, I'm not part of their target audience.)
Jonathan Leffler
Right - at the time that I left that comment, you hadn't made your edit. Sorry if it seemed like I was stepping on your toes. Such is the way of SO.
danben
NP danben - as the timing showed, you were typing the comment (which I see you've now removed, so the timing no longer shows) as I was editing my answer. What you did do was save me from having to spend too much longer on whether Java had changed. I did try Bing; on one of the later pages (2 or 3, I think, compared with half way down the first page on Google), found some more recent evidence of the same thing.
Jonathan Leffler
A: 

based on Jonathan Leffler's answer:
you can use a Runnable as pointer to the commands

private final Runnable going = new Runnable() {
    @Override
    public void run() {
        robot.go(false);
    }
});

private final Runnable spinning = new Runnable {
    @Override
    public void run() {
        robot.spin(false);
    }
});

// other commands 


private boolean isFoundAfter(Runnable command)
{
    command.run();
    while (robot.isMoving())
    {
        if (thingFound())
        {
            robot.stop()
            return true;
        }
        Thread.yield();
    }
    return false;
}

public boolean search()
{
    if (isFoundAfter(going)) return true;

    if (isFoundAfter(spinning)) return true;   

    //etc - around 8 more similar commands
    return false; //didn't find what it was looking for
}


one further step, if appropriate, put the commands in an array or a List and execute it as a script

...

private boolean executeSearch(Runnable... commands)
{
    for (Runnable cmd : commands) {
        if (isFoundAfter(cmd)) return true;
    }
    return false; //didn't find what it was looking for
}

public boolean search() {
    return executeSearch(going, spinning /* around 8 more similar commands */);
}
Carlos Heuberger