예제 #1
0
파일: KBDesigner.py 프로젝트: dtbinh/kbsim
    def __init__(self, app, config):

        self.app = app
        self.config = config

        self.running = False

        self.bots = []
        self.botmove = None
        self.botsel = None
        self.botselpos = None

        self.orientation = 0
        self.links = []
        self.linkc = self.config['n'] * [0]
        self.conns = []
        self.reddots = []

        self.gui = KBGUI(self)
        self.analyseform = False
        self.connectform = False
        self.executeform = False
        self.clearform = False

        for i in range(self.config['n']):
            self.bots.append(Kilobot(self))

        for b in self.bots:  # set semi-random initial position and orientation
            b.orientation = random.uniform(0, 360)
            b.pos = Vec2d(
                self.config['width'] / 2 + random.uniform(0, b.secretID),
                (self.config['height'] * 2) / 3 +
                random.uniform(0, b.secretID))
예제 #2
0
    def __init__(self, app, config):

        self.app = app
        self.config = config

        self.running = False

        self.bots = []
        self.botmove = None
        self.botsel = None
        self.botselpos = None

        self.orientation = 0
        self.links = []
        self.linkc = self.config["n"] * [0]
        self.conns = []
        self.reddots = []

        self.gui = KBGUI(self)
        self.analyseform = False
        self.connectform = False
        self.executeform = False
        self.clearform = False

        for i in range(self.config["n"]):
            self.bots.append(Kilobot(self))

        for b in self.bots:  # set semi-random initial position and orientation
            b.orientation = random.uniform(0, 360)
            b.pos = Vec2d(
                self.config["width"] / 2 + random.uniform(0, b.secretID),
                (self.config["height"] * 2) / 3 + random.uniform(0, b.secretID),
            )
예제 #3
0
    def __init__(self, app, config):
        ## Simulation - Conf
        self.app = app
        self.config = config

        ## Simulation - Core
        self.round = 0
        self.running = False
        self.stopped = False
        self.clock = pygame.time.Clock() # to track FPS
        self.fps = self.config['fps']

        ## Simulation - Noise
        self.anoise = config['anoise']
        self.inoise = config['inoise']
        self.hearmin = config['hearmin']
        
        ## Simulation - View
        if (config['randomseed'] != None):
            random.seed(config['randomseed'])
        self.abstract = False
        self.gui = KBGUI(self)
        self.designerform = False
        self.restartform = False

        ## Simulation - Bots
        thebot = None
        thefood= None
        
        thebot = imp.load_source("bot", config['program'])
        #thefood = imp.load_source("bot2", config['foodp'])
        
        #print thebot
        #print thefood
        
        #if (self.config['form'] == None):
        #   thebot = imp.load_source("aaa", config['program'])
        #   thefood = imp.load_source("bot2", config['foodp'])  # carrega a comida.
        #else:
        #    thebot = imp.load_source("bot", "./Bots/Renderbot.py")

        self.bots = []
        #self.foods = []
        
        variavel=config['n']
        #print variavel
        
        #self.bots.append(thefood.load(self))
        

        for j in range(config['n']):
                self.bots.append(thebot.load(self))
                self.setFormation(config['formation'])
예제 #4
0
    def __init__(self, app, config):
        ## Simulation - Conf
        self.app = app
        self.config = config

        ## Simulation - Core
        self.round = 0
        self.running = False
        self.stopped = False
        self.clock = pygame.time.Clock()  # to track FPS
        self.fps = self.config['fps']

        ## Simulation - Noise
        self.anoise = config['anoise']
        self.inoise = config['inoise']
        self.hearmin = config['hearmin']

        ## Simulation - View
        if (config['randomseed'] != None):
            random.seed(config['randomseed'])
        self.abstract = False
        self.gui = KBGUI(self)
        self.designerform = False
        self.restartform = False

        ## Simulation - Bots
        thebot = None
        if (self.config['form'] == None):
            thebot = imp.load_source("bot", config['program'])
        else:
            thebot = imp.load_source("bot", "./Bots/Renderbot.py")

        self.bots = []
        for i in range(config['n']):
            self.bots.append(thebot.load(self))
        self.setFormation(config['formation'])
예제 #5
0
    def __init__(self, app, config):
        ## Simulation - Conf
        self.app = app
        self.config = config

        ## Simulation - Core
        self.round = 0
        self.running = False
        self.stopped = False
        self.clock = pygame.time.Clock() # to track FPS
        self.fps = self.config['fps']

        ## Simulation - Noise
        self.anoise = config['anoise']
        self.inoise = config['inoise']
        self.hearmin = config['hearmin']
        
        ## Simulation - View
        if (config['randomseed'] != None):
            random.seed(config['randomseed'])
        self.abstract = False
        self.gui = KBGUI(self)
        self.designerform = False
        self.restartform = False

        ## Simulation - Bots
        thebot = None
        if (self.config['form'] == None):
            thebot = imp.load_source("bot", config['program'])
        else:
            thebot = imp.load_source("bot", "./Bots/Renderbot.py")

        self.bots = []
        for i in range(config['n']):
            self.bots.append(thebot.load(self))
        self.setFormation(config['formation'])
예제 #6
0
class KBSimulation:
    def __init__(self, app, config):
        ## Simulation - Conf
        self.app = app
        self.config = config

        ## Simulation - Core
        self.round = 0
        self.running = False
        self.stopped = False
        self.clock = pygame.time.Clock() # to track FPS
        self.fps = self.config['fps']

        ## Simulation - Noise
        self.anoise = config['anoise']
        self.inoise = config['inoise']
        self.hearmin = config['hearmin']
        
        ## Simulation - View
        if (config['randomseed'] != None):
            random.seed(config['randomseed'])
        self.abstract = False
        self.gui = KBGUI(self)
        self.designerform = False
        self.restartform = False

        ## Simulation - Bots
        thebot = None
        thefood= None
        
        thebot = imp.load_source("bot", config['program'])
        #thefood = imp.load_source("bot2", config['foodp'])
        
        #print thebot
        #print thefood
        
        #if (self.config['form'] == None):
        #   thebot = imp.load_source("aaa", config['program'])
        #   thefood = imp.load_source("bot2", config['foodp'])  # carrega a comida.
        #else:
        #    thebot = imp.load_source("bot", "./Bots/Renderbot.py")

        self.bots = []
        #self.foods = []
        
        variavel=config['n']
        #print variavel
        
        #self.bots.append(thefood.load(self))
        

        for j in range(config['n']):
                self.bots.append(thebot.load(self))
                self.setFormation(config['formation'])




    def setFormation(self, formation):
        if formation == "PILED":
            for b in self.bots:
                b.orientation = random.uniform(0,360)
                b.pos = Vec2d(self.config['width']/2 + random.uniform(0,b.secretID), 
                              self.config['height']/2 + random.uniform(0,b.secretID))

        elif formation == "RANDOM":
            xunit = self.config['width'] / 5
            yunit = self.config['height'] / 5
            for b in self.bots:
                b.orientation = random.uniform(0,360)
                b.pos = Vec2d(random.uniform(yunit, 4*yunit), 
                              random.uniform(xunit, 4*xunit))

        elif formation == "LINE":
            for i in range(0,self.config['n']):
                self.bots[i].pos = Vec2d(self.config['width']/2 + i*34, 
                                         self.config['height']/2)
                self.bots[i].orientation = random.uniform(0,360)            
            self.bots[0].orientation = 180 # make first one point left

        elif formation == "CIRCLE":
            deg = 360 / (self.config['n'])
            pi = 3.141592653589793
            radius = (self.bots[0].radius * (self.config['n'] + 5)) / pi
            
            for i,b in enumerate(self.bots):
                b.orientation = random.uniform(0,360)
                b.pos = Vec2d(self.config['width'] / 2, self.config['height'] / 2) 
                b.pos += Vec2d(0, radius).rotated(deg*i)
                
        elif formation == "Q":
            xunit = self.config['width'] / 5
            yunit = self.config['height'] / 5
            
            for b in self.bots:
                if(b.secretID==0):
                    b.orientation = 0
                    b.pos=Vec2d(150,200)
                    
                elif(b.secretID==1):
                    b.orientation = 0
                    b.pos=Vec2d(250,200)
                    
                else:
                    b.orientation = random.uniform(0,360)
                    b.pos = Vec2d(random.uniform(yunit, 4*yunit), random.uniform(xunit, 4*xunit))

        else:
            print "Unknown formation '%s' - aborting." % (formation)
            exit(-42)           


    def update_bot_collisions(self, botpairs):
        for (i,j) in botpairs:
            a = self.bots[i]
            b = self.bots[j]
            dist = a.pos.get_distance(b.pos)
            bound = 2 * a.radius
            if dist < 1 + bound:
                overlap = bound - dist
                direction = b.pos - a.pos
                if (direction == Vec2d(0,0)):
                    direction = Vec2d(1,0)
                direction.length = overlap/2
                #b.pos = b.pos + direction
                a.pos = a.pos - direction
                b.pos = b.pos #MUDEI


    def update_secretNxs(self, botpairs):
        for b in self.bots: b.secretNx = []

        for (i,j) in botpairs:
            a = self.bots[i]
            b = self.bots[j]
            dist = int(a.pos.get_distance(b.pos))
            if (dist <= self.config['near']): 
                a.secretNx.append(j) # secret
                b.secretNx.append(i) #  neighborhood
        

    def update_messaging(self, botpairs):
        for (i,j) in botpairs:
            a = self.bots[i]
            b = self.bots[j]
            dist = int(a.pos.get_distance(b.pos))
            if (a.running and b.running):
                if (dist < a.rradius and a.tx_enabled == 1): # sends
                        inrange = (a.msgtx[0], a.msgtx[1], a.msgtx[2], dist, 0, 1, 0)
                        b.rxtempbuf.append(inrange)
                if (dist < b.rradius and b.tx_enabled == 1):
                        inrange = (b.msgtx[0], b.msgtx[1], b.msgtx[2], dist, 0, 1, 0)
                        a.rxtempbuf.append(inrange)

        if (self.abstract):
            for b in self.bots:
                numheard = min(len(b.rxtempbuf), self.config['rxbufsize'])            
                random.shuffle(b.rxtempbuf) # ordering randomization (RX/TX delays in HW)
                for i in range(0,numheard):
                    if (b.rxbuf[b.rxbufp][self.config['msg_new']] == 0):
                        b.rxbuf[b.rxbufp] = b.rxtempbuf.pop(0)
                        b.rxbufp = (b.rxbufp + 1) % self.config['rxbufsize']
                b.rxtempbuf = [] #reset
            self.noisestat = 1.0

        else: # SNIR
            noiseOK = 0.0
            noiseFAIL = 0.0
            for b in self.bots:
                k = len(b.rxtempbuf)
                if (k == 0):
                    continue
                k -= 1 # autointerference...
                heard = []
                for m in b.rxtempbuf:
                    randy = random.uniform(50.0,100.0) # delay as random default
                    s = randy / (self.anoise + (k * self.inoise))
                    if s >= self.hearmin:                    
                        noiseOK += 1
                        heard.append(m)
                    else:
                        noiseFAIL += 1

                numheard = min(len(heard), self.config['rxbufsize'])            
                random.shuffle(heard) # ordering randomization (RX/TX delays in HW)

                for i in range(0,numheard):
                    if (b.rxbuf[b.rxbufp][self.config['msg_new']] == 0):
                        b.rxbuf[b.rxbufp] = heard.pop(0)
                        b.rxbufp = (b.rxbufp + 1) % self.config['rxbufsize']
                b.rxtempbuf = [] #reset

            if (self.round % 5 == 0): # too hectic otherwise
                self.noisestat = 0.0 if noiseOK + noiseFAIL == 0 else (noiseOK  / (noiseOK + noiseFAIL))
    
    def stepbots(self):
        # run a step of the program on each bot
        for a in self.bots:
            a.runProgram()


    def designer(self):
        self.config['designer'] = True
        self.running = False

    def restarter(self):
        self.running = False

    def updateUI(self):

        if (self.designerform):
            self.designer()
            self.designerform = False

        if (self.restartform):
            self.restarter()
            self.restartform = False

        # dodge, collision detection on world borders
        self.gui.update_border_collisions() # note: before bot collisions              

      
    def update(self): # called before draw; update variables

        # process bots in pairs, shuffled
        botn = range(len(self.bots))
        botpairs = [(x, y) for x in botn for y in botn if x > y]
        random.shuffle(botpairs)

        # dodge, collision detection on fellow bots
        self.update_bot_collisions(botpairs)
        

        # reset secret (internal) neighborhood information
        self.update_secretNxs(botpairs)
        
       
        # messaging (note: position must be fixed before messaging)
        self.update_messaging(botpairs)
    


    def run(self):
        self.running = True

        # launch ui
        form = gui.Form()
        ui = gui.App()
        ctrl = KBSControl(self)
        c = gui.Container(align=-1,valign=-1)
        c.add(ctrl,0,0)
        ui.init(c)
     
        while self.running:
            self.updateUI()
            if (not self.stopped): 
                self.stepbots()
                self.update()
                self.round += 1
            for e in pygame.event.get():
                self.gui.event(e)
            #ui.event(e)
            self.gui.draw()
            #ui.paint()
            pygame.display.flip()
            self.clock.tick(self.fps)      

        return self.config # running a sim doesn't change the configuration
예제 #7
0
class KBDesigner:
    def __init__(self, app, config):

        self.app = app
        self.config = config

        self.running = False

        self.bots = []
        self.botmove = None
        self.botsel = None
        self.botselpos = None

        self.orientation = 0
        self.links = []
        self.linkc = self.config["n"] * [0]
        self.conns = []
        self.reddots = []

        self.gui = KBGUI(self)
        self.analyseform = False
        self.connectform = False
        self.executeform = False
        self.clearform = False

        for i in range(self.config["n"]):
            self.bots.append(Kilobot(self))

        for b in self.bots:  # set semi-random initial position and orientation
            b.orientation = random.uniform(0, 360)
            b.pos = Vec2d(
                self.config["width"] / 2 + random.uniform(0, b.secretID),
                (self.config["height"] * 2) / 3 + random.uniform(0, b.secretID),
            )

    """
    def parsedatafile(self, targetfile):
        N = 3
        conns = []
        orientation = 0
        with open(targetfile, 'r') as f:
            try:
                for line in f:
                    tok = line.split()
                    if (tok[0] == "KBFORM"):
                        if (tok[1] != str(VERSION)):                    
                            print "Unknown data type, expecting 'KBFORM %2g'" % (VERSION)
                            quit(-42)
                        print ">> Reading data file"
                    elif (tok[0] == "N"):
                        N = int(tok[1])
                    elif (tok[0] == "o"):
                        orientation = int(tok[1])
                    elif (tok[0] == "-"):
                        break
                    elif (tok[0] == "#"):
                        pass
                    else:
                        entry = (int(tok[0]), (int(tok[1]), int(tok[2])), 
                                 (int(tok[3]), int(tok[4])), int(tok[5]))
                        print tok, "    -->   ", entry
                        conns.append(entry)
            except e, msg:
                print "File read failed:", msg
        return N, orientation, conns
        """

    """
    def render(self):
        print ">> Rendering"
        self.reddots = []
        self.links = []
        for i in range(2,self.config['n']):
            rules = None
            for conn in self.conns:
                if (conn[0] == i):
                    rules = conn
                    break
            if (rules == None):
                print "File had no rules for %d, breaking." % (i)
                break
            posA = self.bots[rules[1][0]].pos
            posB = self.bots[rules[2][0]].pos
            posAt = posA.inttup()
            posBt = posB.inttup()
            xA = posAt[0]
            yA = posAt[1]
            xB = posBt[0]
            yB = posBt[1]
            
            rA = rules[1][1]
            rB = rules[2][1]
            ds = posA.get_dist_sqrd(posB)
#            print xA, yA, xB, yB, rA, rB, ds
            Ka = (pow(rA+rB,2) - ds); Ka = 0.01 if Ka < 0 else Ka
            Kb = (ds - pow(rA-rB,2)); Kb = 0.01 if Kb < 0 else Kb # precision...
            K = 0.25 * math.sqrt(Ka * Kb)

            xt = (0.5 * (xB + xA)) + (0.5 * (xB - xA) * ((rA**2) - (rB**2)) / ds)
            yt = (0.5 * (yB + yA)) + (0.5 * (yB - yA) * ((rA**2) - (rB**2)) / ds)
            x1 = xt + (2 * (yB - yA) * K / ds)
            y1 = yt - (2 * (xB - xA) * K / ds)
            x2 = xt - (2 * (yB - yA) * K / ds)
            y2 = yt + (2 * (xB - xA) * K / ds)

#            print i, rules, "posA/B:", posAt, posBt, Vec2d(x1,y1), Vec2d(x2,y2)           
            print " %d:"%(i), Vec2d(x1,y1).inttup(), Vec2d(x2,y2).inttup(), 
            print "choosing", rules[3]
            if (rules[3] == LEFT):
                self.reddots.append(Vec2d(x2,y2))
                self.bots[i].pos = Vec2d(x1,y1)
            else:
                self.reddots.append(Vec2d(x1,y1))
                self.bots[i].pos = Vec2d(x2,y2)

            self.links.append((self.bots[i], self.bots[rules[1][0]]))
            self.links.append((self.bots[i], self.bots[rules[2][0]]))
            """

    def analyser(self):
        print "---\n ANALYSER \n---"
        n = len(self.bots)
        isLinked = filter((lambda x: self.linkc[x] == 1), range(n))
        is2Linked = filter((lambda x: self.linkc[x] == 2), range(n))
        isXLinked = filter((lambda x: self.linkc[x] > 2), range(n))

        print "n = %03d | L0:%03d  L1:%03d  L2:%03d  LX:%03d" % (
            n,
            n - len(isLinked),
            len(isLinked),
            len(is2Linked),
            len(isXLinked),
        )

        if len(is2Linked + isXLinked) < n:
            print "DEGREE TEST FAILED: some have degree < 2"
        else:
            print "DEGREE TEST OK: all have degree >= 2"

    def connecter(self):
        print "---\n CONNECTER \n---"
        poss = []
        for b in self.bots:
            tup = b.pos.inttup()
            poss.append(tup)

        avg = map((lambda x: x / len(self.bots)), reduce((lambda x, y: [x[0] + y[0], x[1] + y[1]]), poss, [0, 0]))
        print "positions:", poss, "\n", "avg:", avg
        avg = Vec2d(avg)

        # computer kNN and find those closest to the center of the bot mass
        # TODO: make less sloppy; proper generative 2-MST etc

        order = []
        k = self.config["n"]
        knns = len(self.bots) * [None]
        for i in range(len(self.bots)):
            bot = self.bots[i]
            dist = avg.get_distance(bot.pos)
            order.append((dist, bot))

            knns[i] = []
            for bat in self.bots:
                if bat == bot:
                    continue
                dist = bot.pos.get_distance(bat.pos)
                knns[i].append([dist, bat])
            knns[i] = sorted(knns[i])[:k]  # drop some

        order = sorted(order)

        # create links
        self.links = []
        self.linkc = self.config["n"] * [0]

        # startup
        a = order[0][1]
        b = order[1][1]
        pair = (a, b) if (a.secretID > b.secretID) else (b, a)
        self.links.append(pair)
        self.linkc[a.secretID] += 1
        self.linkc[b.secretID] += 1

        inplace = [a.secretID, b.secretID]  # keep track of the existing form
        dist = int(round(a.pos.get_distance(b.pos)))
        self.conns = [(1, (0, dist), (0, dist))]  # start conns
        self.orientation = int((b.pos - a.pos).get_angle())

        for i in map((lambda x: x[1].secretID), order[2:]):
            knn = map((lambda x: x[1].secretID), knns[i])
            bot = self.bots[i]
            myid = len(inplace)
            temp = None
            for j in knns[i]:  # try to connect every bot to form as directly as possible
                dist = int(round(j[0]))
                k = j[1].secretID
                bat = self.bots[k]
                if k in inplace:
                    # add links by secretID
                    pair = (bot, bat) if i > k else (bat, bot)
                    self.links.append(pair)
                    self.linkc[bot.secretID] += 1
                    self.linkc[bat.secretID] += 1

                    # add connection by form index
                    if temp == None:
                        inplace.append(i)
                        temp = [k, inplace.index(k), dist]
                    else:
                        but = self.bots[temp.pop(0)]
                        # trigonometric black magic
                        # we compute the angle of bot in relation to a vector defined by to others (bat and but)
                        angle = (bot.pos - bat.pos).rotated(-(but.pos - bat.pos).get_angle()).get_angle()
                        left = angle < 0
                        #                        print bat.secretID, "-->", but.secretID, ":", bot.secretID, "L" if angle < 0 else "R"

                        if left:  # we force RIGHTHANDSIDE positioning
                            self.conns.append((myid, temp, [inplace.index(k), dist]))
                        else:
                            self.conns.append((myid, [inplace.index(k), dist], temp))
                        break

        print "conns:"
        for i, conn in enumerate(self.conns):
            print conn

    def clearer(self):
        self.links = []
        self.linkc = self.config["n"] * [0]

    def executor(self):
        if self.conns == []:
            print "SANITY CHECK: No conns, won't start execution"
            return

        print self.orientation

        self.config["form"] = {
            "version": "KBFORM 0.1",
            "n": self.config["n"],
            "orientation": self.orientation,
            "rules": self.conns,
        }

        self.config["designer"] = False
        self.running = False

    def updateUI(self):

        # analyse the current form
        if self.analyseform:
            self.analyser()
            self.analyseform = False

        if self.connectform:
            self.connecter()
            self.connectform = False

        if self.clearform:
            self.clearer()
            self.clearform = False

        if self.executeform:
            self.executor()
            self.executeform = False

        # dodge, collision detection on world borders
        self.gui.update_border_collisions()  # note: before bot collisions

    def update(self):  # called before draw; update variables

        # process bots in pairs, shuffled
        botn = range(len(self.bots))
        botpairs = [(x, y) for x in botn for y in botn if x > y]
        random.shuffle(botpairs)

        # dodge, collision detection on fellow bots
        for (i, j) in botpairs:
            a = self.bots[i]
            b = self.bots[j]
            dist = a.pos.get_distance(b.pos)
            bound = 2 * a.radius
            if dist < 1 + bound:
                overlap = bound - dist
                direction = b.pos - a.pos
                if direction == Vec2d(0, 0):
                    direction = Vec2d(1, 0)
                direction.length = overlap / 2
                b.pos = b.pos + direction
                a.pos = a.pos - direction

    def run(self):
        self.running = True

        # launch ui
        form = gui.Form()
        ui = gui.App()
        ctrl = KBDControl(self)
        c = gui.Container(align=-1, valign=-1)
        c.add(ctrl, 0, 0)
        ui.init(c)

        while self.running:
            self.updateUI()
            self.update()
            for e in pygame.event.get():
                self.gui.event(e)
                ui.event(e)
            self.gui.draw()
            ui.paint()
            pygame.display.flip()

        return self.config
예제 #8
0
class KBSimulation:
    def __init__(self, app, config):
        ## Simulation - Conf
        self.app = app
        self.config = config

        ## Simulation - Core
        self.round = 0
        self.running = False
        self.stopped = False
        self.clock = pygame.time.Clock()  # to track FPS
        self.fps = self.config['fps']

        ## Simulation - Noise
        self.anoise = config['anoise']
        self.inoise = config['inoise']
        self.hearmin = config['hearmin']

        ## Simulation - View
        if (config['randomseed'] != None):
            random.seed(config['randomseed'])
        self.abstract = False
        self.gui = KBGUI(self)
        self.designerform = False
        self.restartform = False

        ## Simulation - Bots
        thebot = None
        if (self.config['form'] == None):
            thebot = imp.load_source("bot", config['program'])
        else:
            thebot = imp.load_source("bot", "./Bots/Renderbot.py")

        self.bots = []
        for i in range(config['n']):
            self.bots.append(thebot.load(self))
        self.setFormation(config['formation'])

    def setFormation(self, formation):
        if formation == "PILED":
            for b in self.bots:
                b.orientation = random.uniform(0, 360)
                b.pos = Vec2d(
                    self.config['width'] / 2 + random.uniform(0, b.secretID),
                    self.config['height'] / 2 + random.uniform(0, b.secretID))

        elif formation == "RANDOM":
            xunit = self.config['width'] / 5
            yunit = self.config['height'] / 5
            for b in self.bots:
                b.orientation = random.uniform(0, 360)
                b.pos = Vec2d(random.uniform(yunit, 4 * yunit),
                              random.uniform(xunit, 4 * xunit))

        elif formation == "LINE":
            for i in range(0, self.config['n']):
                self.bots[i].pos = Vec2d(self.config['width'] / 2 + i * 34,
                                         self.config['height'] / 2)
                self.bots[i].orientation = random.uniform(0, 360)
            self.bots[0].orientation = 180  # make first one point left

        elif formation == "CIRCLE":
            deg = 360 / (self.config['n'])
            pi = 3.141592653589793
            radius = (self.bots[0].radius * (self.config['n'] + 5)) / pi

            for i, b in enumerate(self.bots):
                b.orientation = random.uniform(0, 360)
                b.pos = Vec2d(self.config['width'] / 2,
                              self.config['height'] / 2)
                b.pos += Vec2d(0, radius).rotated(deg * i)

        else:
            print "Unknown formation '%s' - aborting." % (formation)
            exit(-42)

    def update_bot_collisions(self, botpairs):
        for (i, j) in botpairs:
            a = self.bots[i]
            b = self.bots[j]
            dist = a.pos.get_distance(b.pos)
            bound = 2 * a.radius
            if dist < 1 + bound:
                overlap = bound - dist
                direction = b.pos - a.pos
                if (direction == Vec2d(0, 0)):
                    direction = Vec2d(1, 0)
                direction.length = overlap / 2
                b.pos = b.pos + direction
                a.pos = a.pos - direction

    def update_secretNxs(self, botpairs):
        for b in self.bots:
            b.secretNx = []

        for (i, j) in botpairs:
            a = self.bots[i]
            b = self.bots[j]
            dist = int(a.pos.get_distance(b.pos))
            if (dist <= self.config['near']):
                a.secretNx.append(j)  # secret
                b.secretNx.append(i)  #  neighborhood

    def update_messaging(self, botpairs):
        for (i, j) in botpairs:
            a = self.bots[i]
            b = self.bots[j]
            dist = int(a.pos.get_distance(b.pos))
            if (a.running and b.running):
                if (dist < a.rradius and a.tx_enabled == 1):  # sends
                    inrange = (a.msgtx[0], a.msgtx[1], a.msgtx[2], dist, 0, 1,
                               0)
                    b.rxtempbuf.append(inrange)
                if (dist < b.rradius and b.tx_enabled == 1):
                    inrange = (b.msgtx[0], b.msgtx[1], b.msgtx[2], dist, 0, 1,
                               0)
                    a.rxtempbuf.append(inrange)

        if (self.abstract):
            for b in self.bots:
                numheard = min(len(b.rxtempbuf), self.config['rxbufsize'])
                random.shuffle(
                    b.rxtempbuf)  # ordering randomization (RX/TX delays in HW)
                for i in range(0, numheard):
                    if (b.rxbuf[b.rxbufp][self.config['msg_new']] == 0):
                        b.rxbuf[b.rxbufp] = b.rxtempbuf.pop(0)
                        b.rxbufp = (b.rxbufp + 1) % self.config['rxbufsize']
                b.rxtempbuf = []  #reset
            self.noisestat = 1.0

        else:  # SNIR
            noiseOK = 0.0
            noiseFAIL = 0.0
            for b in self.bots:
                k = len(b.rxtempbuf)
                if (k == 0):
                    continue
                k -= 1  # autointerference...
                heard = []
                for m in b.rxtempbuf:
                    randy = random.uniform(50.0,
                                           100.0)  # delay as random default
                    s = randy / (self.anoise + (k * self.inoise))
                    if s >= self.hearmin:
                        noiseOK += 1
                        heard.append(m)
                    else:
                        noiseFAIL += 1

                numheard = min(len(heard), self.config['rxbufsize'])
                random.shuffle(
                    heard)  # ordering randomization (RX/TX delays in HW)

                for i in range(0, numheard):
                    if (b.rxbuf[b.rxbufp][self.config['msg_new']] == 0):
                        b.rxbuf[b.rxbufp] = heard.pop(0)
                        b.rxbufp = (b.rxbufp + 1) % self.config['rxbufsize']
                b.rxtempbuf = []  #reset

            if (self.round % 5 == 0):  # too hectic otherwise
                self.noisestat = 0.0 if noiseOK + noiseFAIL == 0 else (
                    noiseOK / (noiseOK + noiseFAIL))

    def stepbots(self):
        # run a step of the program on each bot
        for a in self.bots:
            a.runProgram()

    def designer(self):
        self.config['designer'] = True
        self.running = False

    def restarter(self):
        self.running = False

    def updateUI(self):

        if (self.designerform):
            self.designer()
            self.designerform = False

        if (self.restartform):
            self.restarter()
            self.restartform = False

        # dodge, collision detection on world borders
        self.gui.update_border_collisions()  # note: before bot collisions

    def update(self):  # called before draw; update variables

        # process bots in pairs, shuffled
        botn = range(len(self.bots))
        botpairs = [(x, y) for x in botn for y in botn if x > y]
        random.shuffle(botpairs)

        # dodge, collision detection on fellow bots
        self.update_bot_collisions(botpairs)

        # reset secret (internal) neighborhood information
        self.update_secretNxs(botpairs)

        # messaging (note: position must be fixed before messaging)
        self.update_messaging(botpairs)

    def run(self):
        self.running = True

        # launch ui
        form = gui.Form()
        ui = gui.App()
        ctrl = KBSControl(self)
        c = gui.Container(align=-1, valign=-1)
        c.add(ctrl, 0, 0)
        ui.init(c)

        while self.running:
            self.updateUI()
            if (not self.stopped):
                self.stepbots()
                self.update()
                self.round += 1
            for e in pygame.event.get():
                self.gui.event(e)
                ui.event(e)
            self.gui.draw()
            ui.paint()
            pygame.display.flip()
            self.clock.tick(self.fps)

        return self.config  # running a sim doesn't change the configuration
예제 #9
0
파일: KBDesigner.py 프로젝트: dtbinh/kbsim
class KBDesigner:
    def __init__(self, app, config):

        self.app = app
        self.config = config

        self.running = False

        self.bots = []
        self.botmove = None
        self.botsel = None
        self.botselpos = None

        self.orientation = 0
        self.links = []
        self.linkc = self.config['n'] * [0]
        self.conns = []
        self.reddots = []

        self.gui = KBGUI(self)
        self.analyseform = False
        self.connectform = False
        self.executeform = False
        self.clearform = False

        for i in range(self.config['n']):
            self.bots.append(Kilobot(self))

        for b in self.bots:  # set semi-random initial position and orientation
            b.orientation = random.uniform(0, 360)
            b.pos = Vec2d(
                self.config['width'] / 2 + random.uniform(0, b.secretID),
                (self.config['height'] * 2) / 3 +
                random.uniform(0, b.secretID))

    """
    def parsedatafile(self, targetfile):
        N = 3
        conns = []
        orientation = 0
        with open(targetfile, 'r') as f:
            try:
                for line in f:
                    tok = line.split()
                    if (tok[0] == "KBFORM"):
                        if (tok[1] != str(VERSION)):                    
                            print "Unknown data type, expecting 'KBFORM %2g'" % (VERSION)
                            quit(-42)
                        print ">> Reading data file"
                    elif (tok[0] == "N"):
                        N = int(tok[1])
                    elif (tok[0] == "o"):
                        orientation = int(tok[1])
                    elif (tok[0] == "-"):
                        break
                    elif (tok[0] == "#"):
                        pass
                    else:
                        entry = (int(tok[0]), (int(tok[1]), int(tok[2])), 
                                 (int(tok[3]), int(tok[4])), int(tok[5]))
                        print tok, "    -->   ", entry
                        conns.append(entry)
            except e, msg:
                print "File read failed:", msg
        return N, orientation, conns
        """
    """
    def render(self):
        print ">> Rendering"
        self.reddots = []
        self.links = []
        for i in range(2,self.config['n']):
            rules = None
            for conn in self.conns:
                if (conn[0] == i):
                    rules = conn
                    break
            if (rules == None):
                print "File had no rules for %d, breaking." % (i)
                break
            posA = self.bots[rules[1][0]].pos
            posB = self.bots[rules[2][0]].pos
            posAt = posA.inttup()
            posBt = posB.inttup()
            xA = posAt[0]
            yA = posAt[1]
            xB = posBt[0]
            yB = posBt[1]
            
            rA = rules[1][1]
            rB = rules[2][1]
            ds = posA.get_dist_sqrd(posB)
#            print xA, yA, xB, yB, rA, rB, ds
            Ka = (pow(rA+rB,2) - ds); Ka = 0.01 if Ka < 0 else Ka
            Kb = (ds - pow(rA-rB,2)); Kb = 0.01 if Kb < 0 else Kb # precision...
            K = 0.25 * math.sqrt(Ka * Kb)

            xt = (0.5 * (xB + xA)) + (0.5 * (xB - xA) * ((rA**2) - (rB**2)) / ds)
            yt = (0.5 * (yB + yA)) + (0.5 * (yB - yA) * ((rA**2) - (rB**2)) / ds)
            x1 = xt + (2 * (yB - yA) * K / ds)
            y1 = yt - (2 * (xB - xA) * K / ds)
            x2 = xt - (2 * (yB - yA) * K / ds)
            y2 = yt + (2 * (xB - xA) * K / ds)

#            print i, rules, "posA/B:", posAt, posBt, Vec2d(x1,y1), Vec2d(x2,y2)           
            print " %d:"%(i), Vec2d(x1,y1).inttup(), Vec2d(x2,y2).inttup(), 
            print "choosing", rules[3]
            if (rules[3] == LEFT):
                self.reddots.append(Vec2d(x2,y2))
                self.bots[i].pos = Vec2d(x1,y1)
            else:
                self.reddots.append(Vec2d(x1,y1))
                self.bots[i].pos = Vec2d(x2,y2)

            self.links.append((self.bots[i], self.bots[rules[1][0]]))
            self.links.append((self.bots[i], self.bots[rules[2][0]]))
            """

    def analyser(self):
        print "---\n ANALYSER \n---"
        n = len(self.bots)
        isLinked = filter((lambda x: self.linkc[x] == 1), range(n))
        is2Linked = filter((lambda x: self.linkc[x] == 2), range(n))
        isXLinked = filter((lambda x: self.linkc[x] > 2), range(n))

        print "n = %03d | L0:%03d  L1:%03d  L2:%03d  LX:%03d" % (
            n, n - len(isLinked), len(isLinked), len(is2Linked),
            len(isXLinked))

        if (len(is2Linked + isXLinked) < n):
            print "DEGREE TEST FAILED: some have degree < 2"
        else:
            print "DEGREE TEST OK: all have degree >= 2"

    def connecter(self):
        print "---\n CONNECTER \n---"
        poss = []
        for b in self.bots:
            tup = b.pos.inttup()
            poss.append(tup)

        avg = map((lambda x: x / len(self.bots)),
                  reduce((lambda x, y: [x[0] + y[0], x[1] + y[1]]), poss,
                         [0, 0]))
        print "positions:", poss, "\n", "avg:", avg
        avg = Vec2d(avg)

        # computer kNN and find those closest to the center of the bot mass
        # TODO: make less sloppy; proper generative 2-MST etc

        order = []
        k = self.config['n']
        knns = len(self.bots) * [None]
        for i in range(len(self.bots)):
            bot = self.bots[i]
            dist = avg.get_distance(bot.pos)
            order.append((dist, bot))

            knns[i] = []
            for bat in self.bots:
                if (bat == bot): continue
                dist = bot.pos.get_distance(bat.pos)
                knns[i].append([dist, bat])
            knns[i] = sorted(knns[i])[:k]  # drop some

        order = sorted(order)

        # create links
        self.links = []
        self.linkc = self.config['n'] * [0]

        # startup
        a = order[0][1]
        b = order[1][1]
        pair = (a, b) if (a.secretID > b.secretID) else (b, a)
        self.links.append(pair)
        self.linkc[a.secretID] += 1
        self.linkc[b.secretID] += 1

        inplace = [a.secretID, b.secretID]  # keep track of the existing form
        dist = int(round(a.pos.get_distance(b.pos)))
        self.conns = [(1, (0, dist), (0, dist))]  # start conns
        self.orientation = int((b.pos - a.pos).get_angle())

        for i in map((lambda x: x[1].secretID), order[2:]):
            knn = map((lambda x: x[1].secretID), knns[i])
            bot = self.bots[i]
            myid = len(inplace)
            temp = None
            for j in knns[
                    i]:  # try to connect every bot to form as directly as possible
                dist = int(round(j[0]))
                k = j[1].secretID
                bat = self.bots[k]
                if (k in inplace):
                    # add links by secretID
                    pair = (bot, bat) if i > k else (bat, bot)
                    self.links.append(pair)
                    self.linkc[bot.secretID] += 1
                    self.linkc[bat.secretID] += 1

                    # add connection by form index
                    if (temp == None):
                        inplace.append(i)
                        temp = [k, inplace.index(k), dist]
                    else:
                        but = self.bots[temp.pop(0)]
                        # trigonometric black magic
                        # we compute the angle of bot in relation to a vector defined by to others (bat and but)
                        angle = (bot.pos - bat.pos).rotated(
                            -(but.pos - bat.pos).get_angle()).get_angle()
                        left = angle < 0
                        #                        print bat.secretID, "-->", but.secretID, ":", bot.secretID, "L" if angle < 0 else "R"

                        if (left):  # we force RIGHTHANDSIDE positioning
                            self.conns.append(
                                (myid, temp, [inplace.index(k), dist]))
                        else:
                            self.conns.append((myid, [inplace.index(k),
                                                      dist], temp))
                        break

        print "conns:"
        for i, conn in enumerate(self.conns):
            print conn

    def clearer(self):
        self.links = []
        self.linkc = self.config['n'] * [0]

    def executor(self):
        if (self.conns == []):
            print "SANITY CHECK: No conns, won't start execution"
            return

        print self.orientation

        self.config['form'] = {
            'version': "KBFORM 0.1",
            'n': self.config['n'],
            'orientation': self.orientation,
            'rules': self.conns
        }

        self.config['designer'] = False
        self.running = False

    def updateUI(self):

        # analyse the current form
        if (self.analyseform):
            self.analyser()
            self.analyseform = False

        if (self.connectform):
            self.connecter()
            self.connectform = False

        if (self.clearform):
            self.clearer()
            self.clearform = False

        if (self.executeform):
            self.executor()
            self.executeform = False

        # dodge, collision detection on world borders
        self.gui.update_border_collisions()  # note: before bot collisions

    def update(self):  # called before draw; update variables

        # process bots in pairs, shuffled
        botn = range(len(self.bots))
        botpairs = [(x, y) for x in botn for y in botn if x > y]
        random.shuffle(botpairs)

        # dodge, collision detection on fellow bots
        for (i, j) in botpairs:
            a = self.bots[i]
            b = self.bots[j]
            dist = a.pos.get_distance(b.pos)
            bound = 2 * a.radius
            if dist < 1 + bound:
                overlap = bound - dist
                direction = b.pos - a.pos
                if (direction == Vec2d(0, 0)):
                    direction = Vec2d(1, 0)
                direction.length = overlap / 2
                b.pos = b.pos + direction
                a.pos = a.pos - direction

    def run(self):
        self.running = True

        # launch ui
        form = gui.Form()
        ui = gui.App()
        ctrl = KBDControl(self)
        c = gui.Container(align=-1, valign=-1)
        c.add(ctrl, 0, 0)
        ui.init(c)

        while self.running:
            self.updateUI()
            self.update()
            for e in pygame.event.get():
                self.gui.event(e)
                ui.event(e)
            self.gui.draw()
            ui.paint()
            pygame.display.flip()

        return self.config