Pages

Tuesday, July 22, 2008

More Rock Paper Scissors

Long long ago, I wrote an Interface for people to write Rock Paper Scissors Bots.
We were playing around with them on one open day, I can’t believe that I didn’t blog about it.
Anyway, to distract me from my actual project, I’ve started working on it again, simplifying code and extracting out interfaces with the intention of providing more that one way to join in the tournament (which is currently only if you are specified in code).
IRC seems like a perfect alternative.
One of my first challanges was how to ask two bots for their choices, but only give a limited time before giving up. It would be cool to let humans play as well so my limit is 10 seconds at the moment. The reason I have to ask two bots at once is that I don’t want to ask bot 1, wait at most 10 seconds, then ask bot 2. Both of these can be done at once.

So, using the java.util.concurrent package, I whip up an ExecutorService. The problem with the Executors.defaultThreadFactory() is that when the program ends, those threads from the factory prevent the application from ending.
That’s easy enough to fix:
class DaemonThreadFactory implements ThreadFactory
{
  ThreadFactory impl = Executors.defaultThreadFactory();

  public Thread newThread(Runnable r)
  {
    Thread t = impl.newThread(r);
    t.setDaemon(true);
    return t;
  }
}

Now, I need to wait on two different threads, sounds like a semaphore, or a CountDownLatch in Java. I pass the latch to the Callable that will be done in the other thread.

executor.submit(new Callable()
{
  public Choice call() throws Exception
  {
    Choice result = player.brain.makeMove(round);
    latch.countDown();
    gameEventListener.moveMade(player, result);
    return result;
  }
});

Then it is just a matter of CountDownLatch.await(long timeout, TimeUnit unit)

When you submit a task to the ExecutorService, you get back a Future object which can be check if the task is done and what the result of the Callable was.

future.get(2, TimeUnit.MILLISECONDS);

And this is where the fun begins.

You’ll note that I am waiting 2 milliseconds to get the value, after waiting at most 10 seconds from the latch. I know that the methods were completed because the event “moveMade” was raised.
But sometimes, just sometimes, they get call timesout.

When I was working with Threading in Advanced .Net, I was happy debugging this sort of code because all of the utility methods were my own. I wrote them, I should know what is going on. Here I am just going off the API.

Time to “Mind Meld” with the source code of the FutureTask me thinks. It seems like there is a missing synchronized keyword somewhere but I would have thought that the FutureTask would have taken care of that for me.
I’m almost putting money on there being a “Gotchas” post being made after this one.

No comments:

Post a Comment