The Santa Claus Problem with Join Patterns

Here is a complete code for an implementation of the Santa Claus Problem with join patterns. Or at least, my initial stab at something approximating a join pattern. This code accompanies the previous post How Do You Solve a Problem Like Santa?.

One may ask “What is with the Twisted?” In this case, I use Twisted to ensure that tasklets sleep for the correct unit of time. Simply using sleep() will put the entire thread (and all the tasklets running in that thread), to sleep). It would not take much effort to make the elves and reindeer represent network connections.

Yes Virginia, one can make Stackless and Twisted interact….

One of these days I will write a stacklessreactor 🙂

Now to find a WordPress theme that has a wider margin…..

#!/usr/bin/env python
"""
joinSanta.py
Andrew Francis

November 17th, 2011

The purpose of joinSanta is as follows:

Show a solution to the Santa Claus problem using a join object
"""

import random

import time
import sys

from twisted.internet                     import reactor
from twisted.internet                     import task
from twisted.python.failure               import Failure

import stackless

# we can use ETIME and RTIME to control how long reindeer
# and elves wait before returning and/or asking questions

RTIME = (10,12)
ETIME = (1,12)


def tick(seconds):
    tickCh = stackless.channel()
    reactor.callLater(seconds, tickCh.send, None)
    tickCh.receive()


def startTwisted():
    reactor.run()


def stopTwisted():
    reactor.callLater(1, reactor.stop)
    print "that's all folks"


"""
a way of telling the tasklets that Santa tasklet is done
"""
def acceptChannels(pattern, status):
    print "[ACCEPTING]"
    for chanop in pattern:
        chanop.channel.send(status)


def worker(ch, name, theRange):
    while True:
       waitTime = random.randint(theRange[0], theRange[1])
       print name, "waiting ", waitTime, " seconds"
       tick(waitTime)
       ch.send(name)
       answer = ch.receive()


def deliveryToys(reindeer):
    print "All the reindeer have arrived - delivering toys"


def consultWithSanta(elves):
    print "Santa consulting with elves"
    acceptChannels(elves, True)


def harness(reindeer):
    for deer in reindeer:
        print "harnessing ", deer.value 


def unharness(reindeer):
    print "unharnessing"
    acceptChannels(reindeer, True)
    

def santa(reindeer, elves):
    print "in santa"
    joinObject = stackless.join().addPattern([ch for _, ch, _ in reindeer]).\
                                  addPattern([ch for _, ch, _ in elves],3)

    reindeerPattern, elfPattern = joinObject.patterns

    while True:
        pattern = joinObject.join()
        print "-->", pattern ,"<---"
        if reindeerPattern.ready():
            print "*** REINDEER GET PRIORITY ***"
            reindeerPattern.join()
            pattern = reindeerPattern
        if pattern is reindeerPattern:
            harness(reindeerPattern)
            deliveryToys(reindeerPattern)
            unharness(reindeerPattern)
        elif pattern is elfPattern:
            consultWithSanta(elfPattern)

    stopTwisted()
    print "Twisted is dead"


def makeWorkers(workers):
    for name, ch, waitTime in workers:
        stackless.tasklet(worker, name)(ch, name, waitTime)
    return 


if __name__ == "__main__":
   random.seed()
   reindeers = [(reindeer, stackless.channel(reindeer), RTIME) for reindeer in \
               ["DANCER", "PRANCER", "VIXEN", "COMET", "CUPID", "DONER", \
                "DASHER", "BLITZEN", "RUDOLPH"]]

   elves = [(elf, stackless.channel(elf), ETIME) for elf in \
            ['A','B','C','D','E','F','G','H','I','J']]
 
   makeWorkers(reindeers)
   makeWorkers(elves)

   l = task.LoopingCall(stackless.schedule)
   l.start(.001)
   stackless.tasklet(startTwisted, "TWISTED")()
   stackless.tasklet(santa,"SANTA")(reindeers, elves)
   stackless.run()

Leave a comment