Example #1
0
 def __init__(self, arqEndereco, arqEstrategia):
     super(MonitorAspirador, self).__init__()
     self.enderecos = Enderecos(arqEndereco)
     self.endereco = self.enderecos.endereco("monitor")
     self.participantes = {}
     self._log = []
     self.configuracao = json.load(open(arqEstrategia))
Example #2
0
 def __init__(self, configSim, configExe, configEnd, configComp):
     super(TestadorAspirador, self).__init__()
     self.configs = {}
     self.configs['sim'] = json.load(open(configSim))
     self.configs['exe'] = json.load(open(configExe))
     self.enderecos = Enderecos(configEnd)
     self.componentes = Componentes(configComp)
Example #3
0
    def __init__(self, agId, configEnd, configCom):
        super(AspiradorIII, self).__init__()

        self.mid = agId
        self.enderecos = Enderecos(configEnd)
        self.endereco = self.enderecos.endereco('agente')
        self.enderecoMonitor = self.enderecos.endereco('monitor')
        self.componentes  = Componentes(configCom)

        self.socketReceive = None
        self.socketSend = None

        self.enviar = True #True se agente deve enviar mensagem, False caso esteja esperando resposta
        self.agindo = True #False para enviar ação de perceber
        self.ENERGIAMAX = 80.0
        self.limiteRecarga = 0.25

        self.RESERVATORIOMAX = 4
        self.PLANO_EXPLORAR = 0
        self.PLANO_RECARREGAR = 1
        self.PLANO_DEPOSITAR = 2
        self.PLANO_SUJEIRA = 3
        self.tiposPlano = (self.PLANO_EXPLORAR, self.PLANO_RECARREGAR, self.PLANO_DEPOSITAR, self.PLANO_SUJEIRA)

        self.reiniciarMemoria()
Example #4
0
 def __init__(self, configEst, configEnd, configCom):
     super(Nsga2, self).__init__()
     self.crossoverProb = 0.0
     self.mutacaoProb = 0.0
     self.componentes = Componentes(configCom)
     self.configuracoes = json.load(open(configEst))
     self.enderecos = Enderecos(configEnd)
     self.enderecos.participantes()
     #TODO: guardar o log
     self.npop = 0
     self.maxite = 0
Example #5
0
class MonitorAspirador(Monitor):
    def __init__(self, arqEndereco, arqEstrategia):
        super(MonitorAspirador, self).__init__()
        self.enderecos = Enderecos(arqEndereco)
        self.endereco = self.enderecos.endereco("monitor")
        self.participantes = {}
        self._log = []
        self.configuracao = json.load(open(arqEstrategia))

    @property
    def log(self):
        return self._log[:]

    def pronto(self):
        while True:
            msgTestador = self.socketReceive.recv().split()
            if msgTestador[0] == "###":
                for pid in self.participantes.keys():
                    self.socketsParticipantes[pid].send("###")
                break
            elif msgTestador[0] == "@@@":
                self.simulationLoop(msgTestador)
            else:
                print "Monitor: Mensagem '", msgTestador, "' desconhecida"

    def simulationLoop(self, msgTestador):
        resolucao, ncargas = None, None
        if len(msgTestador) > 1:
            resolucao = int(msgTestador[1])
            ncargas = int(msgTestador[2])
            nsujeiras = int(msgTestador[3])
        self._log = []
        for pid in self.participantes.keys():
            self.socketsParticipantes[pid].send("@@@")
        while True:
            mmsg = self.socketReceive.recv()
            msg = mmsg.split()
            de, para, texto = int(msg[0]), int(msg[1]), msg[2:]  # NOTE: o último elemento NÃO é uma string
            self._log.append((de, para, texto))
            if para == -1:
                self.avaliar(1, resolucao, ncargas, nsujeiras)
                break
            self.socketsParticipantes[para].send(mmsg)

    def avaliar(self, agid, resolucao=None, ncargas=None, nsujeiras=None):
        nmovimentos = 0
        nrecolhidos = 0
        consumo = 0
        consumoMax = 0
        for de, para, texto in self._log:
            if para == agid:
                if texto[0] == "moveu":
                    nmovimentos += 1
                elif texto[0] == "limpou":
                    nrecolhidos += 1
                elif texto[0] == "recarregou":
                    consumo -= 10
            elif de == agid and texto[0] != "perceber":
                consumo += 1
                if consumo > consumoMax:
                    consumoMax = consumo

        fatorx = nrecolhidos / float(nsujeiras)

        tamanho = 0.0
        if resolucao == None:
            tamanho = float(self.configuracao["resolucao"] ** 2)
        else:
            tamanho = float(resolucao ** 2)
        consumoMin = 0.0
        if ncargas == None:
            consumoMin = (tamanho + nrecolhidos) / float(self.configuracao["carga"])
        else:
            consumoMin = (tamanho + nrecolhidos) / float(ncargas)

        if nmovimentos < tamanho:
            obj1 = 50.0 * fatorx
        else:
            obj1 = 100.0 / 2 ** (log(nmovimentos / tamanho, 3.5))
        if consumoMax < consumoMin:  # caso em que o agente parou no caminho
            obj2 = 0.0
        else:
            obj2 = fatorx * (100.0 / 2 ** (log(consumoMax / consumoMin, 4.5)))

        # print (obj1, obj2)
        self.socketTestador.send("%s %s" % (obj1, obj2))

    def run(self):
        contexto = zmq.Context()
        self.socketReceive = contexto.socket(zmq.PULL)
        self.socketReceive.bind(self.endereco)
        self.socketTestador = contexto.socket(zmq.PUSH)
        self.socketTestador.connect(self.enderecos.endereco("testador"))
        self.socketsParticipantes = {}
        for chave in self.participantes.keys():
            self.socketsParticipantes[chave] = contexto.socket(zmq.PUSH)
            self.socketsParticipantes[chave].connect(self.participantes[chave])

        self.pronto()
        time.sleep(1)  # este tempo é necessário para garantir o envio das mensagens para os participantes
        print "monitor finalizando..."

    def adicionarParticipante(self, pid, endereco):
        """
        participante -> tupla contendo referência ao agente e o seu apelido.
        """
        self.participantes[pid] = endereco

    def removerParticipante(self, pid):
        del self.participantes[pid]
Example #6
0
class Nsga2(Process):
    def __init__(self, configEst, configEnd, configCom):
        super(Nsga2, self).__init__()
        self.crossoverProb = 0.0
        self.mutacaoProb = 0.0
        self.componentes = Componentes(configCom)
        self.configuracoes = json.load(open(configEst))
        self.enderecos = Enderecos(configEnd)
        self.enderecos.participantes()
        #TODO: guardar o log
        self.npop = 0
        self.maxite = 0

    def run(self):
        raise NotImplementedError

    def fastNondominatedSort(self, populacao):
        """
        returns a list of fronts.
        """
        frontes = []
        fronteAtual = []
        for individuo in populacao:
            individuo.ndominam = 0
            individuo.dominadas = []
        for indiceI, individuo in enumerate(populacao):
            for indiceO, outroIndividuo in enumerate(populacao):
                if indiceI == indiceO:
                    continue
                comp = individuo.comparar(outroIndividuo)
                if comp == COMP_DOMINA:
                    individuo.dominadas.append(indiceO)
                elif comp == COMP_DOMINADA:
                    individuo.ndominam += 1
            if individuo.ndominam == 0:
                individuo.fitness = 1
                fronteAtual.append(individuo)

        frontes.append(fronteAtual)
        i = 0
        while len(frontes[i]) > 0:
            fronteAnterior = frontes[i]
            fronteNovo = []
            for individuo in fronteAnterior:
                for indice in individuo.dominadas:
                    q = populacao[indice] #tentativa de reduzir o acesso a índices de listas
                    q.ndominam -= 1
                    if q.ndominam == 0:
                        q.fitness = i + 2
                        fronteNovo.append(q)
            i += 1
            frontes.append(fronteNovo)
        return frontes  #NOTE: retorna um fronte vazio também?

    def configurar(self, **args):
        for k, valor in args.iteritems():
            if k == 'npopulacao':
                self.npop = valor
            elif k == 'ngeracoes':
                self.maxite = valor
            elif k == 'crossover':
                self.crossoverProb = valor
            elif k == 'mutacao':
                self.mutacao = valor

    #TODO: modificar nomenclatura desse método.
    def crowdingDistanceAssignment(self, pontos):
        for i in pontos:
            i.distancia = 0.0
        nobjetivos = len(pontos[0].objetivos)
        l = len(pontos)
        for m in range(nobjetivos):
            pontos = sorted(pontos, key=lambda ponto: ponto.objetivos[m])
            pontos[0].distancia, pontos[-1].distancia = INFINITO, INFINITO
            i = 1
            while (i < l-1):
                pontos[i].distancia += (pontos[i+1].objetivos[m] - pontos[i-1].objetivos[m])
                i += 1

    def gerarPopulacaoInicial(self):
        raise NotImplementedError

    def gerarPopulacao(self):
        raise NotImplementedError

    def gravarPopulacao(self, pid, populacao):
        log = open('populacao.txt','a')
        log.write(str(pid) + '\n')
        for individuo in populacao:
            for objetivo in individuo.objetivos:
                log.write(str(objetivo)+' ')
            log.write('\n')
        log.close()

    #TODO: mudar o nome para unir populações?
    def gerarConjunto(self, pop1, pop2):
        extra = filter(lambda p:p.cloned==False, pop2)
        for e in extra:
            for p in pop1:
                if e.cromossomo == p.cromossomo:
                    break
            else:
                pop1.append(e)
        return pop1


    def mainLoop(self):
        print "mainloop()"
        msg = self.socketReceive.recv() #aguarda mensagem de inicialização
        p = self.gerarPopulacaoInicial()
        self.gravarPopulacao(0, p)
        q = []
        i = 0
        while i < self.maxite:
            print >> sys.stderr, i,
            #log = open(self.mainlog,"a")
            #log.write("\nGeração %s\n" % (i+1))
            #log.close()
            #print "Geração %s" % (i+1),
            #r = list(set(p + q))
            r = self.gerarConjunto(p, q)
            frontes = self.fastNondominatedSort(r)
            p = []
            for fronte in frontes:
                self.crowdingDistanceAssignment(fronte)
                p.extend(fronte)
                if len(p) >= self.npop:
                    break
            p = sorted(p, key = lambda el: el.distancia, reverse = True)
            p = p[:self.npop]
            q = self.gerarPopulacao(p, self.npop)
            if i % 50 == 0:
                Nsga2Aspirador.draw(p, 'pop_%s.txt' % i)
            i += 1
            self.gravarPopulacao(i, p)
        return p
Example #7
0
class TestadorAspirador(Process):
    def __init__(self, configSim, configExe, configEnd, configComp):
        super(TestadorAspirador, self).__init__()
        self.configs = {}
        self.configs['sim'] = json.load(open(configSim))
        self.configs['exe'] = json.load(open(configExe))
        self.enderecos = Enderecos(configEnd)
        self.componentes = Componentes(configComp)

    def run (self):
        print '*'*20, 'Zephyrus', '*'*20
        print 'conectando...'
        modo = self.configs['sim']['mode']
        contexto = zmq.Context()
        self.socketReceive = contexto.socket(zmq.PULL)
        self.socketReceive.bind(self.enderecos.endereco('tester'))
        if modo == 'cent': #um testador
            self.inicializarParticipantesCentralizado()
            self.socketMonitor = contexto.socket(zmq.PUSH)
            self.socketMonitor.connect(self.enderecos.endereco('monitor'))
            self.socketConfiguracoes = contexto.socket(zmq.PUB)
            self.socketConfiguracoes.bind(self.enderecos.endereco('testador_par'))
        elif modo == 'dist':
            self.incializarParticipantesDistribuido()
            #...
        else:
            raise CoreException("Modo de funcionamento desconhecido: %s" % modo)
        self.socketEstrategia = contexto.socket(zmq.PUSH)
        self.socketEstrategia.connect(self.enderecos.endereco('estrategia'))
        self.loopPrincipal(modo)
        print 'finalizando os testes...'
        time.sleep(2)
        print >> sys.stderr, 'FIM'

    def inicializarParticipantesCentralizado(self):
        if not '<MANUAL>' in self.configs['exe']['monitor']: #monitor
            subp.Popen(self.configs['exe']['monitor'].split())
        else:
            endereco = self.enderecos.endereco('monitor')
            #endereco = self.configs['end']['monitor'].split(',')[-1]
            print 'execute o monitor manualmente, esperado em: ', endereco
            raw_input('\npressione enter para continuar')

        pprint.pprint(self.configs)
        if not '<MANUAL>' in self.configs['exe']['environment']: #ambiente
            subp.Popen(self.configs['exe']['environment'].split())
        else:
            endereco = self.enderecos.endereco('environment')
            #endereco = self.configs['end']['ambiente'].split(',')[-1]
            print 'execute o ambiente manualmente, esperado em: ', endereco
            raw_input('\npressione enter para continuar')
        for i, agente in enumerate(self.configs['exe']['agentes']): #agentes
            if not '<MANUAL>' in agente:
                subp.Popen(agente.split())
            else:
                endereco = self.enderecos.endereco('agente')
                #endereco = self.configs['end']['agentes'][i].split(',')[-1]
                print 'execute o agente manualmente, esperado em: ', endereco
                raw_input('\npressione enter para continuar')
        if not '<MANUAL>' in self.configs['exe']['estrategia']: #estratégia
            subp.Popen(self.configs['exe']['estrategia'].split())
        else:
            endereco = self.enderecos.endereco('estrategia')
            #endereco = self.configs['end']['estrategia'].split(',')[-1]
            print 'execute o estratégia manualmente, esperado em: ', endereco
            raw_input('\npressione enter para continuar')

    def incializarParticipantesDistribuido(self):
        pass    #TODO!


    def loopPrincipal(self, modo):
        self.socketEstrategia.send("@@@")
        self.cenarioPadrao = map(int, self.configs['sim']['cenarioPadrao'].split())
        resolucao = self.configs['sim']['resolucao']
        ncargas = self.configs['sim']['carga']
        sujeiras = self.configs['sim']['sujeira']
        nomeAmbiente = self.enderecos.get('ambiente')[0]
        while True:
            msg = self.socketReceive.recv()
            if "###" in msg:
                self.socketConfiguracoes.send('%s ,' % nomeAmbiente)
                self.socketMonitor.send("###")
                break
            iagente = 1
            linha = 0
            coluna = 0
            ambiente = map(self.componentes.juntar, map(int, msg.split()), self.cenarioPadrao)
            for i in xrange(len(ambiente)):
                agentes = filter(lambda k:self.componentes.checar(k, ambiente[i]), ['AG01', 'AG02', 'AG03', 'AG04'])
                if len(agentes) > 0:
                    linha, coluna = i/resolucao, i%resolucao
            ambiente = ' '.join(map(str,ambiente))
            resultados = []
            for i in range(self.configs['sim']['repeat']):
                self.socketConfiguracoes.send('%s %s,%s,%s,%s,%s' % (nomeAmbiente, ambiente, resolucao,iagente,linha,coluna))
                self.socketMonitor.send("@@@ %s %s %s" % (resolucao, ncargas, sujeiras))
                #print ambiente
                resultados.append(map(float, self.socketReceive.recv().split()))
            obj1, obj2 = zip(*resultados) #unzip!!!
            medias = "%s %s" % (sum(obj1)/len(resultados), sum(obj2)/len(resultados))
            #print 'medias', medias
            #medias = "%s %s" % (100 * random.random(), 100 * random.random())
            self.socketEstrategia.send(medias)
            #print self.enderecos.get('ambiente')[0]

    #        print 'recebi', msg
    #        for resultado in resultados:
    #            log.write(str(resultado))
    #        medias = sum(map(lambda k:k[0], resultados))/len(resultados), sum(map(lambda k:k[1], resultados))/len(resultados)
    #        self.socketEstrategia.send("%s %s" % (medias[0], medias[1]))
    #        return medias


    #TODO: expandir para uma versão com roteiro
    def iniciarSimulacao(self, modo):
        teste = self.socketReceive()

        tinicio = time()
        print 'Teste iniciado às: ', strftime("%H:%M:%S", localtime())
        #self.

        self.configuracao = json.loads(open('configuracao.js').read())
        self.cenarioPadrao = map(int, self._configuracao["cenarioPadrao"].split())
        self.estrategia = self.estrategiaNsga2()
        populacao = self.estrategia.mainLoop()
        self.analise(populacao)

        tfim  = time()
        print 'Teste finalizado às: ', strftime("%H:%M:%S", localtime())
        print "tempo consumido: ",  str(tfim - tinicio) + 's'


    def avaliarMultiplos(self, cenario):
        #print '@'
        ambiente = map(self.componentes.juntar, cenario, self.cenarioPadrao)
        #dimensao = self._configuracao["resolucao"]
        resultados = []

        log = open(self._configuracao["mainlog"],'a')
        log.write('\n@\n')
        log.write(str(ambiente))
        log.write('\n')
        #for v in ambiente:
        #   print filter(lambda k:self.componentes.checar(k,v), self.componentes.items.keys())
        ambiente = reduce(lambda a,b: a + ' '+ b, map(str, ambiente))
        info = "%s %s %s," % (self._configuracao["resolucao"], self._configuracao["ncargas"], self._configuracao["nsujeiras"])
        msg = info + ambiente
        for socket in self.socketAuxiliares:
            socket.send(msg)
            #socket.send(str(ambiente))

        for i in xrange(self._configuracao["nauxiliares"]):
            msg = self.socketReceive.recv()
            resultados.append(map(float,msg.split()))
            #print 'recebi', msg

        for resultado in resultados:
            log.write(str(resultado))
        log.write('\n')
        medias = sum(map(lambda k:k[0], resultados))/len(resultados), sum(map(lambda k:k[1], resultados))/len(resultados)
        log.write(str(medias))
        log.close()
        return medias


    def analise(self, populacao):
        cenarios = []
        for i in populacao:
            individuo = i.decodificar(self.componentes)
            cenarios.append(map(self.componentes.juntar, individuo, self.cenarioPadrao))
        with open(self._configuracao['popfinal'], 'w') as a:
            for cenario in cenarios:
                for elemento in cenario:
                    a.write(str(elemento) + ' ')
                a.write('\n')
Example #8
0
class AspiradorIII(Process):
    def __init__(self, agId, configEnd, configCom):
        super(AspiradorIII, self).__init__()

        self.mid = agId
        self.enderecos = Enderecos(configEnd)
        self.endereco = self.enderecos.endereco('agente')
        self.enderecoMonitor = self.enderecos.endereco('monitor')
        self.componentes  = Componentes(configCom)

        self.socketReceive = None
        self.socketSend = None

        self.enviar = True #True se agente deve enviar mensagem, False caso esteja esperando resposta
        self.agindo = True #False para enviar ação de perceber
        self.ENERGIAMAX = 80.0
        self.limiteRecarga = 0.25

        self.RESERVATORIOMAX = 4
        self.PLANO_EXPLORAR = 0
        self.PLANO_RECARREGAR = 1
        self.PLANO_DEPOSITAR = 2
        self.PLANO_SUJEIRA = 3
        self.tiposPlano = (self.PLANO_EXPLORAR, self.PLANO_RECARREGAR, self.PLANO_DEPOSITAR, self.PLANO_SUJEIRA)

        self.reiniciarMemoria()


    def perceber(self, percebido):
        #define o momento em que o agente enxerga o ambiente captando informações sobre
        #existência de obstáculos e de sujeira.

        itens = ['PAREDEN', 'PAREDEL', 'PAREDES', 'PAREDEO', 'LIXO', 'LIXEIRA','RECARGA']
        #posições: N, L, S ,O e 'sujo' (True indica presença de parede/sujeira).
        st = map(lambda item:self.componentes.checar(item, percebido),itens)
        return self.agir(st)

    def reiniciarMemoria(self):
        self.visitados = {}
        self.nvisitados = []
        self.lixeiras = [] #posição de pontos de depósito de lixo
        self.recargas = [] #posição de pontos de recarga
        self.sujeiras = set() #posição de sujeiras encontradas

        self.x, self.y = 0, 0
        self.percebido = None
        self.px, self.py = 0, 0
        self.DELTA_POS = ((-1, 0), (0, 1), (1, 0), (0, -1)) #auxiliar em várias operações
        self.energia = self.ENERGIAMAX

    #           self.limiteRecarga = 0.4
        self.reservatorio = 0

        self.plano = None #qual tipo de plano atualmente sendo executado
        self.movimentar = [] #sequência de movimentos a serem realizados
        self.nrecargas = 0 #usada durante a execução do plano de recarga
        self.recuperarMovimento = 0 #armazena um movimento tentado para recuperá-lo em caso de falha.

    def run(self):
        print 'Agente rodando!!!'
        contexto = zmq.Context()
        self.socketReceive = contexto.socket(zmq.PULL)
        self.socketReceive.bind(self.endereco)
        self.socketSend = contexto.socket(zmq.PUSH)
        self.socketSend.connect(self.enderecoMonitor)
        self.ready()

    def ready(self):
        print "Agent %s is ready." % (self.mid)
        while True:
            msg = self.socketReceive.recv()
            if msg == "@@@":
                self.reiniciarMemoria()
                self.enviar = True
                self.agindo = False
                while True:
                    if self.enviar:
                        if self.agindo == False:
                            self.socketSend.send("%s %s perceber" % (self.mid, 0))
                            self.enviar = False
                        else:
                            acao = self.perceber(self.percebido)
                            msg = "%s %s " % (self.mid, 0)
                            #TODO: tratar o caso PARAR
                            self.socketSend.send(msg + acao)
                            self.enviar = False
                            pass
                    else:
                        if self.agindo == False:
                            msg = self.socketReceive.recv()
                            self.enviar = True
                            self.agindo = True
                            self.percebido = int(msg.split()[2])
                        else:
                            msg = self.socketReceive.recv() #apenas um feddback (ack)
                            retorno = msg.split()[-1]
                            if retorno == 'moveu':
                                self.mover()
                            elif retorno == 'limpou':
                                self.limpar()
                            elif retorno == 'recarregou':
                                self.carregar()
                            elif retorno == 'depositou':
                                self.depositar()
                            elif retorno == 'colidiu':
                                self.colidir()
                            elif retorno == 'parou':
                                break
                            elif retorno == 'nop':
                                self.nop()
                            else:
                                pass
                            self.enviar = True
                            self.agindo = False
            elif msg == "###":
                print "Agente %s recebeu mensagem de finalização de atividades." % (self.mid)
                break
            else:
                print "Agente %s recebeu mensagem inválida." % (self.mid)


    def agir(self, st):
        self.memorizarAmbiente(st)
        if self.energia <= 0:
            return 'parar'
        if self.plano != None:
            if self.plano == self.PLANO_EXPLORAR:
                if len(self.movimentar) > 0:
                    self.recuperarMovimento = self.movimentar.pop(0)
                    self.px, self.py = self.DELTA_POS[self.recuperarMovimento]
                    if len(self.movimentar) == 0:
                        self.plano = None
                    return "mover %s" % self.recuperarMovimento
                else:
                    print 'erro na função agir' #TODO: transformar isso em execeção
            elif self.plano == self.PLANO_DEPOSITAR:
                if len(self.movimentar) > 0:
                    self.recuperarMovimento = self.movimentar.pop(0)
                    self.px, self.py = self.DELTA_POS[self.recuperarMovimento]
                    self.energia -= 1
                    return "mover %s" % self.recuperarMovimento
                else:
                    self.plano = None
                    return "depositar"
            elif self.plano == self.PLANO_RECARREGAR:
                if len(self.movimentar) > 0:
                    self.recuperarMovimento = self.movimentar.pop(0)
                    self.px, self.py = self.DELTA_POS[self.recuperarMovimento]
                    self.energia -= 1
                    return "mover %s" % self.recuperarMovimento
                else:
                    self.nrecargas -= 1
                    if self.nrecargas == 0:
                        self.plano = None
                    return "recarregar"
            elif self.plano == self.PLANO_SUJEIRA:
                if len(self.movimentar) > 0:
                    self.recuperarMovimento = self.movimentar.pop(0)
                    self.px, self.py = self.DELTA_POS[self.recuperarMovimento]
                    self.energia -= 1
                    return "mover %s" % self.recuperarMovimento
                else:
                    self.plano = None
                    return "limpar"
            else:
                print "plano desconhecido" #TODO: transformar em exceção

        elif (self.energia / self.ENERGIAMAX) < self.limiteRecarga:
            return self.tracarPlanoRecarga(st)
        elif self.reservatorio == self.RESERVATORIOMAX:
            return self.tracarPlanoDeposito(st)
        elif st[4] == True:
            self.energia -= 3 #consome energia independente de limpar ou não de verdade
            return  'limpar'
        else:
            return self.escolherDirecao(st[:4])

    def memorizarAmbiente (self,st):
        if (self.x, self.y) in self.nvisitados:
            self.nvisitados.remove((self.x,self.y))
        self.visitados[(self.x, self.y)] = st[0:4]
        visitados = self.visitados.keys() #NOTE: tentativa de melhorar o desempenho, gerando a lista apenas uma vez
        if st[0] == False:
            if ((self.x-1, self.y) not in visitados) and ((self.x-1, self.y) not in self.nvisitados):
                self.nvisitados.append((self.x-1, self.y))
        if st[1] == False:
            if ((self.x, self.y+1) not in visitados) and ((self.x, self.y+1) not in self.nvisitados):
                self.nvisitados.append((self.x, self.y + 1))
        if st[2] == False:
            if ((self.x+1, self.y) not in visitados) and ((self.x+1, self.y) not in self.nvisitados):
                self.nvisitados.append((self.x + 1, self.y))
        if st[3] == False:
            if ((self.x, self.y-1) not in visitados) and ((self.x, self.y-1) not in self.nvisitados):
                self.nvisitados.append((self.x, self.y - 1))
        if st[4] == True:
            self.sujeiras.add((self.x, self.y))
        if (st[5] == True) and  not ((self.x, self.y) in self.lixeiras):
            self.lixeiras.append((self.x, self.y))
        if (st[6] == True) and  not ((self.x, self.y) in self.recargas):
            self.recargas.append((self.x, self.y))

    #TODO: a checagem de colisão no ambiente NÃO funciona para colisão com paredes
    def escolherDirecao(self, paredes):
        direcoes = []
        for i, parede in enumerate(paredes):
            if not parede:
                direcoes.append(i)

        if len(direcoes) == 0:
            return 'parar'

        if len(self.nvisitados) == 0 and len(self.sujeiras) == 0:
            return 'parar'

        nvisitados = []
        visitados = self.visitados.keys()
        for direcao in direcoes:
            if direcao == 0:
                if ((self.x-1, self.y) not in visitados):   #TODO: buscas a visitados podem ser substituídas por buscas a nvisitados?
                    nvisitados.append((0, (-1, 0)))
            elif direcao == 1:
                if ((self.x, self.y+1) not in visitados):
                    nvisitados.append((1, (0, 1)))
            elif direcao == 2:
                if ((self.x+1, self.y) not in visitados):
                    nvisitados.append((2, (1, 0)))
            else:
                if ((self.x, self.y-1) not in visitados):
                    nvisitados.append((3, (0, -1)))
        if len(nvisitados) == 0:
            if len(self.nvisitados) == 0:
                return self.tracarPlanoSujeira()
            else:
                return self.tracarPlanoExploracao()
        choiced = choice(nvisitados)
        self.px, self.py = choiced[1]
        self.energia -= 1
        self.recuperarMovimento = choiced[0]
        return 'mover %s' % self.recuperarMovimento


    def tracarPlanoRecarga(self,st):
        if len(self.recargas) == 0:
            return self.escolherDirecao(st[:4])
        self.plano = self.PLANO_RECARREGAR
        self.nrecargas = int((self.ENERGIAMAX - self.energia)/10)

        if st[6] == True: #o agente já está em um ponto de recarga
            self.movimentar = []
            self.nrecargas -= 1
            return 'recarregar'

        minx, maxx, miny, maxy = self.calcularDimensoes()
        sizex = maxx - minx + 1
        sizey = maxy - miny + 1
        matriz = [[-1000 for i in range(sizey)] for i in range(sizex)]

        for x, y in self.visitados.keys():
            matriz[x-minx][y-miny] = 1000

        for x,y in self.recargas:
            matriz[x - minx][y - miny] = -1
        caminho = self.caminhoMaisCurto(matriz, (self.x, self.y),minx, maxx,miny, maxy)
        self.movimentar = self.caminhoParaMovimentos(caminho)
        self.recuperarMovimento = self.movimentar.pop(0)
        self.energia -= 1
        self.px, self.py = self.DELTA_POS[self.recuperarMovimento]
        return "mover %s" % self.recuperarMovimento

    def tracarPlanoDeposito(self,st):
        if len(self.lixeiras) == 0:
            return self.escolherDirecao(st[:4])
        self.plano = self.PLANO_DEPOSITAR

        if st[5] == True: #o agente já está em um ponto de recarga
            self.movimentar = []
            self.plano = None
            return 'depositar'

        minx, maxx, miny, maxy = self.calcularDimensoes()
        sizex = maxx - minx + 1
        sizey = maxy - miny + 1
        matriz = [[-1000 for i in range(sizey)] for i in range(sizex)]

        for x, y in self.visitados.keys():
            matriz[x-minx][y-miny] = 1000

        for x,y in self.lixeiras:
            matriz[x - minx][y - miny] = -1
        caminho = self.caminhoMaisCurto(matriz, (self.x, self.y),minx, maxx,miny, maxy)
        self.movimentar = self.caminhoParaMovimentos(caminho)
        self.recuperarMovimento = self.movimentar.pop(0)
        self.energia -= 1
        self.px, self.py = self.DELTA_POS[self.recuperarMovimento]
        return "mover %s" % self.recuperarMovimento

    def tracarPlanoSujeira(self):
        self.plano = self.PLANO_SUJEIRA

        minx, maxx, miny, maxy = self.calcularDimensoes()
        sizex = maxx - minx + 1
        sizey = maxy - miny + 1
        matriz = [[-1000 for i in range(sizey)] for i in range(sizex)]

        for x, y in self.visitados.keys():
            matriz[x-minx][y-miny] = 1000

        for x,y in self.sujeiras:
            matriz[x - minx][y - miny] = -1
        caminho = self.caminhoMaisCurto(matriz, (self.x, self.y),minx, maxx,miny, maxy)
        self.movimentar = self.caminhoParaMovimentos(caminho)
        self.recuperarMovimento = self.movimentar.pop(0)
        self.energia -= 1
        self.px, self.py = self.DELTA_POS[self.recuperarMovimento]
        return "mover %s" % self.recuperarMovimento

    def tracarPlanoExploracao(self):
        self.plano = self.PLANO_EXPLORAR
        minx, maxx, miny, maxy = self.calcularDimensoes()
        sizex = maxx - minx + 1
        sizey = maxy - miny + 1
        matriz = [[-1 for i in range(sizey)] for i in range(sizex)]

        for x, y in self.visitados.keys():
            matriz[x-minx][y-miny] = 1000
        caminho = self.caminhoMaisCurto(matriz, (self.x, self.y),minx, maxx,miny, maxy)
        self.movimentar = self.caminhoParaMovimentos(caminho)
        self.energia -= 1
        self.recuperarMovimento = self.movimentar.pop(0)
        self.px, self.py = self.DELTA_POS[self.recuperarMovimento]
        return "mover %s" % self.recuperarMovimento

    def calcularDimensoes(self):
        visitados = self.visitados.keys()
        if len(self.nvisitados) != 0:
            maxx = max(max(visitados)[0], max(self.nvisitados)[0])
            minx = min(min(visitados)[0], min(self.nvisitados)[0])
            maxy = max(max(visitados, key=lambda k:k[1])[1],max(self.nvisitados, key=lambda k:k[1])[1])
            miny = min(min(visitados, key=lambda k:k[1])[1],min(self.nvisitados, key=lambda k:k[1])[1])
        else:
            maxx = max(visitados)[0]
            minx = min(visitados)[0]
            maxy = max(visitados, key=lambda k:k[1])[1]
            miny = min(visitados, key=lambda k:k[1])[1]


        return minx, maxx, miny, maxy

    def caminhoMaisCurto(self, matriz, atual, minx, maxx, miny, maxy):
        fila = deque()
        caminho = []
        fila.append(atual)
        px, py = atual
        matriz[px-minx][py-miny] =  0
        peso = 0
        while len(fila) > 0:
            px, py = fila.popleft()
            if matriz[px - minx][py - miny] ==  -1:
                return (px,py) #TODO: se entrar aqui (é possível?) vai dar bug!!!!!!
            peso = matriz[px - minx][py - miny]
            direcoes = self.estadosParaDirecoes((px, py), self.visitados[(px, py)])
            for direcao in direcoes:
                opx, opy = direcao
                if matriz[opx - minx][opy - miny] > peso + 1:   #encontrou um caminho melhor (ou o primeiro caminho) até aquela posição.
                    matriz[opx - minx][opy - miny] = peso + 1
                    fila.append(direcao)
                elif matriz[opx - minx][opy - miny] == -1: #encontrou uma posição que ainda não foi visitada.
                    caminho.append((opx, opy))
                    while peso >= 0:
                        #Sul
                        if ((opx - minx + 1 <= maxx - minx) and (matriz[opx - minx + 1][opy - miny] == peso)):
                            caminho.append((opx + 1, opy))
                            opx += 1
                            peso -= 1
                            continue
                        #Oeste
                        if ((opy - miny - 1 >= 0) and (matriz[opx - minx][opy - 1 - miny] == peso)):
                            caminho.append((opx, opy - 1))
                            opy -= 1
                            peso -= 1
                            continue
                        #Norte
                        if (opx - minx - 1 >= 0) and (matriz[opx - minx - 1][opy - miny] == peso):
                            caminho.append((opx - 1, opy))
                            peso -= 1
                            opx -= 1
                            continue
                        if (opy - miny + 1 <= maxy - miny) and (matriz[opx - minx][opy + 1 - miny] == peso):
                            caminho.append((opx, opy + 1))
                            peso -= 1
                            opy += 1
                            continue
                    return caminho[::-1]
        print 'nao encontrou caminho!'
        print self.info()

    #Método auxiliar que realiza a conversão de estados(paredes) para direções
    def estadosParaDirecoes(self, pos, st):
        ret = []
        x,y = pos
        if st[0] == False:
            ret.append((x-1,y))
        if st[1] == False:
            ret.append((x,y+1))
        if st[2] == False:
            ret.append((x+1,y))
        if st[3] == False:
            ret.append((x,y-1))
        return ret

    def caminhoParaMovimentos (self, caminho):
        movimentos = []
        orix, oriy = caminho[0]
        for i in range(1,len(caminho)):
            desx, desy = caminho[i]
            if orix != desx:
                if orix > desx:
                    movimentos.append(0)
                else:
                    movimentos.append(2)
            else:
                if oriy > desy:
                    movimentos.append(3)
                else:
                    movimentos.append(1)
            orix, oriy = desx, desy
        return movimentos


    def limpar(self):
        #O agente executa a ação de limpar em sua posição atual.
        self.sujeiras.discard((self.x, self.y))
        self.reservatorio += 1

    def carregar(self):
        self.energia += 10

    def depositar(self):
        self.energia -= 1
        self.reservatorio = 0

    def parar(self):
        #O agente permanece parado e apenas informa esse fato ao observador.
        self.info()
        while True:
            pass

    def mover(self):
        #movimento realizado com sucesso
        self.x += self.px
        self.y += self.py

    def colidir(self):
        print 'colidi'
        self.energia -= 1
        if self.plano != None:
            self.movimentar.insert(0,self.recuperarMovimento)

    def nop(self):
        pass

    def info(self):
        print '*'*10
        print 'posicao', (self.x, self.y)
        print self.energia, self.reservatorio, self.plano
        print 'visitados', self.visitados.keys()
        print 'nvisitados', self.nvisitados
        print 'lixeiras', self.lixeiras
        print 'recargas', self.recargas
        print 'sujeiras', self.sujeiras
        print '*'*10