I solved the handover problem by simply adding a piggyback member called "recepient" to the ball resource and having each player check it to determine hether the ball was destined for him.

Here's the entire code for posterity.

Player pang holds on to the ball until time=3 and then hands it over to Pong who then play back and forth with Ping.

#!/usr/bin/python

import simpy

ball_wait = 1

def racket(env, name, ball, calc_recipent):
    global turn
    while True:
        # Let the first user catch the ball
        with ball.request() as req:  # Create a waiting resource
            yield req   # Wait and get the ball

            # Check if the ball was for me.
            if ball.recepient == name:
                # The time it takes for the ball to arrive. This can
                # be used to plan the strategy of how to hit the ball.
                yield env.timeout(ball_wait)
                print env.now, name

                # Use the provided callback to calculate the
                # next receipient.
                ball.recepient = calc_recipent(env)

        # Let simpy check the next player.
        yield env.timeout(0)


env = simpy.Environment()

ball = simpy.Resource(env, capacity = 1)
ball.recepient='Pang'
env.process(racket(env,'Ping',ball,lambda env:'Pong'))
env.process(racket(env,'Pong',ball,lambda env:'Ping'))
env.process(racket(env,'Pang',ball,
                   lambda env:'Pang' if env.now < 3 else 'Pong'))

env.run(until=10)
print 'Done!'
Regards,
Dov


On Tue, Mar 4, 2014 at 9:52 PM, Dov Grobgeld <dov.grobgeld@gmail.com> wrote:
Thanks for the answer. I guess I can live with the timeout(0). The game with multiple balls is also ok.

But I'm still having a problem with the hand over of the turn. E.g. if I introduce a third player Pang into the game and then Ping decides whether to send the ball to Pang or to Pong, how would that be done? I guess I could manually rearrange the event queue of ball. Is there any other way?

Regards,
Dov



On Tue, Mar 4, 2014 at 9:10 PM, Stefan Scherfke <stefan@sofa-rockers.org> wrote:
Hi Dov,

> Hello,
>
> While learning how to use simpy for robotics simulations, I got stuck on the
> concept of how to hand over the "turn" between processes (players). Below is an
> example of a two player ping pong simulation, where the ball is a shared
> resource. To hand over the turn each player does a `yield env.timout(0)`. My
> first question is why do you need this timeout, which apprearently does
> nothing?

This is what happens if you inlude the "timeout(0)":

1. When ping leaves the "with" block, "ball.release()" is called (via the
   context manager’s __exit__() method). This schedules an event which will
   let the next process from the ball’s queue use the ball when it (the event)
   is processed by SimPy.

2. ping yields the timeout(0) and hands over execution control so the SimPy
   core.

3. SimPy gets the next event from its event queue. This is the event generated
   ball.release(). At this time, only pong has made another request() to ball
   and ball is available, so pong gets the ball (pongs "req" event is triggered
   and scheduled).

4. The next event in the event queue is ping’s timeout(0). Ping gets resumed
   and makes another request to ball, which will be granted when pong is done.

This is what happens *without* the "timeout(0)":

1. When ping leaves the "with" block, "ball.release()" is called (via the
   context manager’s __exit__() method). This schedules an event which will
   let the next process from the ball’s queue use the ball when it (the event)
   is processed by SimPy.

2. Since ping doesn’t yield an event, it starts over with its loop and makes
   its second request to the ball. At this time, the ball has no user (ping
   was directly removed when ball.release() was called. The request will thus
   be immediately successful and ping goes from the ball’s queue to its user’s
   list. An "req" event is also directly scheduled.

3. ping yields the "req" event.

4. SimPy gets the event generated by "ball.release()" and finds, that its only
   slot is used by ping, so pong continues to wait.

5. Pings "req" event is processed and ping is resumed.

I’m not sure if this is the intended behavior, but at the moment, I don’t think
so. I’ll discuss this issue with Ontje.

> Another question is how to implement handling over the "turn" in
> a more generic fashion? One way I explored is to have the players do an
> infinite env.timeout() and have the other player interrupt it. But this
> approach seems kind of ugly to me. It also does not support the concept of
> a player playing in two games simultaneously. E.g. if a player plays ping-pong
> one game with a red ball and one game with a blue ball and each opponent wants
> to hand over the turn. By catching an interrupt the player won't know who
> interrupted him. This could be solved if there was some kind of a semaphore
> that you could wait on. But perhaps the Event class already supports this, does
> it?

If you had multiple balls, you could do something like this to wait for one
of them:

    with red_ball.request() as rreq, blue_ball.request() as breq:
        yield rreq | breq  # or: yield env.any_of([rreq, breq])


Cheers,
Stefan


>
> Thanks in advance!
>
> Follows my current ping-pong. Looking forward for suggestions on improvements.
> Regards,
> Dov
>
> import simpy
>
> ball_wait = 1
>
> def racket(env, name, ball):
>     while True:
>         # Let the first user catch the ball
>         with ball.request() as req:  # Create a waiting resource
>             yield req   # Wait and get the ball
>
>             # The time it takes for the ball to arrive. This can
>             # be used to plan the strategy of how to hit the ball.
>             yield env.timeout(ball_wait)
>             print env.now, name
>
>         # "Sleep" to get the other user have his turn.
>         yield env.timeout(0)
>
> env = simpy.Environment()
> ball = simpy.Resource(env, capacity = 1)
>
> env.process(racket(env, 'Ping', ball))
> env.process(racket(env, 'Pong', ball))
>
> env.run(until=10)
> print 'Done!'


------------------------------------------------------------------------------
Subversion Kills Productivity. Get off Subversion & Make the Move to Perforce.
With Perforce, you get hassle-free workflows. Merge that actually works.
Faster operations. Version large binaries.  Built-in WAN optimization and the
freedom to use Git, Perforce or both. Make the move to Perforce.
http://pubads.g.doubleclick.net/gampad/clk?id=122218951&iu=/4140/ostg.clktrk
_______________________________________________
Simpy-users mailing list
Simpy-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/simpy-users